import type { IncomingMessage, ServerResponse } from 'node:http'; import { HarborError } from '../../../shared/errors.js'; import { sendJson } from '../response.js'; interface DeviceInventoryPort { snapshot(): unknown; refresh(): Promise; update(deviceId: string, patch: Record, expectedRevision: unknown): unknown; createTag(name: unknown, expectedRevision: unknown): unknown; renameTag(tagId: string, name: unknown, expectedRevision: unknown): unknown; deleteTag(tagId: string, expectedRevision: unknown): unknown; resetTraffic(expectedRevision: unknown): Promise; setPolicy(deviceId: string, mode: unknown, expectedRevision: unknown): Promise; } interface DeviceInventoryRouteDependencies { deviceInventory: DeviceInventoryPort | null; readBody(req: IncomingMessage): Promise>; } const DEVICE_PATH = /^\/api\/devices\/(dev_[a-f0-9]{16})$/; const DEVICE_POLICY_PATH = /^\/api\/devices\/(dev_[a-f0-9]{16})\/policy$/; const DEVICE_TAG_PATH = /^\/api\/device-tags\/(tag_[a-f0-9]{16})$/; export function createDeviceInventoryRoute(dependencies: DeviceInventoryRouteDependencies) { return { async handle(req: IncomingMessage, res: ServerResponse) { const pathname = new URL(req.url || '/', 'http://localhost').pathname; if (pathname === '/api/devices') { if (!dependencies.deviceInventory || req.method !== 'GET') { throw new HarborError('ENDPOINT_NOT_FOUND'); } sendJson(res, 200, dependencies.deviceInventory.snapshot()); return true; } if (pathname === '/api/devices/refresh') { if (!dependencies.deviceInventory || req.method !== 'POST') { throw new HarborError('ENDPOINT_NOT_FOUND'); } sendJson(res, 200, await dependencies.deviceInventory.refresh()); return true; } if (pathname === '/api/devices/traffic') { if (!dependencies.deviceInventory || req.method !== 'DELETE') { throw new HarborError('ENDPOINT_NOT_FOUND'); } const body = await dependencies.readBody(req); sendJson(res, 200, await dependencies.deviceInventory.resetTraffic(body.expectedRevision)); return true; } if (pathname === '/api/device-tags') { if (!dependencies.deviceInventory || req.method !== 'POST') { throw new HarborError('ENDPOINT_NOT_FOUND'); } const body = await dependencies.readBody(req); sendJson( res, 200, dependencies.deviceInventory.createTag(body.name, body.expectedRevision), ); return true; } const tagMatch = pathname.match(DEVICE_TAG_PATH); if (tagMatch) { if (!dependencies.deviceInventory || !['PUT', 'DELETE'].includes(req.method || '')) { throw new HarborError('ENDPOINT_NOT_FOUND'); } const body = await dependencies.readBody(req); sendJson( res, 200, req.method === 'PUT' ? dependencies.deviceInventory.renameTag(tagMatch[1], body.name, body.expectedRevision) : dependencies.deviceInventory.deleteTag(tagMatch[1], body.expectedRevision), ); return true; } const deviceMatch = pathname.match(DEVICE_PATH); if (deviceMatch) { if (!dependencies.deviceInventory || req.method !== 'PUT') { throw new HarborError('ENDPOINT_NOT_FOUND'); } const { expectedRevision, ...patch } = await dependencies.readBody(req); sendJson( res, 200, dependencies.deviceInventory.update(deviceMatch[1], patch, expectedRevision), ); return true; } const policyMatch = pathname.match(DEVICE_POLICY_PATH); if (policyMatch) { if (!dependencies.deviceInventory || req.method !== 'PUT') { throw new HarborError('ENDPOINT_NOT_FOUND'); } const body = await dependencies.readBody(req); sendJson( res, 200, await dependencies.deviceInventory.setPolicy( policyMatch[1], body.mode, body.expectedRevision, ), ); return true; } return false; }, }; }