// integrations/atlas/resolveStoreDevice.js // Strict AMP store resolution for /atlasdiag (separate from avstatus includes() matching). export function deviceStatus(d) { return String( d?.status || d?.effective_status || d?.state?.status || d?.state?.effective_status || '', ).toLowerCase().trim(); } export function isOffline(d) { const st = deviceStatus(d); return st === 'offline' || st === 'disconnected' || st === 'never_seen'; } /** * Resolve by UUID, exact name, or unique partial name match. * @throws {{ code: 'AMBIGUOUS' }} when multiple partial matches */ export function resolveDevice(devices, idOrName) { if (!idOrName) return null; const q = String(idOrName).trim(); const byId = devices.find(d => d.id === q); if (byId) return byId; const lower = q.toLowerCase(); const exact = devices.find(d => String(d.name || '').toLowerCase() === lower); if (exact) return exact; const partial = devices.filter(d => String(d.name || '').toLowerCase().includes(lower)); if (partial.length === 1) return partial[0]; if (partial.length > 1) { const err = new Error( `Ambiguous device "${q}": ${partial.slice(0, 5).map(d => d.name).join(', ')}`, ); err.code = 'AMBIGUOUS'; err.matches = partial; throw err; } return null; } /** * Pad a store number to 6 digits (2547 → 002547). */ export function padStoreNumber(storeNumber) { const digits = String(storeNumber).replace(/\D/g, ''); if (!digits) return null; return digits.padStart(6, '0').slice(-6); } /** * Match device names like US002547AMP / CA000969AMP for a store number. * * @returns {{ device: object|null, storePadded: string|null, matches: object[], error?: string, code?: string }} */ export function resolveStoreDevice(devices, storeOrName) { const q = String(storeOrName || '').trim(); if (!q) { return { device: null, storePadded: null, matches: [], error: 'Store number required', code: 'MISSING' }; } if (!/^\d{1,6}$/.test(q)) { try { const device = resolveDevice(devices, q); if (!device) { return { device: null, storePadded: null, matches: [], error: `No device found for "${q}"`, code: 'NOT_FOUND' }; } const m = String(device.name || '').match(/^[A-Z]{2}(\d{6})AMP$/i); return { device, storePadded: m ? m[1] : null, matches: [device] }; } catch (err) { if (err.code === 'AMBIGUOUS') { return { device: null, storePadded: null, matches: err.matches || [], error: err.message, code: 'AMBIGUOUS', }; } throw err; } } const padded = padStoreNumber(q); const re = new RegExp(`^[A-Z]{2}${padded}AMP$`, 'i'); const matches = (devices || []).filter(d => re.test(String(d.name || ''))); if (matches.length === 0) { return { device: null, storePadded: padded, matches: [], error: `No AZM found for store ${String(Number(padded))} (${padded})`, code: 'NOT_FOUND', }; } if (matches.length > 1) { return { device: null, storePadded: padded, matches, error: `Multiple AZMs for store ${String(Number(padded))}: ${matches.map(d => d.name).join(', ')}. Retry with a device name.`, code: 'AMBIGUOUS', }; } return { device: matches[0], storePadded: padded, matches }; }