const config = require('../config'); const { proxyRequest } = require('./websocket'); const { parseStoreNumber } = require('../utils/validate'); const logger = require('../utils/logger'); function getSiwAuthHeaders() { const { username, password } = config.siw; if (!username || !password) { throw new Error('SIW credentials are not configured (SIW_USERNAME / SIW_PASSWORD)'); } const authString = Buffer.from(`${username}:${password}`).toString('base64'); return { Authorization: `Basic ${authString}` }; } function buildSiwRequest(path) { if (!config.siw.baseUrl) { throw new Error('SIW_BASE_URL is not configured'); } return { method: 'GET', url: `${config.siw.baseUrl}${path}`, headers: getSiwAuthHeaders(), }; } /** * Perform a SIW request and gracefully degrade when the remote agent isn't * connected. Returns `fallback` (default: null) so downstream code can keep * rendering Meraki/MDM sections without crashing. * * Any other error is propagated so the integration layer can decide whether * to swallow or surface it. */ async function siwGet(path, { fallback = null, storeNumber } = {}) { try { const result = await proxyRequest(buildSiwRequest(path)); return result?.data ?? fallback; } catch (err) { if (err.code === 'AGENT_NOT_CONNECTED') { logger.warn('SIW request skipped — remote agent not connected', { path, storeNumber }); return fallback; } throw err; } } async function getStoreLocation(storeNumber) { const normalized = parseStoreNumber(storeNumber); if (!normalized) throw new Error('Invalid store number'); const data = await siwGet(`/StoreLocation/${normalized}`, { storeNumber: normalized }); if (!data) { logger.warn('SIW returned no location record', { storeNumber: normalized }); } return data; } /** * /StoreGeneral/{n} returns brand info, environment, POS type, status, * open/close dates, etc. Distinct from /StoreLocation which is the address. */ async function getStoreGeneral(storeNumber) { const normalized = parseStoreNumber(storeNumber); if (!normalized) throw new Error('Invalid store number'); const data = await siwGet(`/StoreGeneral/${normalized}`, { storeNumber: normalized }); if (!data) { logger.warn('SIW returned no general record', { storeNumber: normalized }); } return data; } async function getStoreRegisters(storeNumber) { const normalized = parseStoreNumber(storeNumber); if (!normalized) throw new Error('Invalid store number'); return siwGet(`/StoreRegister/${normalized}`, { fallback: [], storeNumber: normalized }); } async function getStorePrinters(storeNumber) { const normalized = parseStoreNumber(storeNumber); if (!normalized) throw new Error('Invalid store number'); return siwGet(`/StorePrinter/${normalized}`, { fallback: [], storeNumber: normalized }); } async function getStorePaymentTerminals(storeNumber) { const normalized = parseStoreNumber(storeNumber); if (!normalized) throw new Error('Invalid store number'); return siwGet(`/StorePayment/${normalized}`, { fallback: [], storeNumber: normalized }); } module.exports = { getStoreLocation, getStoreGeneral, getStoreRegisters, getStorePrinters, getStorePaymentTerminals, };