@aigne/afs-omada 1.11.0-beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +26 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
- package/dist/cache.cjs +59 -0
- package/dist/cache.d.cts +39 -0
- package/dist/cache.d.cts.map +1 -0
- package/dist/cache.d.mts +39 -0
- package/dist/cache.d.mts.map +1 -0
- package/dist/cache.mjs +59 -0
- package/dist/cache.mjs.map +1 -0
- package/dist/client.cjs +168 -0
- package/dist/client.d.cts +66 -0
- package/dist/client.d.cts.map +1 -0
- package/dist/client.d.mts +66 -0
- package/dist/client.d.mts.map +1 -0
- package/dist/client.mjs +169 -0
- package/dist/client.mjs.map +1 -0
- package/dist/index.cjs +11 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.mjs +6 -0
- package/dist/omada-afs.cjs +2076 -0
- package/dist/omada-afs.d.cts +443 -0
- package/dist/omada-afs.d.cts.map +1 -0
- package/dist/omada-afs.d.mts +443 -0
- package/dist/omada-afs.d.mts.map +1 -0
- package/dist/omada-afs.mjs +2077 -0
- package/dist/omada-afs.mjs.map +1 -0
- package/dist/types.cjs +59 -0
- package/dist/types.d.cts +43 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +43 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +58 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"omada-afs.mjs","names":[],"sources":["../src/omada-afs.ts"],"sourcesContent":["import type {\n AFSAccessMode,\n AFSEntry,\n AFSExecResult,\n AFSExplainResult,\n AFSListResult,\n AFSModuleClass,\n AFSModuleLoadParams,\n AFSSearchOptions,\n AFSStatResult,\n AFSWriteEntryPayload,\n AFSWriteResult,\n CapabilitiesManifest,\n ProviderManifest,\n ProviderTreeSchema,\n} from \"@aigne/afs\";\nimport { AFSNotFoundError, type SecurityProfile } from \"@aigne/afs\";\nimport type { RouteContext } from \"@aigne/afs/provider\";\nimport {\n Actions,\n AFSBaseProvider,\n Explain,\n List,\n Meta,\n Read,\n Search,\n Stat,\n Write,\n} from \"@aigne/afs/provider\";\nimport { joinURL } from \"ufo\";\nimport { z } from \"zod\";\nimport { OmadaApiClient } from \"./client.js\";\nimport {\n type AFSOmadaOptionsInput,\n afsOmadaOptionsSchema,\n mapDeviceStatus,\n normalizeMac,\n} from \"./types.js\";\n\n// ============================================================================\n// Input validation helpers\n// ============================================================================\n\n/** Validate an ID parameter (siteId, ssidId, networkId) is safe for URL construction. */\nfunction validateIdParam(value: string, name: string): void {\n if (!/^[\\w-]+$/.test(value)) {\n throw new AFSNotFoundError(`Invalid ${name}: ${value}`);\n }\n}\n\n/** Parse write payload content, normalizing JSON parse errors. */\nfunction parseWritePayload(payload: AFSWriteEntryPayload): unknown {\n if (typeof payload.content === \"string\") {\n try {\n return JSON.parse(payload.content);\n } catch {\n throw new Error(\"Invalid JSON in write payload\");\n }\n }\n return payload.content;\n}\n\n/** Validate portId is a positive integer. */\nfunction validatePortId(portId: string): number {\n const num = Number.parseInt(portId, 10);\n if (!Number.isFinite(num) || num < 1 || String(num) !== portId) {\n throw new AFSNotFoundError(`Invalid port: ${portId}`);\n }\n return num;\n}\n\n// ============================================================================\n// Write payload schemas (allowlisted fields only)\n// ============================================================================\n\nconst ssidWriteSchema = z\n .object({\n name: z.string().optional(),\n enable: z.boolean().optional(),\n band: z.number().int().min(0).max(2).optional(),\n security: z.string().optional(),\n vlanId: z.number().int().min(0).max(4094).optional(),\n guestNetwork: z.boolean().optional(),\n })\n .strict();\n\nconst wiredNetworkWriteSchema = z\n .object({\n name: z.string().optional(),\n vlanId: z.number().int().min(0).max(4094).optional(),\n subnet: z.string().optional(),\n gateway: z.string().optional(),\n dhcpEnabled: z.boolean().optional(),\n })\n .strict();\n\nconst wifiOptimizationWriteSchema = z\n .object({\n autoChannel: z.boolean().optional(),\n roaming: z.boolean().optional(),\n bandSteering: z.boolean().optional(),\n })\n .strict();\n\nconst portConfigWriteSchema = z\n .object({\n enable: z.boolean().optional(),\n poeEnabled: z.boolean().optional(),\n vlanId: z.number().int().min(0).max(4094).optional(),\n profileName: z.string().optional(),\n })\n .strict();\n\nconst deviceConfigWriteSchema = z\n .object({\n name: z.string().optional(),\n // Switch-specific fields\n poeEnabled: z.boolean().optional(),\n // AP radio settings\n txPower: z.number().int().min(0).max(30).optional(),\n channel: z.number().int().min(0).optional(),\n })\n .strict();\n\n// ============================================================================\n// Types for Omada API responses\n// ============================================================================\n\ninterface OmadaSite {\n siteId: string;\n name: string;\n region?: string;\n}\n\ninterface OmadaDevice {\n mac: string;\n name: string;\n model: string;\n firmwareVersion: string;\n status: number;\n statusCategory: number;\n type: string;\n cpuUtil?: number;\n memUtil?: number;\n uptime?: string;\n poeRemain?: number;\n radioSetting2g?: { channel: number; txPower: number };\n radioSetting5g?: { channel: number; txPower: number };\n}\n\ninterface OmadaClient {\n mac: string;\n name: string;\n ip: string;\n ssid?: string;\n signalLevel?: number;\n trafficDown?: number;\n trafficUp?: number;\n connectDevMac?: string;\n}\n\ninterface OmadaDashboard {\n totalDevices: number;\n connectedDevices: number;\n totalClients: number;\n gatewayNum: number;\n switchNum: number;\n apNum: number;\n}\n\ninterface OmadaSsid {\n id: string;\n name: string;\n band: number; // 0=2.4GHz, 1=both, 2=5GHz\n enable: boolean;\n security: string;\n vlanId: number;\n guestNetwork: boolean;\n}\n\ninterface OmadaWiredNetwork {\n id: string;\n name: string;\n vlanId: number;\n subnet: string;\n gateway: string;\n dhcpEnabled: boolean;\n}\n\ninterface OmadaWifiOptimization {\n autoChannel: boolean;\n roaming: boolean;\n bandSteering: boolean;\n}\n\ninterface OmadaSwitchPort {\n port: number;\n name: string;\n profileName: string;\n enable: boolean;\n linkStatus: number;\n linkSpeed: string;\n duplex: string;\n poe: boolean;\n poeEnabled: boolean;\n poePower: number;\n vlanId: number;\n}\n\ninterface OmadaFirmwareInfo {\n currentVersion: string;\n latestVersion: string;\n hasUpdate: boolean;\n}\n\n// Device type classification based on Omada API type field\nconst DEVICE_TYPE_MAP: Record<string, string> = {\n gateway: \"gateways\",\n switch: \"switches\",\n ap: \"aps\",\n};\n\nconst DEVICE_KIND_MAP: Record<string, string> = {\n gateways: \"network:gateway\",\n switches: \"network:switch\",\n aps: \"network:access-point\",\n};\n\nconst VALID_DEVICE_CATEGORIES = [\"gateways\", \"switches\", \"aps\"];\n\n/**\n * AFSOmadaProvider maps TP-Link Omada SDN Controller as an AFS filesystem.\n *\n * Controller -> Sites -> Devices (Gateways/Switches/APs) -> Clients\n * are mapped to a directory hierarchy accessible via standard AFS operations.\n */\nexport class AFSOmadaProvider extends AFSBaseProvider {\n static securityProfiles(): Record<string, SecurityProfile> {\n return {\n admin: { actionPolicy: \"full\", sensitivity: \"full\" },\n user: {\n actionPolicy: \"standard\",\n sensitiveFields: [\"mac\", \"ip\"],\n sensitivity: \"redacted\",\n },\n guest: {\n actionPolicy: \"safe\",\n accessMode: \"readonly\",\n sensitiveFields: [\"mac\", \"ip\"],\n sensitivity: \"redacted\",\n },\n };\n }\n\n static schema() {\n return afsOmadaOptionsSchema;\n }\n\n static manifest(): ProviderManifest {\n return {\n name: \"omada\",\n description:\n \"TP-Link Omada SDN Controller — network devices as filesystem.\\n- Controller -> Sites -> Devices (Gateways/Switches/APs) -> Clients\\n- Read device status, manage ports, view dashboard, configure networks\\n- VPN, firewall, routing, NAT, logs, firmware management\\n- Path structure: `/sites/{siteId}/devices/{type}/{mac}`\",\n uriTemplate: \"omada://{host}\",\n category: \"network\",\n schema: z.object({ host: z.string() }),\n tags: [\"omada\", \"network\", \"sdn\", \"device\"],\n capabilityTags: [\n \"read-write\",\n \"crud\",\n \"search\",\n \"auth:token\",\n \"remote\",\n \"http\",\n \"on-premise\",\n ],\n security: {\n riskLevel: \"external\",\n resourceAccess: [\"internet\", \"local-network\"],\n dataSensitivity: [\"system-config\"],\n notes: [\"Manages network infrastructure — misconfiguration can cause network outages\"],\n },\n capabilities: {\n network: { egress: true },\n secrets: [\"omada/password\"],\n },\n };\n }\n\n static treeSchema(): ProviderTreeSchema {\n return {\n operations: [\"list\", \"read\", \"write\", \"search\", \"exec\", \"stat\", \"explain\"],\n tree: {\n \"/\": {\n kind: \"network:controller\",\n actions: [\"create-site\"],\n },\n \"/sites\": { kind: \"afs:directory\", operations: [\"list\"] },\n \"/sites/{siteId}\": { kind: \"network:site\", operations: [\"list\", \"read\"] },\n \"/sites/{siteId}/devices\": { kind: \"network:device-group\", operations: [\"list\"] },\n \"/sites/{siteId}/devices/gateways\": { kind: \"network:device-group\", operations: [\"list\"] },\n \"/sites/{siteId}/devices/gateways/{mac}\": {\n kind: \"network:gateway\",\n operations: [\"read\", \"write\", \"exec\"],\n actions: [\"reboot\", \"upgrade-firmware\"],\n destructive: [\"reboot\"],\n },\n \"/sites/{siteId}/devices/gateways/{mac}/firmware\": {\n kind: \"network:firmware\",\n operations: [\"read\"],\n },\n \"/sites/{siteId}/devices/switches\": { kind: \"network:device-group\", operations: [\"list\"] },\n \"/sites/{siteId}/devices/switches/{mac}\": {\n kind: \"network:switch\",\n operations: [\"read\", \"write\", \"exec\"],\n actions: [\"reboot\", \"upgrade-firmware\"],\n destructive: [\"reboot\"],\n },\n \"/sites/{siteId}/devices/switches/{mac}/ports\": {\n kind: \"network:port-group\",\n operations: [\"list\"],\n },\n \"/sites/{siteId}/devices/switches/{mac}/firmware\": {\n kind: \"network:firmware\",\n operations: [\"read\"],\n },\n \"/sites/{siteId}/devices/aps\": { kind: \"network:device-group\", operations: [\"list\"] },\n \"/sites/{siteId}/devices/aps/{mac}\": {\n kind: \"network:access-point\",\n operations: [\"read\", \"write\", \"exec\"],\n actions: [\"reboot\", \"upgrade-firmware\"],\n destructive: [\"reboot\"],\n },\n \"/sites/{siteId}/devices/aps/{mac}/firmware\": {\n kind: \"network:firmware\",\n operations: [\"read\"],\n },\n \"/sites/{siteId}/clients\": { kind: \"afs:directory\", operations: [\"list\"] },\n \"/sites/{siteId}/clients/{mac}\": {\n kind: \"network:client\",\n operations: [\"read\", \"exec\"],\n actions: [\"block\", \"unblock\"],\n },\n \"/sites/{siteId}/dashboard\": { kind: \"network:dashboard\", operations: [\"read\"] },\n \"/sites/{siteId}/networks\": { kind: \"network:network\", operations: [\"list\", \"read\"] },\n \"/sites/{siteId}/networks/wireless\": { kind: \"network:wireless\", operations: [\"list\"] },\n \"/sites/{siteId}/networks/wireless/{ssidId}\": {\n kind: \"network:ssid\",\n operations: [\"read\"],\n },\n \"/sites/{siteId}/networks/wired\": { kind: \"network:wired\", operations: [\"list\"] },\n \"/sites/{siteId}/networks/wired/{netId}\": { kind: \"network:vlan\", operations: [\"read\"] },\n \"/sites/{siteId}/networks/wifi-optimization\": {\n kind: \"network:wifi-optimization\",\n operations: [\"read\"],\n },\n \"/sites/{siteId}/vpn\": { kind: \"network:vpn\", operations: [\"read\"] },\n \"/sites/{siteId}/firewall\": { kind: \"network:firewall\", operations: [\"read\"] },\n \"/sites/{siteId}/routing\": { kind: \"network:routing\", operations: [\"read\"] },\n \"/sites/{siteId}/nat\": { kind: \"network:nat\", operations: [\"read\"] },\n \"/sites/{siteId}/logs\": { kind: \"network:logs\", operations: [\"read\"] },\n },\n auth: { type: \"custom\", env: [\"OMADA_CLIENT_ID\", \"OMADA_CLIENT_SECRET\"] },\n bestFor: [\"network monitoring\", \"SDN management\", \"device control\"],\n notFor: [\"file storage\", \"database queries\"],\n };\n }\n\n static async load({ config }: AFSModuleLoadParams = {}) {\n const valid = afsOmadaOptionsSchema.parse(config);\n return new AFSOmadaProvider(valid);\n }\n\n readonly name: string;\n readonly description?: string;\n readonly accessMode: AFSAccessMode;\n private client: OmadaApiClient;\n\n constructor(options: AFSOmadaOptionsInput) {\n super();\n const parsed = afsOmadaOptionsSchema.parse(options);\n this.name = parsed.name;\n this.description = parsed.description;\n this.accessMode = parsed.accessMode;\n this.client = new OmadaApiClient(\n parsed.baseUrl,\n parsed.clientId,\n parsed.clientSecret,\n parsed.omadacId,\n parsed.strictSsl,\n );\n }\n\n // ========== Capabilities ==========\n\n @Read(\"/.meta/.capabilities\")\n async readCapabilities(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const manifest: CapabilitiesManifest = {\n schemaVersion: 1,\n provider: this.name,\n description:\n this.description || \"TP-Link Omada SDN Controller — network devices as filesystem\",\n tools: [],\n actions: [],\n operations: this.getOperationsDeclaration(),\n };\n\n return {\n id: \"/.meta/.capabilities\",\n path: \"/.meta/.capabilities\",\n content: manifest,\n meta: {\n kind: \"afs:capabilities\",\n operations: [\"list\", \"read\", \"stat\", \"explain\", \"search\", \"write\", \"exec\", \"delete\"].filter(\n (op) => {\n const decl = manifest.operations as unknown as Record<string, boolean>;\n return decl[op];\n },\n ),\n },\n };\n }\n\n // ========== Root handlers ==========\n\n @List(\"/\")\n async listRoot(_ctx: RouteContext): Promise<AFSListResult> {\n const result = await this.client.request<{ data: OmadaSite[] }>(\"/sites\");\n const sites = result?.data ?? [];\n\n return {\n data: [\n this.buildEntry(\"/sites\", {\n meta: {\n kind: \"network:container\",\n childrenCount: sites.length,\n },\n }),\n ],\n };\n }\n\n @Read(\"/\")\n async readRoot(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n return this.buildEntry(\"/\", {\n content: \"Omada SDN Controller\",\n meta: {\n kind: \"network:controller\",\n childrenCount: 1,\n description: \"Omada SDN Controller\",\n },\n });\n }\n\n @Meta(\"/\")\n async metaRoot(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n return this.buildEntry(\"/.meta\", {\n meta: {\n kind: \"network:controller\",\n childrenCount: 1,\n description: \"Omada SDN Controller\",\n events: [\n { type: \"omada:device_reboot\", description: \"Device reboot initiated\" },\n { type: \"omada:firmware_upgrade\", description: \"Device firmware upgrade initiated\" },\n { type: \"omada:client_blocked\", description: \"Client blocked from network\" },\n { type: \"omada:client_unblocked\", description: \"Client unblocked from network\" },\n { type: \"omada:network_updated\", description: \"Network configuration updated\" },\n { type: \"omada:device_config_updated\", description: \"Device configuration updated\" },\n ],\n },\n });\n }\n\n @Stat(\"/\")\n async statRoot(_ctx: RouteContext): Promise<AFSStatResult> {\n return {\n data: {\n id: \"/\",\n path: \"/\",\n meta: {\n kind: \"network:controller\",\n childrenCount: 1,\n description: \"Omada SDN Controller\",\n },\n },\n };\n }\n\n // ========== Sites handlers ==========\n\n @List(\"/sites\")\n async listSites(_ctx: RouteContext): Promise<AFSListResult> {\n const result = await this.client.request<{ data: OmadaSite[] }>(\"/sites\");\n const sites = result?.data ?? [];\n\n return {\n data: sites.map((site) =>\n this.buildEntry(joinURL(\"/sites\", site.siteId), {\n id: site.siteId,\n meta: {\n kind: \"network:site\",\n childrenCount: 9, // devices, clients, dashboard, networks, vpn, firewall, routing, nat, logs\n description: site.name,\n },\n }),\n ),\n };\n }\n\n @Read(\"/sites\")\n async readSites(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const result = await this.client.request<{ data: OmadaSite[] }>(\"/sites\");\n const sites = result?.data ?? [];\n\n return this.buildEntry(\"/sites\", {\n content: sites.map((s) => `${s.siteId}: ${s.name}`).join(\"\\n\"),\n meta: {\n kind: \"network:container\",\n childrenCount: sites.length,\n },\n });\n }\n\n @Meta(\"/sites\")\n async metaSites(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const result = await this.client.request<{ data: OmadaSite[] }>(\"/sites\");\n const sites = result?.data ?? [];\n\n return this.buildEntry(\"/sites/.meta\", {\n meta: {\n kind: \"network:container\",\n childrenCount: sites.length,\n },\n });\n }\n\n @Stat(\"/sites\")\n async statSites(_ctx: RouteContext): Promise<AFSStatResult> {\n const result = await this.client.request<{ data: OmadaSite[] }>(\"/sites\");\n const sites = result?.data ?? [];\n\n return {\n data: {\n id: \"/sites\",\n path: \"/sites\",\n meta: {\n kind: \"network:container\",\n childrenCount: sites.length,\n },\n },\n };\n }\n\n // ========== Single site handlers ==========\n\n @List(\"/sites/:siteId\")\n async listSite(ctx: RouteContext<{ siteId: string }>): Promise<AFSListResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n return {\n data: [\n this.buildEntry(joinURL(\"/sites\", siteId, \"devices\"), {\n meta: { kind: \"network:device-group\", childrenCount: 3 },\n }),\n this.buildEntry(joinURL(\"/sites\", siteId, \"clients\"), {\n meta: { childrenCount: -1 },\n }),\n this.buildEntry(joinURL(\"/sites\", siteId, \"dashboard\"), {\n meta: { kind: \"network:dashboard\", childrenCount: 0 },\n }),\n this.buildEntry(joinURL(\"/sites\", siteId, \"networks\"), {\n meta: { kind: \"network:network\", childrenCount: 3 },\n }),\n this.buildEntry(joinURL(\"/sites\", siteId, \"vpn\"), {\n meta: { kind: \"network:vpn\", childrenCount: 0 },\n }),\n this.buildEntry(joinURL(\"/sites\", siteId, \"firewall\"), {\n meta: { kind: \"network:firewall\", childrenCount: 0 },\n }),\n this.buildEntry(joinURL(\"/sites\", siteId, \"routing\"), {\n meta: { kind: \"network:routing\", childrenCount: 0 },\n }),\n this.buildEntry(joinURL(\"/sites\", siteId, \"nat\"), {\n meta: { kind: \"network:nat\", childrenCount: 0 },\n }),\n this.buildEntry(joinURL(\"/sites\", siteId, \"logs\"), {\n meta: { kind: \"network:logs\", childrenCount: 0 },\n }),\n ],\n };\n }\n\n @Read(\"/sites/:siteId\")\n async readSite(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n const site = await this.getSite(siteId);\n\n return this.buildEntry(joinURL(\"/sites\", siteId), {\n id: site.siteId,\n content: `${site.name} (${site.region || \"default\"})`,\n meta: {\n kind: \"network:site\",\n childrenCount: 9,\n description: site.name,\n },\n });\n }\n\n @Meta(\"/sites/:siteId\")\n async metaSite(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n const site = await this.getSite(siteId);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \".meta\"), {\n meta: {\n kind: \"network:site\",\n childrenCount: 9,\n description: site.name,\n },\n });\n }\n\n @Stat(\"/sites/:siteId\")\n async statSite(ctx: RouteContext<{ siteId: string }>): Promise<AFSStatResult> {\n const { siteId } = ctx.params;\n const site = await this.getSite(siteId);\n\n return {\n data: {\n id: site.siteId,\n path: joinURL(\"/sites\", siteId),\n meta: {\n kind: \"network:site\",\n childrenCount: 9,\n description: site.name,\n },\n },\n };\n }\n\n // ========== Devices container handlers ==========\n\n @List(\"/sites/:siteId/devices\")\n async listDevicesContainer(ctx: RouteContext<{ siteId: string }>): Promise<AFSListResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const devices = await this.getAllDevices(siteId);\n const gateways = devices.filter((d) => DEVICE_TYPE_MAP[d.type] === \"gateways\");\n const switches = devices.filter((d) => DEVICE_TYPE_MAP[d.type] === \"switches\");\n const aps = devices.filter((d) => DEVICE_TYPE_MAP[d.type] === \"aps\");\n\n return {\n data: [\n this.buildEntry(joinURL(\"/sites\", siteId, \"devices/gateways\"), {\n meta: { kind: \"network:device-group\", childrenCount: gateways.length },\n }),\n this.buildEntry(joinURL(\"/sites\", siteId, \"devices/switches\"), {\n meta: { kind: \"network:device-group\", childrenCount: switches.length },\n }),\n this.buildEntry(joinURL(\"/sites\", siteId, \"devices/aps\"), {\n meta: { kind: \"network:device-group\", childrenCount: aps.length },\n }),\n ],\n };\n }\n\n @Read(\"/sites/:siteId/devices\")\n async readDevicesContainer(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const devices = await this.getAllDevices(siteId);\n const gateways = devices.filter((d) => DEVICE_TYPE_MAP[d.type] === \"gateways\");\n const switches = devices.filter((d) => DEVICE_TYPE_MAP[d.type] === \"switches\");\n const aps = devices.filter((d) => DEVICE_TYPE_MAP[d.type] === \"aps\");\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"devices\"), {\n content: `Devices: ${devices.length} total\\nGateways: ${gateways.length} | Switches: ${switches.length} | APs: ${aps.length}`,\n meta: {\n kind: \"network:device-group\",\n childrenCount: 3,\n },\n });\n }\n\n @Meta(\"/sites/:siteId/devices\")\n async metaDevicesContainer(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"devices/.meta\"), {\n meta: {\n kind: \"network:device-group\",\n childrenCount: 3,\n },\n });\n }\n\n @Stat(\"/sites/:siteId/devices\")\n async statDevicesContainer(ctx: RouteContext<{ siteId: string }>): Promise<AFSStatResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"devices\"),\n path: joinURL(\"/sites\", siteId, \"devices\"),\n meta: {\n kind: \"network:device-group\",\n childrenCount: 3,\n },\n },\n };\n }\n\n // ========== Device category handlers ==========\n\n @List(\"/sites/:siteId/devices/:category\")\n async listDeviceCategory(\n ctx: RouteContext<{ siteId: string; category: string }>,\n ): Promise<AFSListResult> {\n const { siteId, category } = ctx.params;\n this.validateDeviceCategory(category);\n await this.validateSite(siteId);\n\n const devices = await this.getDevicesByCategory(siteId, category);\n\n return {\n data: devices.map((device) => {\n const mac = normalizeMac(device.mac);\n const kind = DEVICE_KIND_MAP[category];\n const status = mapDeviceStatus(device.status);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"devices\", category, mac), {\n id: mac,\n content: this.formatDeviceContent(device, category),\n meta: {\n kind,\n childrenCount: this.deviceChildrenCount(category),\n model: device.model,\n status,\n firmware: device.firmwareVersion,\n },\n });\n }),\n };\n }\n\n @Read(\"/sites/:siteId/devices/:category\")\n async readDeviceCategory(\n ctx: RouteContext<{ siteId: string; category: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, category } = ctx.params;\n this.validateDeviceCategory(category);\n await this.validateSite(siteId);\n\n const devices = await this.getDevicesByCategory(siteId, category);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"devices\", category), {\n content: devices.map((d) => `${normalizeMac(d.mac)}: ${d.name} (${d.model})`).join(\"\\n\"),\n meta: {\n kind: \"network:device-group\",\n childrenCount: devices.length,\n },\n });\n }\n\n @Meta(\"/sites/:siteId/devices/:category\")\n async metaDeviceCategory(\n ctx: RouteContext<{ siteId: string; category: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, category } = ctx.params;\n this.validateDeviceCategory(category);\n await this.validateSite(siteId);\n\n const devices = await this.getDevicesByCategory(siteId, category);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"devices\", category, \".meta\"), {\n meta: {\n kind: \"network:device-group\",\n childrenCount: devices.length,\n },\n });\n }\n\n @Stat(\"/sites/:siteId/devices/:category\")\n async statDeviceCategory(\n ctx: RouteContext<{ siteId: string; category: string }>,\n ): Promise<AFSStatResult> {\n const { siteId, category } = ctx.params;\n this.validateDeviceCategory(category);\n await this.validateSite(siteId);\n\n const devices = await this.getDevicesByCategory(siteId, category);\n\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"devices\", category),\n path: joinURL(\"/sites\", siteId, \"devices\", category),\n meta: {\n kind: \"network:device-group\",\n childrenCount: devices.length,\n },\n },\n };\n }\n\n // ========== Single device handlers ==========\n\n @List(\"/sites/:siteId/devices/:category/:mac\")\n async listDevice(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n ): Promise<AFSListResult> {\n const { siteId, category, mac } = ctx.params;\n this.validateDeviceCategory(category);\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, category, normalizedMac);\n\n const basePath = joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac);\n const children: AFSEntry[] = [];\n\n // Switches have ports\n if (category === \"switches\") {\n children.push(\n this.buildEntry(joinURL(basePath, \"ports\"), {\n meta: { kind: \"network:port-group\" },\n }),\n );\n }\n\n // All devices have firmware\n children.push(\n this.buildEntry(joinURL(basePath, \"firmware\"), {\n meta: { kind: \"network:firmware\", childrenCount: 0 },\n }),\n );\n\n return { data: children };\n }\n\n @Read(\"/sites/:siteId/devices/:category/:mac\")\n async readDevice(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, category, mac } = ctx.params;\n this.validateDeviceCategory(category);\n const normalizedMac = normalizeMac(mac);\n\n const device = await this.getDevice(siteId, category, normalizedMac);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac), {\n id: normalizedMac,\n content: this.formatDeviceContent(device, category),\n meta: {\n kind: DEVICE_KIND_MAP[category],\n childrenCount: this.deviceChildrenCount(category),\n model: device.model,\n status: mapDeviceStatus(device.status),\n firmware: device.firmwareVersion,\n },\n });\n }\n\n @Meta(\"/sites/:siteId/devices/:category/:mac\")\n async metaDevice(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, category, mac } = ctx.params;\n this.validateDeviceCategory(category);\n const normalizedMac = normalizeMac(mac);\n\n const device = await this.getDevice(siteId, category, normalizedMac);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac, \".meta\"), {\n meta: {\n kind: DEVICE_KIND_MAP[category],\n childrenCount: this.deviceChildrenCount(category),\n model: device.model,\n status: mapDeviceStatus(device.status),\n firmware: device.firmwareVersion,\n },\n });\n }\n\n @Stat(\"/sites/:siteId/devices/:category/:mac\")\n async statDevice(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n ): Promise<AFSStatResult> {\n const { siteId, category, mac } = ctx.params;\n this.validateDeviceCategory(category);\n const normalizedMac = normalizeMac(mac);\n\n const device = await this.getDevice(siteId, category, normalizedMac);\n\n return {\n data: {\n id: normalizedMac,\n path: joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac),\n meta: {\n kind: DEVICE_KIND_MAP[category],\n childrenCount: this.deviceChildrenCount(category),\n model: device.model,\n status: mapDeviceStatus(device.status),\n firmware: device.firmwareVersion,\n },\n },\n };\n }\n\n // ========== Clients handlers ==========\n\n @List(\"/sites/:siteId/clients\")\n async listClients(ctx: RouteContext<{ siteId: string }>): Promise<AFSListResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const result = await this.client.request<{ data: OmadaClient[] }>(\n joinURL(\"/sites\", siteId, \"clients\"),\n );\n const clients = result?.data ?? [];\n\n return {\n data: clients.map((c) => {\n const mac = normalizeMac(c.mac);\n return this.buildEntry(joinURL(\"/sites\", siteId, \"clients\", mac), {\n id: mac,\n content: this.formatClientContent(c),\n meta: {\n kind: \"network:client\",\n childrenCount: 0,\n ip: c.ip,\n ssid: c.ssid,\n },\n });\n }),\n };\n }\n\n @Read(\"/sites/:siteId/clients\")\n async readClients(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const result = await this.client.request<{ data: OmadaClient[] }>(\n joinURL(\"/sites\", siteId, \"clients\"),\n );\n const clients = result?.data ?? [];\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"clients\"), {\n content: clients.map((c) => `${normalizeMac(c.mac)}: ${c.name} (${c.ip})`).join(\"\\n\"),\n meta: {\n childrenCount: -1,\n },\n });\n }\n\n @Meta(\"/sites/:siteId/clients\")\n async metaClients(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"clients/.meta\"), {\n meta: {\n childrenCount: -1,\n },\n });\n }\n\n @Stat(\"/sites/:siteId/clients\")\n async statClients(ctx: RouteContext<{ siteId: string }>): Promise<AFSStatResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"clients\"),\n path: joinURL(\"/sites\", siteId, \"clients\"),\n meta: {\n childrenCount: -1,\n },\n },\n };\n }\n\n // ========== Single client handlers ==========\n\n @List(\"/sites/:siteId/clients/:mac\")\n async listClient(ctx: RouteContext<{ siteId: string; mac: string }>): Promise<AFSListResult> {\n // Leaf node: clients have no children\n const { siteId, mac } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n await this.getClient(siteId, normalizedMac); // validate existence\n return { data: [] };\n }\n\n @Read(\"/sites/:siteId/clients/:mac\")\n async readClient(\n ctx: RouteContext<{ siteId: string; mac: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, mac } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n const client = await this.getClient(siteId, normalizedMac);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"clients\", normalizedMac), {\n id: normalizedMac,\n content: this.formatClientContent(client),\n meta: {\n kind: \"network:client\",\n childrenCount: 0,\n ip: client.ip,\n ssid: client.ssid,\n },\n });\n }\n\n @Meta(\"/sites/:siteId/clients/:mac\")\n async metaClient(\n ctx: RouteContext<{ siteId: string; mac: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, mac } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n const client = await this.getClient(siteId, normalizedMac);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"clients\", normalizedMac, \".meta\"), {\n meta: {\n kind: \"network:client\",\n childrenCount: 0,\n ip: client.ip,\n ssid: client.ssid,\n },\n });\n }\n\n @Stat(\"/sites/:siteId/clients/:mac\")\n async statClient(ctx: RouteContext<{ siteId: string; mac: string }>): Promise<AFSStatResult> {\n const { siteId, mac } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n const client = await this.getClient(siteId, normalizedMac);\n\n return {\n data: {\n id: normalizedMac,\n path: joinURL(\"/sites\", siteId, \"clients\", normalizedMac),\n meta: {\n kind: \"network:client\",\n childrenCount: 0,\n ip: client.ip,\n ssid: client.ssid,\n },\n },\n };\n }\n\n // ========== Dashboard handlers ==========\n\n @List(\"/sites/:siteId/dashboard\")\n async listDashboard(ctx: RouteContext<{ siteId: string }>): Promise<AFSListResult> {\n // Leaf node: dashboard has no children\n await this.validateSite(ctx.params.siteId);\n return { data: [] };\n }\n\n @Read(\"/sites/:siteId/dashboard\")\n async readDashboard(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n const site = await this.getSite(siteId);\n\n const dashboard = await this.client.request<OmadaDashboard>(\n joinURL(\"/sites\", siteId, \"dashboard\"),\n );\n\n const totalDevices = dashboard?.totalDevices ?? 0;\n const connectedDevices = dashboard?.connectedDevices ?? 0;\n const totalClients = dashboard?.totalClients ?? 0;\n const gatewayNum = dashboard?.gatewayNum ?? 0;\n const switchNum = dashboard?.switchNum ?? 0;\n const apNum = dashboard?.apNum ?? 0;\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"dashboard\"), {\n content: `${site.name} Dashboard\\nDevices: ${totalDevices} (${connectedDevices} connected) | Clients: ${totalClients}\\nGateways: ${gatewayNum} | Switches: ${switchNum} | APs: ${apNum}`,\n meta: {\n kind: \"network:dashboard\",\n childrenCount: 0,\n },\n });\n }\n\n @Meta(\"/sites/:siteId/dashboard\")\n async metaDashboard(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"dashboard/.meta\"), {\n meta: {\n kind: \"network:dashboard\",\n childrenCount: 0,\n },\n });\n }\n\n @Stat(\"/sites/:siteId/dashboard\")\n async statDashboard(ctx: RouteContext<{ siteId: string }>): Promise<AFSStatResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"dashboard\"),\n path: joinURL(\"/sites\", siteId, \"dashboard\"),\n meta: {\n kind: \"network:dashboard\",\n childrenCount: 0,\n },\n },\n };\n }\n\n // ========== Networks handlers ==========\n\n @List(\"/sites/:siteId/networks\")\n async listNetworks(ctx: RouteContext<{ siteId: string }>): Promise<AFSListResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n // Fetch counts for children\n const ssidResult = await this.client.request<{ data: OmadaSsid[] }>(\n joinURL(\"/sites\", siteId, \"setting/ssids\"),\n );\n const ssidCount = ssidResult?.data?.length ?? 0;\n\n const netResult = await this.client.request<{ data: OmadaWiredNetwork[] }>(\n joinURL(\"/sites\", siteId, \"setting/lan/networks\"),\n );\n const netCount = netResult?.data?.length ?? 0;\n\n return {\n data: [\n this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wireless\"), {\n meta: { kind: \"network:wireless\", childrenCount: ssidCount },\n }),\n this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wired\"), {\n meta: { kind: \"network:wired\", childrenCount: netCount },\n }),\n this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wifi-optimization\"), {\n meta: { kind: \"network:wifi-optimization\", childrenCount: 0 },\n }),\n ],\n };\n }\n\n @Read(\"/sites/:siteId/networks\")\n async readNetworks(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"networks\"), {\n content: \"Network configuration summary\",\n meta: {\n kind: \"network:network\",\n childrenCount: 3,\n },\n });\n }\n\n @Meta(\"/sites/:siteId/networks\")\n async metaNetworks(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"networks/.meta\"), {\n meta: {\n kind: \"network:network\",\n childrenCount: 3,\n },\n });\n }\n\n @Stat(\"/sites/:siteId/networks\")\n async statNetworks(ctx: RouteContext<{ siteId: string }>): Promise<AFSStatResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"networks\"),\n path: joinURL(\"/sites\", siteId, \"networks\"),\n meta: {\n kind: \"network:network\",\n childrenCount: 3,\n },\n },\n };\n }\n\n // ========== Wireless SSID handlers ==========\n\n @List(\"/sites/:siteId/networks/wireless\")\n async listWirelessSsids(ctx: RouteContext<{ siteId: string }>): Promise<AFSListResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const result = await this.client.request<{ data: OmadaSsid[] }>(\n joinURL(\"/sites\", siteId, \"setting/ssids\"),\n );\n const ssids = result?.data ?? [];\n\n return {\n data: ssids.map((ssid) =>\n this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wireless\", ssid.id), {\n id: ssid.id,\n content: this.formatSsidContent(ssid),\n meta: {\n kind: \"network:ssid\",\n name: ssid.name,\n band: this.mapBand(ssid.band),\n security: ssid.security,\n vlanId: ssid.vlanId,\n enabled: ssid.enable,\n childrenCount: 0,\n },\n }),\n ),\n };\n }\n\n @Read(\"/sites/:siteId/networks/wireless\")\n async readWireless(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const result = await this.client.request<{ data: OmadaSsid[] }>(\n joinURL(\"/sites\", siteId, \"setting/ssids\"),\n );\n const ssids = result?.data ?? [];\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wireless\"), {\n content: ssids.map((s) => `${s.id}: ${s.name} (${this.mapBand(s.band)})`).join(\"\\n\"),\n meta: {\n kind: \"network:wireless\",\n childrenCount: ssids.length,\n },\n });\n }\n\n @Meta(\"/sites/:siteId/networks/wireless\")\n async metaWireless(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const result = await this.client.request<{ data: OmadaSsid[] }>(\n joinURL(\"/sites\", siteId, \"setting/ssids\"),\n );\n const ssids = result?.data ?? [];\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wireless/.meta\"), {\n meta: {\n kind: \"network:wireless\",\n childrenCount: ssids.length,\n },\n });\n }\n\n @Stat(\"/sites/:siteId/networks/wireless\")\n async statWireless(ctx: RouteContext<{ siteId: string }>): Promise<AFSStatResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const result = await this.client.request<{ data: OmadaSsid[] }>(\n joinURL(\"/sites\", siteId, \"setting/ssids\"),\n );\n const ssids = result?.data ?? [];\n\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"networks/wireless\"),\n path: joinURL(\"/sites\", siteId, \"networks/wireless\"),\n meta: {\n kind: \"network:wireless\",\n childrenCount: ssids.length,\n },\n },\n };\n }\n\n @Read(\"/sites/:siteId/networks/wireless/:ssidId\")\n async readSsid(\n ctx: RouteContext<{ siteId: string; ssidId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, ssidId } = ctx.params;\n await this.validateSite(siteId);\n const ssid = await this.getSsid(siteId, ssidId);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wireless\", ssidId), {\n id: ssidId,\n content: this.formatSsidContent(ssid),\n meta: {\n kind: \"network:ssid\",\n name: ssid.name,\n band: this.mapBand(ssid.band),\n security: ssid.security,\n vlanId: ssid.vlanId,\n enabled: ssid.enable,\n childrenCount: 0,\n },\n });\n }\n\n @List(\"/sites/:siteId/networks/wireless/:ssidId\")\n async listSsid(ctx: RouteContext<{ siteId: string; ssidId: string }>): Promise<AFSListResult> {\n const { siteId, ssidId } = ctx.params;\n await this.validateSite(siteId);\n await this.getSsid(siteId, ssidId);\n return { data: [] };\n }\n\n @Meta(\"/sites/:siteId/networks/wireless/:ssidId\")\n async metaSsid(\n ctx: RouteContext<{ siteId: string; ssidId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, ssidId } = ctx.params;\n await this.validateSite(siteId);\n const ssid = await this.getSsid(siteId, ssidId);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wireless\", ssidId, \".meta\"), {\n meta: {\n kind: \"network:ssid\",\n name: ssid.name,\n childrenCount: 0,\n },\n });\n }\n\n @Stat(\"/sites/:siteId/networks/wireless/:ssidId\")\n async statSsid(ctx: RouteContext<{ siteId: string; ssidId: string }>): Promise<AFSStatResult> {\n const { siteId, ssidId } = ctx.params;\n await this.validateSite(siteId);\n const ssid = await this.getSsid(siteId, ssidId);\n\n return {\n data: {\n id: ssidId,\n path: joinURL(\"/sites\", siteId, \"networks/wireless\", ssidId),\n meta: {\n kind: \"network:ssid\",\n name: ssid.name,\n childrenCount: 0,\n },\n },\n };\n }\n\n @Write(\"/sites/:siteId/networks/wireless/:ssidId\")\n async writeSsid(\n ctx: RouteContext<{ siteId: string; ssidId: string }>,\n payload: AFSWriteEntryPayload,\n ): Promise<AFSWriteResult> {\n const { siteId, ssidId } = ctx.params;\n await this.validateSite(siteId);\n await this.getSsid(siteId, ssidId);\n\n const raw = parseWritePayload(payload);\n const config = ssidWriteSchema.parse(raw);\n\n await this.client.patch(joinURL(\"/sites\", siteId, \"setting/ssids\", ssidId), config);\n\n this.emit({\n type: \"omada:network_updated\",\n path: joinURL(\"/sites\", siteId, \"networks/wireless\", ssidId),\n data: { siteId, ssidId, networkType: \"wireless\" },\n });\n\n return {\n data: this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wireless\", ssidId), {\n content: JSON.stringify(config),\n meta: { kind: \"network:ssid\" },\n }),\n message: \"SSID config updated\",\n };\n }\n\n // ========== Wired network handlers ==========\n\n @List(\"/sites/:siteId/networks/wired\")\n async listWiredNetworks(ctx: RouteContext<{ siteId: string }>): Promise<AFSListResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const result = await this.client.request<{ data: OmadaWiredNetwork[] }>(\n joinURL(\"/sites\", siteId, \"setting/lan/networks\"),\n );\n const networks = result?.data ?? [];\n\n return {\n data: networks.map((net) =>\n this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wired\", net.id), {\n id: net.id,\n content: this.formatWiredNetworkContent(net),\n meta: {\n kind: \"network:vlan\",\n name: net.name,\n vlanId: net.vlanId,\n subnet: net.subnet,\n childrenCount: 0,\n },\n }),\n ),\n };\n }\n\n @Read(\"/sites/:siteId/networks/wired\")\n async readWired(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const result = await this.client.request<{ data: OmadaWiredNetwork[] }>(\n joinURL(\"/sites\", siteId, \"setting/lan/networks\"),\n );\n const networks = result?.data ?? [];\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wired\"), {\n content: networks.map((n) => `${n.id}: ${n.name} (VLAN ${n.vlanId})`).join(\"\\n\"),\n meta: {\n kind: \"network:wired\",\n childrenCount: networks.length,\n },\n });\n }\n\n @Meta(\"/sites/:siteId/networks/wired\")\n async metaWired(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const result = await this.client.request<{ data: OmadaWiredNetwork[] }>(\n joinURL(\"/sites\", siteId, \"setting/lan/networks\"),\n );\n const networks = result?.data ?? [];\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wired/.meta\"), {\n meta: {\n kind: \"network:wired\",\n childrenCount: networks.length,\n },\n });\n }\n\n @Stat(\"/sites/:siteId/networks/wired\")\n async statWired(ctx: RouteContext<{ siteId: string }>): Promise<AFSStatResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const result = await this.client.request<{ data: OmadaWiredNetwork[] }>(\n joinURL(\"/sites\", siteId, \"setting/lan/networks\"),\n );\n const networks = result?.data ?? [];\n\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"networks/wired\"),\n path: joinURL(\"/sites\", siteId, \"networks/wired\"),\n meta: {\n kind: \"network:wired\",\n childrenCount: networks.length,\n },\n },\n };\n }\n\n @Read(\"/sites/:siteId/networks/wired/:networkId\")\n async readWiredNetwork(\n ctx: RouteContext<{ siteId: string; networkId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, networkId } = ctx.params;\n await this.validateSite(siteId);\n const net = await this.getWiredNetwork(siteId, networkId);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wired\", networkId), {\n id: networkId,\n content: this.formatWiredNetworkContent(net),\n meta: {\n kind: \"network:vlan\",\n name: net.name,\n vlanId: net.vlanId,\n subnet: net.subnet,\n childrenCount: 0,\n },\n });\n }\n\n @List(\"/sites/:siteId/networks/wired/:networkId\")\n async listWiredNetwork(\n ctx: RouteContext<{ siteId: string; networkId: string }>,\n ): Promise<AFSListResult> {\n const { siteId, networkId } = ctx.params;\n await this.validateSite(siteId);\n await this.getWiredNetwork(siteId, networkId);\n return { data: [] };\n }\n\n @Meta(\"/sites/:siteId/networks/wired/:networkId\")\n async metaWiredNetwork(\n ctx: RouteContext<{ siteId: string; networkId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, networkId } = ctx.params;\n await this.validateSite(siteId);\n const net = await this.getWiredNetwork(siteId, networkId);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wired\", networkId, \".meta\"), {\n meta: {\n kind: \"network:vlan\",\n name: net.name,\n childrenCount: 0,\n },\n });\n }\n\n @Stat(\"/sites/:siteId/networks/wired/:networkId\")\n async statWiredNetwork(\n ctx: RouteContext<{ siteId: string; networkId: string }>,\n ): Promise<AFSStatResult> {\n const { siteId, networkId } = ctx.params;\n await this.validateSite(siteId);\n const net = await this.getWiredNetwork(siteId, networkId);\n\n return {\n data: {\n id: networkId,\n path: joinURL(\"/sites\", siteId, \"networks/wired\", networkId),\n meta: {\n kind: \"network:vlan\",\n name: net.name,\n childrenCount: 0,\n },\n },\n };\n }\n\n @Write(\"/sites/:siteId/networks/wired/:networkId\")\n async writeWiredNetwork(\n ctx: RouteContext<{ siteId: string; networkId: string }>,\n payload: AFSWriteEntryPayload,\n ): Promise<AFSWriteResult> {\n const { siteId, networkId } = ctx.params;\n await this.validateSite(siteId);\n await this.getWiredNetwork(siteId, networkId);\n\n const raw = parseWritePayload(payload);\n const config = wiredNetworkWriteSchema.parse(raw);\n\n await this.client.patch(joinURL(\"/sites\", siteId, \"setting/lan/networks\", networkId), config);\n\n return {\n data: this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wired\", networkId), {\n content: JSON.stringify(config),\n meta: { kind: \"network:vlan\" },\n }),\n message: \"Wired network config updated\",\n };\n }\n\n // ========== WiFi Optimization handlers ==========\n\n @List(\"/sites/:siteId/networks/wifi-optimization\")\n async listWifiOptimization(ctx: RouteContext<{ siteId: string }>): Promise<AFSListResult> {\n await this.validateSite(ctx.params.siteId);\n return { data: [] };\n }\n\n @Read(\"/sites/:siteId/networks/wifi-optimization\")\n async readWifiOptimization(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const opt = await this.client.request<OmadaWifiOptimization>(\n joinURL(\"/sites\", siteId, \"setting/wlan/optimization\"),\n );\n\n const lines = [\n `Auto Channel: ${opt?.autoChannel ? \"enabled\" : \"disabled\"}`,\n `Roaming: ${opt?.roaming ? \"enabled\" : \"disabled\"}`,\n `Band Steering: ${opt?.bandSteering ? \"enabled\" : \"disabled\"}`,\n ];\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wifi-optimization\"), {\n content: lines.join(\"\\n\"),\n meta: {\n kind: \"network:wifi-optimization\",\n childrenCount: 0,\n },\n });\n }\n\n @Meta(\"/sites/:siteId/networks/wifi-optimization\")\n async metaWifiOptimization(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wifi-optimization/.meta\"), {\n meta: {\n kind: \"network:wifi-optimization\",\n childrenCount: 0,\n },\n });\n }\n\n @Stat(\"/sites/:siteId/networks/wifi-optimization\")\n async statWifiOptimization(ctx: RouteContext<{ siteId: string }>): Promise<AFSStatResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"networks/wifi-optimization\"),\n path: joinURL(\"/sites\", siteId, \"networks/wifi-optimization\"),\n meta: {\n kind: \"network:wifi-optimization\",\n childrenCount: 0,\n },\n },\n };\n }\n\n @Write(\"/sites/:siteId/networks/wifi-optimization\")\n async writeWifiOptimization(\n ctx: RouteContext<{ siteId: string }>,\n payload: AFSWriteEntryPayload,\n ): Promise<AFSWriteResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const raw = parseWritePayload(payload);\n const config = wifiOptimizationWriteSchema.parse(raw);\n\n await this.client.patch(joinURL(\"/sites\", siteId, \"setting/wlan/optimization\"), config);\n\n return {\n data: this.buildEntry(joinURL(\"/sites\", siteId, \"networks/wifi-optimization\"), {\n content: JSON.stringify(config),\n meta: { kind: \"network:wifi-optimization\" },\n }),\n message: \"WiFi optimization config updated\",\n };\n }\n\n // ========== VPN handlers ==========\n\n @List(\"/sites/:siteId/vpn\")\n async listVpn(ctx: RouteContext<{ siteId: string }>): Promise<AFSListResult> {\n await this.validateSite(ctx.params.siteId);\n return { data: [] };\n }\n\n @Read(\"/sites/:siteId/vpn\")\n async readVpn(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const vpn = await this.client.request<{\n ipsec: { enabled: boolean };\n l2tp: { enabled: boolean };\n wireguard: { enabled: boolean };\n }>(joinURL(\"/sites\", siteId, \"setting/vpn\"));\n\n const lines = [\n `IPsec: ${vpn?.ipsec?.enabled ? \"enabled\" : \"disabled\"}`,\n `L2TP: ${vpn?.l2tp?.enabled ? \"enabled\" : \"disabled\"}`,\n `WireGuard: ${vpn?.wireguard?.enabled ? \"enabled\" : \"disabled\"}`,\n ];\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"vpn\"), {\n content: lines.join(\"\\n\"),\n meta: { kind: \"network:vpn\", childrenCount: 0 },\n });\n }\n\n @Meta(\"/sites/:siteId/vpn\")\n async metaVpn(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n return this.buildEntry(joinURL(\"/sites\", siteId, \"vpn/.meta\"), {\n meta: { kind: \"network:vpn\", childrenCount: 0 },\n });\n }\n\n @Stat(\"/sites/:siteId/vpn\")\n async statVpn(ctx: RouteContext<{ siteId: string }>): Promise<AFSStatResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"vpn\"),\n path: joinURL(\"/sites\", siteId, \"vpn\"),\n meta: { kind: \"network:vpn\", childrenCount: 0 },\n },\n };\n }\n\n // ========== Firewall handlers ==========\n\n @List(\"/sites/:siteId/firewall\")\n async listFirewall(ctx: RouteContext<{ siteId: string }>): Promise<AFSListResult> {\n await this.validateSite(ctx.params.siteId);\n return { data: [] };\n }\n\n @Read(\"/sites/:siteId/firewall\")\n async readFirewall(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const fw = await this.client.request<{ data: unknown[] }>(\n joinURL(\"/sites\", siteId, \"setting/firewall/acl\"),\n );\n const rules = fw?.data ?? [];\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"firewall\"), {\n content: `Firewall ACL rules: ${rules.length}`,\n meta: { kind: \"network:firewall\", childrenCount: 0, ruleCount: rules.length },\n });\n }\n\n @Meta(\"/sites/:siteId/firewall\")\n async metaFirewall(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n return this.buildEntry(joinURL(\"/sites\", siteId, \"firewall/.meta\"), {\n meta: { kind: \"network:firewall\", childrenCount: 0 },\n });\n }\n\n @Stat(\"/sites/:siteId/firewall\")\n async statFirewall(ctx: RouteContext<{ siteId: string }>): Promise<AFSStatResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"firewall\"),\n path: joinURL(\"/sites\", siteId, \"firewall\"),\n meta: { kind: \"network:firewall\", childrenCount: 0 },\n },\n };\n }\n\n // ========== Routing handlers ==========\n\n @List(\"/sites/:siteId/routing\")\n async listRouting(ctx: RouteContext<{ siteId: string }>): Promise<AFSListResult> {\n await this.validateSite(ctx.params.siteId);\n return { data: [] };\n }\n\n @Read(\"/sites/:siteId/routing\")\n async readRouting(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const routing = await this.client.request<{\n staticRoutes: unknown[];\n policyRoutes: unknown[];\n }>(joinURL(\"/sites\", siteId, \"setting/routing\"));\n\n const staticCount = routing?.staticRoutes?.length ?? 0;\n const policyCount = routing?.policyRoutes?.length ?? 0;\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"routing\"), {\n content: `Static routes: ${staticCount} | Policy routes: ${policyCount}`,\n meta: { kind: \"network:routing\", childrenCount: 0 },\n });\n }\n\n @Meta(\"/sites/:siteId/routing\")\n async metaRouting(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n return this.buildEntry(joinURL(\"/sites\", siteId, \"routing/.meta\"), {\n meta: { kind: \"network:routing\", childrenCount: 0 },\n });\n }\n\n @Stat(\"/sites/:siteId/routing\")\n async statRouting(ctx: RouteContext<{ siteId: string }>): Promise<AFSStatResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"routing\"),\n path: joinURL(\"/sites\", siteId, \"routing\"),\n meta: { kind: \"network:routing\", childrenCount: 0 },\n },\n };\n }\n\n // ========== NAT handlers ==========\n\n @List(\"/sites/:siteId/nat\")\n async listNat(ctx: RouteContext<{ siteId: string }>): Promise<AFSListResult> {\n await this.validateSite(ctx.params.siteId);\n return { data: [] };\n }\n\n @Read(\"/sites/:siteId/nat\")\n async readNat(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const nat = await this.client.request<{ data: unknown[] }>(\n joinURL(\"/sites\", siteId, \"setting/nat\"),\n );\n const rules = nat?.data ?? [];\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"nat\"), {\n content: `NAT rules: ${rules.length}`,\n meta: { kind: \"network:nat\", childrenCount: 0, ruleCount: rules.length },\n });\n }\n\n @Meta(\"/sites/:siteId/nat\")\n async metaNat(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n return this.buildEntry(joinURL(\"/sites\", siteId, \"nat/.meta\"), {\n meta: { kind: \"network:nat\", childrenCount: 0 },\n });\n }\n\n @Stat(\"/sites/:siteId/nat\")\n async statNat(ctx: RouteContext<{ siteId: string }>): Promise<AFSStatResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"nat\"),\n path: joinURL(\"/sites\", siteId, \"nat\"),\n meta: { kind: \"network:nat\", childrenCount: 0 },\n },\n };\n }\n\n // ========== Logs handlers ==========\n\n @List(\"/sites/:siteId/logs\")\n async listLogs(ctx: RouteContext<{ siteId: string }>): Promise<AFSListResult> {\n await this.validateSite(ctx.params.siteId);\n return { data: [] };\n }\n\n @Read(\"/sites/:siteId/logs\")\n async readLogs(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n\n const logs = await this.client.request<{\n data: Array<{ timestamp: number; level: string; message: string }>;\n }>(joinURL(\"/sites\", siteId, \"logs\"));\n const entries = logs?.data ?? [];\n\n const content = entries\n .map((e) => `[${new Date(e.timestamp).toISOString()}] ${e.level}: ${e.message}`)\n .join(\"\\n\");\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"logs\"), {\n content: content || \"No log entries\",\n meta: { kind: \"network:logs\", childrenCount: 0, entryCount: entries.length },\n });\n }\n\n @Meta(\"/sites/:siteId/logs\")\n async metaLogs(ctx: RouteContext<{ siteId: string }>): Promise<AFSEntry | undefined> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n return this.buildEntry(joinURL(\"/sites\", siteId, \"logs/.meta\"), {\n meta: { kind: \"network:logs\", childrenCount: 0 },\n });\n }\n\n @Stat(\"/sites/:siteId/logs\")\n async statLogs(ctx: RouteContext<{ siteId: string }>): Promise<AFSStatResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"logs\"),\n path: joinURL(\"/sites\", siteId, \"logs\"),\n meta: { kind: \"network:logs\", childrenCount: 0 },\n },\n };\n }\n\n // ========== Switch port handlers ==========\n\n @Read(\"/sites/:siteId/devices/switches/:mac/ports\")\n async readSwitchPorts(\n ctx: RouteContext<{ siteId: string; mac: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, mac } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, \"switches\", normalizedMac);\n\n const ports = await this.getSwitchPorts(siteId, normalizedMac);\n\n return this.buildEntry(joinURL(\"/sites\", siteId, \"devices/switches\", normalizedMac, \"ports\"), {\n content: ports.map((p) => `Port ${p.port}: ${p.name} (${p.linkSpeed})`).join(\"\\n\"),\n meta: {\n kind: \"network:port-group\",\n childrenCount: ports.length,\n },\n });\n }\n\n @Meta(\"/sites/:siteId/devices/switches/:mac/ports\")\n async metaSwitchPorts(\n ctx: RouteContext<{ siteId: string; mac: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, mac } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, \"switches\", normalizedMac);\n\n const ports = await this.getSwitchPorts(siteId, normalizedMac);\n\n return this.buildEntry(\n joinURL(\"/sites\", siteId, \"devices/switches\", normalizedMac, \"ports/.meta\"),\n {\n meta: {\n kind: \"network:port-group\",\n childrenCount: ports.length,\n },\n },\n );\n }\n\n @Stat(\"/sites/:siteId/devices/switches/:mac/ports\")\n async statSwitchPorts(\n ctx: RouteContext<{ siteId: string; mac: string }>,\n ): Promise<AFSStatResult> {\n const { siteId, mac } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, \"switches\", normalizedMac);\n\n const ports = await this.getSwitchPorts(siteId, normalizedMac);\n\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"devices/switches\", normalizedMac, \"ports\"),\n path: joinURL(\"/sites\", siteId, \"devices/switches\", normalizedMac, \"ports\"),\n meta: {\n kind: \"network:port-group\",\n childrenCount: ports.length,\n },\n },\n };\n }\n\n @List(\"/sites/:siteId/devices/switches/:mac/ports\")\n async listSwitchPorts(\n ctx: RouteContext<{ siteId: string; mac: string }>,\n ): Promise<AFSListResult> {\n const { siteId, mac } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, \"switches\", normalizedMac);\n\n const ports = await this.getSwitchPorts(siteId, normalizedMac);\n\n return {\n data: ports.map((port) =>\n this.buildEntry(\n joinURL(\"/sites\", siteId, \"devices/switches\", normalizedMac, \"ports\", String(port.port)),\n {\n id: String(port.port),\n content: this.formatPortContent(port),\n meta: {\n kind: \"network:port\",\n port: port.port,\n childrenCount: 0,\n linkSpeed: port.linkSpeed,\n poeEnabled: port.poeEnabled,\n vlanId: port.vlanId,\n },\n },\n ),\n ),\n };\n }\n\n @List(\"/sites/:siteId/devices/:category/:mac/ports\")\n async listNonSwitchPorts(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n ): Promise<AFSListResult> {\n const { category } = ctx.params;\n if (category === \"switches\") {\n // Should not reach here, handled by the specific route above\n return { data: [] };\n }\n throw new AFSNotFoundError(`Ports are only available on switches, not ${category}`);\n }\n\n @Read(\"/sites/:siteId/devices/switches/:mac/ports/:portId\")\n async readSwitchPort(\n ctx: RouteContext<{ siteId: string; mac: string; portId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, mac, portId } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, \"switches\", normalizedMac);\n\n const port = await this.getSwitchPort(siteId, normalizedMac, validatePortId(portId));\n\n return this.buildEntry(\n joinURL(\"/sites\", siteId, \"devices/switches\", normalizedMac, \"ports\", portId),\n {\n id: portId,\n content: this.formatPortContent(port),\n meta: {\n kind: \"network:port\",\n port: port.port,\n childrenCount: 0,\n linkSpeed: port.linkSpeed,\n poeEnabled: port.poeEnabled,\n vlanId: port.vlanId,\n },\n },\n );\n }\n\n @List(\"/sites/:siteId/devices/switches/:mac/ports/:portId\")\n async listSwitchPort(\n ctx: RouteContext<{ siteId: string; mac: string; portId: string }>,\n ): Promise<AFSListResult> {\n const { siteId, mac, portId } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n await this.getSwitchPort(siteId, normalizedMac, validatePortId(portId));\n return { data: [] };\n }\n\n @Meta(\"/sites/:siteId/devices/switches/:mac/ports/:portId\")\n async metaSwitchPort(\n ctx: RouteContext<{ siteId: string; mac: string; portId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, mac, portId } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n const port = await this.getSwitchPort(siteId, normalizedMac, validatePortId(portId));\n\n return this.buildEntry(\n joinURL(\"/sites\", siteId, \"devices/switches\", normalizedMac, \"ports\", portId, \".meta\"),\n {\n meta: {\n kind: \"network:port\",\n port: port.port,\n childrenCount: 0,\n },\n },\n );\n }\n\n @Stat(\"/sites/:siteId/devices/switches/:mac/ports/:portId\")\n async statSwitchPort(\n ctx: RouteContext<{ siteId: string; mac: string; portId: string }>,\n ): Promise<AFSStatResult> {\n const { siteId, mac, portId } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n const port = await this.getSwitchPort(siteId, normalizedMac, validatePortId(portId));\n\n return {\n data: {\n id: portId,\n path: joinURL(\"/sites\", siteId, \"devices/switches\", normalizedMac, \"ports\", portId),\n meta: {\n kind: \"network:port\",\n port: port.port,\n childrenCount: 0,\n },\n },\n };\n }\n\n @Read(\"/sites/:siteId/devices/switches/:mac/ports/:portId/config\")\n async readSwitchPortConfig(\n ctx: RouteContext<{ siteId: string; mac: string; portId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, mac, portId } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n const port = await this.getSwitchPort(siteId, normalizedMac, validatePortId(portId));\n\n const config = {\n enable: port.enable,\n poeEnabled: port.poeEnabled,\n vlanId: port.vlanId,\n profileName: port.profileName,\n };\n\n return this.buildEntry(\n joinURL(\"/sites\", siteId, \"devices/switches\", normalizedMac, \"ports\", portId, \"config\"),\n {\n content: JSON.stringify(config),\n meta: { kind: \"network:port-config\" },\n },\n );\n }\n\n @Write(\"/sites/:siteId/devices/switches/:mac/ports/:portId/config\")\n async writeSwitchPortConfig(\n ctx: RouteContext<{ siteId: string; mac: string; portId: string }>,\n payload: AFSWriteEntryPayload,\n ): Promise<AFSWriteResult> {\n const { siteId, mac, portId } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n await this.getSwitchPort(siteId, normalizedMac, validatePortId(portId));\n\n const raw = parseWritePayload(payload);\n const config = portConfigWriteSchema.parse(raw);\n\n await this.client.patch(\n joinURL(\"/sites\", siteId, \"devices\", normalizedMac, \"ports\", portId),\n config,\n );\n\n return {\n data: this.buildEntry(\n joinURL(\"/sites\", siteId, \"devices/switches\", normalizedMac, \"ports\", portId, \"config\"),\n {\n content: JSON.stringify(config),\n meta: { kind: \"network:port-config\" },\n },\n ),\n message: \"Port config updated\",\n };\n }\n\n // ========== Firmware handlers ==========\n\n @List(\"/sites/:siteId/devices/:category/:mac/firmware\")\n async listFirmware(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n ): Promise<AFSListResult> {\n const { siteId, category, mac } = ctx.params;\n this.validateDeviceCategory(category);\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, category, normalizedMac);\n return { data: [] };\n }\n\n @Read(\"/sites/:siteId/devices/:category/:mac/firmware\")\n async readFirmware(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, category, mac } = ctx.params;\n this.validateDeviceCategory(category);\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, category, normalizedMac);\n\n const fw = await this.client.request<OmadaFirmwareInfo>(\n joinURL(\"/sites\", siteId, \"devices\", normalizedMac, \"firmware\"),\n );\n\n const lines = [\n `Current: ${fw?.currentVersion ?? \"unknown\"}`,\n `Latest: ${fw?.latestVersion ?? \"unknown\"}`,\n `Update available: ${fw?.hasUpdate ? \"yes\" : \"no\"}`,\n ];\n\n return this.buildEntry(\n joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac, \"firmware\"),\n {\n content: lines.join(\"\\n\"),\n meta: {\n kind: \"network:firmware\",\n childrenCount: 0,\n currentVersion: fw?.currentVersion,\n latestVersion: fw?.latestVersion,\n hasUpdate: fw?.hasUpdate ?? false,\n },\n },\n );\n }\n\n @Meta(\"/sites/:siteId/devices/:category/:mac/firmware\")\n async metaFirmware(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, category, mac } = ctx.params;\n this.validateDeviceCategory(category);\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, category, normalizedMac);\n\n return this.buildEntry(\n joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac, \"firmware/.meta\"),\n {\n meta: { kind: \"network:firmware\", childrenCount: 0 },\n },\n );\n }\n\n @Stat(\"/sites/:siteId/devices/:category/:mac/firmware\")\n async statFirmware(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n ): Promise<AFSStatResult> {\n const { siteId, category, mac } = ctx.params;\n this.validateDeviceCategory(category);\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, category, normalizedMac);\n\n return {\n data: {\n id: joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac, \"firmware\"),\n path: joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac, \"firmware\"),\n meta: { kind: \"network:firmware\", childrenCount: 0 },\n },\n };\n }\n\n // ========== Explain handlers ==========\n\n @Explain(\"/\")\n async explainRoot(_ctx: RouteContext): Promise<AFSExplainResult> {\n // Get sites for the controller summary\n const result = await this.client.request<{ data: OmadaSite[] }>(\"/sites\");\n const sites = result?.data ?? [];\n\n let totalDevices = 0;\n for (const site of sites) {\n try {\n const dashboard = await this.client.request<OmadaDashboard>(\n joinURL(\"/sites\", site.siteId, \"dashboard\"),\n );\n totalDevices += dashboard?.totalDevices ?? 0;\n } catch {\n // Skip sites with inaccessible dashboards\n }\n }\n\n const lines = [\n \"# Omada SDN Controller\",\n \"\",\n `**Sites:** ${sites.length}`,\n `**Total Devices:** ${totalDevices}`,\n \"\",\n \"## Sites\",\n \"\",\n ...sites.map((s) => `- **${s.name}** (${s.siteId})`),\n ];\n\n return { content: lines.join(\"\\n\"), format: \"markdown\" };\n }\n\n @Explain(\"/sites/:siteId\")\n async explainSite(ctx: RouteContext<{ siteId: string }>): Promise<AFSExplainResult> {\n const { siteId } = ctx.params;\n const site = await this.getSite(siteId);\n\n const dashboard = await this.client.request<OmadaDashboard>(\n joinURL(\"/sites\", siteId, \"dashboard\"),\n );\n\n const clientResult = await this.client.request<{ data: OmadaClient[] }>(\n joinURL(\"/sites\", siteId, \"clients\"),\n );\n const clientCount = clientResult?.data?.length ?? 0;\n\n const lines = [\n `# ${site.name}`,\n \"\",\n `**Site ID:** ${siteId}`,\n `**Devices:** ${dashboard?.totalDevices ?? 0} (${dashboard?.connectedDevices ?? 0} connected)`,\n `**Clients:** ${clientCount}`,\n `**Gateways:** ${dashboard?.gatewayNum ?? 0}`,\n `**Switches:** ${dashboard?.switchNum ?? 0}`,\n `**APs:** ${dashboard?.apNum ?? 0}`,\n ];\n\n return { content: lines.join(\"\\n\"), format: \"markdown\" };\n }\n\n @Explain(\"/sites/:siteId/devices\")\n @Explain(\"/sites/:siteId/devices/:category\")\n @Explain(\"/sites/:siteId/devices/:category/:mac\")\n @Explain(\"/sites/:siteId/devices/:category/:mac/ports\")\n @Explain(\"/sites/:siteId/devices/:category/:mac/ports/:portId\")\n @Explain(\"/sites/:siteId/devices/:category/:mac/firmware\")\n @Explain(\"/sites/:siteId/clients\")\n @Explain(\"/sites/:siteId/clients/:mac\")\n @Explain(\"/sites/:siteId/dashboard\")\n @Explain(\"/sites/:siteId/networks\")\n @Explain(\"/sites/:siteId/networks/wireless\")\n @Explain(\"/sites/:siteId/networks/wireless/:ssidId\")\n @Explain(\"/sites/:siteId/networks/wired\")\n @Explain(\"/sites/:siteId/networks/wired/:networkId\")\n @Explain(\"/sites/:siteId/networks/wifi-optimization\")\n @Explain(\"/sites/:siteId/vpn\")\n @Explain(\"/sites/:siteId/firewall\")\n @Explain(\"/sites/:siteId/routing\")\n @Explain(\"/sites/:siteId/nat\")\n @Explain(\"/sites/:siteId/logs\")\n async explainSiteChild(ctx: RouteContext<{ siteId: string }>): Promise<AFSExplainResult> {\n const { siteId } = ctx.params;\n await this.validateSite(siteId);\n return {\n content: `Path: ${ctx.path}`,\n format: \"text\",\n };\n }\n\n // ========== Search handler ==========\n\n @Search(\"/:path*\")\n async searchAll(\n ctx: RouteContext<{ path?: string }>,\n query: string,\n options?: AFSSearchOptions,\n ): Promise<{ data: AFSEntry[]; message?: string }> {\n const basePath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const searchQuery = query.toLowerCase();\n const limit = options?.limit ?? 100;\n const results: AFSEntry[] = [];\n\n // Determine which sites to search\n let sitesToSearch: OmadaSite[] = [];\n const siteResult = await this.client.request<{ data: OmadaSite[] }>(\"/sites\");\n const allSites = siteResult?.data ?? [];\n\n const siteMatch = basePath.match(/^\\/sites\\/([^/]+)/);\n if (siteMatch) {\n const matchedSite = allSites.find((s) => s.siteId === siteMatch[1]);\n if (!matchedSite) throw new AFSNotFoundError(basePath);\n sitesToSearch = [matchedSite];\n } else {\n sitesToSearch = allSites;\n }\n\n for (const site of sitesToSearch) {\n if (results.length >= limit) break;\n\n // Search devices\n const devices = await this.getAllDevices(site.siteId);\n for (const device of devices) {\n if (results.length >= limit) break;\n\n const mac = normalizeMac(device.mac);\n const category = DEVICE_TYPE_MAP[device.type] || \"unknown\";\n const searchableContent = [device.name, device.model, mac, device.firmwareVersion]\n .join(\" \")\n .toLowerCase();\n\n if (searchableContent.includes(searchQuery)) {\n results.push(\n this.buildEntry(joinURL(\"/sites\", site.siteId, \"devices\", category, mac), {\n id: mac,\n content: this.formatDeviceContent(device, category),\n meta: {\n kind: DEVICE_KIND_MAP[category],\n childrenCount: 0,\n model: device.model,\n status: mapDeviceStatus(device.status),\n firmware: device.firmwareVersion,\n },\n }),\n );\n }\n }\n\n // Search clients\n const clientResult = await this.client.request<{ data: OmadaClient[] }>(\n joinURL(\"/sites\", site.siteId, \"clients\"),\n );\n const clients = clientResult?.data ?? [];\n\n for (const c of clients) {\n if (results.length >= limit) break;\n\n const mac = normalizeMac(c.mac);\n const searchableContent = [c.name, c.ip, mac, c.ssid].join(\" \").toLowerCase();\n\n if (searchableContent.includes(searchQuery)) {\n results.push(\n this.buildEntry(joinURL(\"/sites\", site.siteId, \"clients\", mac), {\n id: mac,\n content: this.formatClientContent(c),\n meta: {\n kind: \"network:client\",\n childrenCount: 0,\n ip: c.ip,\n ssid: c.ssid,\n },\n }),\n );\n }\n }\n }\n\n return { data: results };\n }\n\n // ========== Actions handlers ==========\n\n @Actions(\"/\")\n async listRootActions(_ctx: RouteContext): Promise<AFSListResult> {\n return {\n data: [\n this.buildEntry(\"/.actions/create-site\", {\n id: \"create-site\",\n meta: {\n kind: \"network:action\",\n name: \"create-site\",\n severity: \"boundary\",\n description: \"Create a new site on the Omada controller\",\n },\n }),\n ],\n };\n }\n\n @Actions.Exec(\"/\", \"create-site\")\n async execCreateSite(_ctx: RouteContext, args: Record<string, unknown>): Promise<AFSExecResult> {\n const name = args.name as string | undefined;\n if (!name) {\n throw new Error(\"create-site requires 'name' argument\");\n }\n const region = (args.region as string) || \"default\";\n\n const result = await this.client.post<{ siteId: string; name: string }>(\"/sites\", {\n name,\n region,\n });\n\n return {\n success: true,\n data: { siteId: result.siteId, name: result.name },\n };\n }\n\n @Actions(\"/sites/:siteId/devices/:category/:mac\")\n async listDeviceActions(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n ): Promise<AFSListResult> {\n const { siteId, category, mac } = ctx.params;\n this.validateDeviceCategory(category);\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, category, normalizedMac);\n\n const basePath = joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac);\n return {\n data: [\n this.buildEntry(joinURL(basePath, \".actions/reboot\"), {\n id: \"reboot\",\n meta: {\n kind: \"network:action\",\n name: \"reboot\",\n severity: \"boundary\",\n description: \"Reboot this device\",\n },\n }),\n this.buildEntry(joinURL(basePath, \".actions/upgrade-firmware\"), {\n id: \"upgrade-firmware\",\n meta: {\n kind: \"network:action\",\n name: \"upgrade-firmware\",\n severity: \"critical\",\n description: \"Upgrade this device's firmware to latest version\",\n },\n }),\n ],\n };\n }\n\n @Actions.Exec(\"/sites/:siteId/devices/:category/:mac\", \"reboot\")\n async execDeviceReboot(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n ): Promise<AFSExecResult> {\n const { siteId, category, mac } = ctx.params;\n this.validateDeviceCategory(category);\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, category, normalizedMac);\n\n await this.client.post(joinURL(\"/sites\", siteId, \"cmd/devices\", normalizedMac, \"reboot\"));\n\n this.emit({\n type: \"omada:device_reboot\",\n path: joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac),\n data: { mac: normalizedMac, siteId },\n });\n\n return { success: true, data: { mac: normalizedMac, action: \"reboot\" } };\n }\n\n @Actions.Exec(\"/sites/:siteId/devices/:category/:mac\", \"upgrade-firmware\")\n async execDeviceUpgradeFirmware(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n ): Promise<AFSExecResult> {\n const { siteId, category, mac } = ctx.params;\n this.validateDeviceCategory(category);\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, category, normalizedMac);\n\n await this.client.post(joinURL(\"/sites\", siteId, \"cmd/devices\", normalizedMac, \"upgrade\"));\n\n this.emit({\n type: \"omada:firmware_upgrade\",\n path: joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac),\n data: { mac: normalizedMac, siteId },\n });\n\n return { success: true, data: { mac: normalizedMac, action: \"upgrade-firmware\" } };\n }\n\n @Actions(\"/sites/:siteId/clients/:mac\")\n async listClientActions(\n ctx: RouteContext<{ siteId: string; mac: string }>,\n ): Promise<AFSListResult> {\n const { siteId, mac } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n await this.getClient(siteId, normalizedMac);\n\n const basePath = joinURL(\"/sites\", siteId, \"clients\", normalizedMac);\n return {\n data: [\n this.buildEntry(joinURL(basePath, \".actions/block\"), {\n id: \"block\",\n meta: {\n kind: \"network:action\",\n name: \"block\",\n severity: \"boundary\",\n description: \"Block this client\",\n },\n }),\n this.buildEntry(joinURL(basePath, \".actions/unblock\"), {\n id: \"unblock\",\n meta: {\n kind: \"network:action\",\n name: \"unblock\",\n severity: \"boundary\",\n description: \"Unblock this client\",\n },\n }),\n ],\n };\n }\n\n @Actions.Exec(\"/sites/:siteId/clients/:mac\", \"block\")\n async execClientBlock(\n ctx: RouteContext<{ siteId: string; mac: string }>,\n ): Promise<AFSExecResult> {\n const { siteId, mac } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n await this.getClient(siteId, normalizedMac);\n\n await this.client.post(joinURL(\"/sites\", siteId, \"cmd/clients\", normalizedMac, \"block\"));\n\n this.emit({\n type: \"omada:client_blocked\",\n path: joinURL(\"/sites\", siteId, \"clients\", normalizedMac),\n data: { mac: normalizedMac, siteId },\n });\n\n return { success: true, data: { mac: normalizedMac, action: \"block\" } };\n }\n\n @Actions.Exec(\"/sites/:siteId/clients/:mac\", \"unblock\")\n async execClientUnblock(\n ctx: RouteContext<{ siteId: string; mac: string }>,\n ): Promise<AFSExecResult> {\n const { siteId, mac } = ctx.params;\n const normalizedMac = normalizeMac(mac);\n await this.getClient(siteId, normalizedMac);\n\n await this.client.post(joinURL(\"/sites\", siteId, \"cmd/clients\", normalizedMac, \"unblock\"));\n\n this.emit({\n type: \"omada:client_unblocked\",\n path: joinURL(\"/sites\", siteId, \"clients\", normalizedMac),\n data: { mac: normalizedMac, siteId },\n });\n\n return { success: true, data: { mac: normalizedMac, action: \"unblock\" } };\n }\n\n // ========== Device config handlers ==========\n\n @Read(\"/sites/:siteId/devices/:category/:mac/config\")\n async readDeviceConfig(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n ): Promise<AFSEntry | undefined> {\n const { siteId, category, mac } = ctx.params;\n this.validateDeviceCategory(category);\n const normalizedMac = normalizeMac(mac);\n const device = await this.getDevice(siteId, category, normalizedMac);\n\n // Return the device's raw config representation\n const configData: Record<string, unknown> = {\n name: device.name,\n model: device.model,\n firmwareVersion: device.firmwareVersion,\n };\n\n return this.buildEntry(\n joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac, \"config\"),\n {\n content: JSON.stringify(configData),\n meta: { kind: \"network:config\" },\n },\n );\n }\n\n // ========== Write handlers ==========\n\n @Write(\"/sites/:siteId/devices/:category/:mac/config\")\n async writeDeviceConfig(\n ctx: RouteContext<{ siteId: string; category: string; mac: string }>,\n payload: AFSWriteEntryPayload,\n ): Promise<AFSWriteResult> {\n const { siteId, category, mac } = ctx.params;\n this.validateDeviceCategory(category);\n const normalizedMac = normalizeMac(mac);\n await this.getDevice(siteId, category, normalizedMac);\n\n const raw = parseWritePayload(payload);\n const config = deviceConfigWriteSchema.parse(raw);\n\n await this.client.patch(joinURL(\"/sites\", siteId, \"devices\", normalizedMac), config);\n\n this.emit({\n type: \"omada:device_config_updated\",\n path: joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac),\n data: { mac: normalizedMac, siteId, category },\n });\n\n return {\n data: this.buildEntry(\n joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac, \"config\"),\n {\n content: JSON.stringify(config),\n meta: { kind: \"network:config\" },\n },\n ),\n message: \"Device config updated\",\n };\n }\n\n // ========== Private helpers ==========\n\n private async getSite(siteId: string): Promise<OmadaSite> {\n validateIdParam(siteId, \"siteId\");\n const result = await this.client.request<{ data: OmadaSite[] }>(\"/sites\");\n const sites = result?.data ?? [];\n const site = sites.find((s) => s.siteId === siteId);\n if (!site) {\n throw new AFSNotFoundError(joinURL(\"/sites\", siteId));\n }\n return site;\n }\n\n private async validateSite(siteId: string): Promise<void> {\n await this.getSite(siteId);\n }\n\n private validateDeviceCategory(category: string): void {\n if (!VALID_DEVICE_CATEGORIES.includes(category)) {\n throw new AFSNotFoundError(\n `Invalid device category: ${category}. Valid: ${VALID_DEVICE_CATEGORIES.join(\", \")}`,\n );\n }\n }\n\n private async getAllDevices(siteId: string): Promise<OmadaDevice[]> {\n const result = await this.client.request<{ data: OmadaDevice[] }>(\n joinURL(\"/sites\", siteId, \"devices\"),\n );\n return result?.data ?? [];\n }\n\n private async getDevicesByCategory(siteId: string, category: string): Promise<OmadaDevice[]> {\n const devices = await this.getAllDevices(siteId);\n return devices.filter((d) => DEVICE_TYPE_MAP[d.type] === category);\n }\n\n private async getDevice(\n siteId: string,\n category: string,\n normalizedMac: string,\n ): Promise<OmadaDevice> {\n const devices = await this.getDevicesByCategory(siteId, category);\n const device = devices.find((d) => normalizeMac(d.mac) === normalizedMac);\n if (!device) {\n throw new AFSNotFoundError(joinURL(\"/sites\", siteId, \"devices\", category, normalizedMac));\n }\n return device;\n }\n\n private async getClient(siteId: string, normalizedMac: string): Promise<OmadaClient> {\n const result = await this.client.request<{ data: OmadaClient[] }>(\n joinURL(\"/sites\", siteId, \"clients\"),\n );\n const clients = result?.data ?? [];\n const client = clients.find((c) => normalizeMac(c.mac) === normalizedMac);\n if (!client) {\n throw new AFSNotFoundError(joinURL(\"/sites\", siteId, \"clients\", normalizedMac));\n }\n return client;\n }\n\n private formatDeviceContent(device: OmadaDevice, category: string): string {\n const status = mapDeviceStatus(device.status);\n const lines = [`${device.name} \\u2014 ${device.model} (${status})`];\n\n if (category === \"gateways\") {\n const cpu = device.cpuUtil ?? 0;\n const mem = device.memUtil ?? 0;\n const uptime = device.uptime ?? \"unknown\";\n lines.push(`CPU: ${cpu}% | Mem: ${mem}% | Uptime: ${uptime}`);\n } else if (category === \"switches\") {\n if (device.poeRemain !== undefined) {\n lines.push(`PoE remaining: ${device.poeRemain}W`);\n }\n } else if (category === \"aps\") {\n const parts: string[] = [];\n if (device.radioSetting2g) {\n parts.push(`2.4G: ch${device.radioSetting2g.channel} @${device.radioSetting2g.txPower}dBm`);\n }\n if (device.radioSetting5g) {\n parts.push(`5G: ch${device.radioSetting5g.channel} @${device.radioSetting5g.txPower}dBm`);\n }\n if (parts.length > 0) {\n lines.push(parts.join(\" | \"));\n }\n }\n\n return lines.join(\"\\n\");\n }\n\n private formatClientContent(client: OmadaClient): string {\n const lines = [`${client.name} \\u2014 ${client.ip}`];\n const parts: string[] = [];\n if (client.ssid) parts.push(`SSID: ${client.ssid}`);\n if (client.signalLevel !== undefined) parts.push(`Signal: ${client.signalLevel}dBm`);\n if (parts.length > 0) lines.push(parts.join(\" | \"));\n return lines.join(\"\\n\");\n }\n\n private async getSsid(siteId: string, ssidId: string): Promise<OmadaSsid> {\n validateIdParam(ssidId, \"ssidId\");\n const result = await this.client.request<{ data: OmadaSsid[] }>(\n joinURL(\"/sites\", siteId, \"setting/ssids\"),\n );\n const ssids = result?.data ?? [];\n const ssid = ssids.find((s) => s.id === ssidId);\n if (!ssid) {\n throw new AFSNotFoundError(joinURL(\"/sites\", siteId, \"networks/wireless\", ssidId));\n }\n return ssid;\n }\n\n private async getWiredNetwork(siteId: string, networkId: string): Promise<OmadaWiredNetwork> {\n validateIdParam(networkId, \"networkId\");\n const result = await this.client.request<{ data: OmadaWiredNetwork[] }>(\n joinURL(\"/sites\", siteId, \"setting/lan/networks\"),\n );\n const networks = result?.data ?? [];\n const net = networks.find((n) => n.id === networkId);\n if (!net) {\n throw new AFSNotFoundError(joinURL(\"/sites\", siteId, \"networks/wired\", networkId));\n }\n return net;\n }\n\n private mapBand(band: number): string {\n switch (band) {\n case 0:\n return \"2.4GHz\";\n case 1:\n return \"2.4GHz+5GHz\";\n case 2:\n return \"5GHz\";\n default:\n return `unknown(${band})`;\n }\n }\n\n private formatSsidContent(ssid: OmadaSsid): string {\n const lines = [\n `${ssid.name} \\u2014 ${this.mapBand(ssid.band)}`,\n `Security: ${ssid.security} | VLAN: ${ssid.vlanId} | Guest: ${ssid.guestNetwork ? \"yes\" : \"no\"}`,\n ];\n return lines.join(\"\\n\");\n }\n\n private deviceChildrenCount(category: string): number {\n // Switches have ports + firmware (2 children), others have firmware only (1 child)\n return category === \"switches\" ? 2 : 1;\n }\n\n private async getSwitchPorts(siteId: string, normalizedMac: string): Promise<OmadaSwitchPort[]> {\n const result = await this.client.request<{ data: OmadaSwitchPort[] }>(\n joinURL(\"/sites\", siteId, \"devices\", normalizedMac, \"ports\"),\n );\n return result?.data ?? [];\n }\n\n private async getSwitchPort(\n siteId: string,\n normalizedMac: string,\n portId: number,\n ): Promise<OmadaSwitchPort> {\n const ports = await this.getSwitchPorts(siteId, normalizedMac);\n const port = ports.find((p) => p.port === portId);\n if (!port) {\n throw new AFSNotFoundError(\n joinURL(\"/sites\", siteId, \"devices/switches\", normalizedMac, \"ports\", String(portId)),\n );\n }\n return port;\n }\n\n private formatPortContent(port: OmadaSwitchPort): string {\n const lines = [\n `${port.name} \\u2014 ${port.linkSpeed} (${port.duplex})`,\n `VLAN: ${port.vlanId} | PoE: ${port.poeEnabled ? `enabled (${port.poePower}W)` : \"disabled\"}`,\n ];\n return lines.join(\"\\n\");\n }\n\n private formatWiredNetworkContent(net: OmadaWiredNetwork): string {\n const lines = [\n `${net.name} \\u2014 VLAN ${net.vlanId}`,\n `Subnet: ${net.subnet} | Gateway: ${net.gateway} | DHCP: ${net.dhcpEnabled ? \"enabled\" : \"disabled\"}`,\n ];\n return lines.join(\"\\n\");\n }\n}\n\nconst _typeCheck: AFSModuleClass<AFSOmadaProvider, AFSOmadaOptionsInput> = AFSOmadaProvider;\n"],"mappings":"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"}
|
package/dist/types.cjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
let zod = require("zod");
|
|
2
|
+
|
|
3
|
+
//#region src/types.ts
|
|
4
|
+
/**
|
|
5
|
+
* Zod schema for AFSOmadaProvider configuration.
|
|
6
|
+
*
|
|
7
|
+
* Validates required fields, applies defaults, and marks sensitive credentials.
|
|
8
|
+
*/
|
|
9
|
+
const afsOmadaOptionsSchema = zod.z.object({
|
|
10
|
+
name: zod.z.string().default("omada"),
|
|
11
|
+
description: zod.z.string().optional(),
|
|
12
|
+
baseUrl: zod.z.string().url().refine((url) => /^https?:\/\//i.test(url), { message: "baseUrl must use http:// or https:// protocol" }),
|
|
13
|
+
omadacId: zod.z.string().regex(/^[\w-]+$/, "omadacId must be alphanumeric (with hyphens/underscores)").optional(),
|
|
14
|
+
clientId: zod.z.string().min(1),
|
|
15
|
+
clientSecret: zod.z.string().min(1),
|
|
16
|
+
cacheTtl: zod.z.number().default(60),
|
|
17
|
+
strictSsl: zod.z.boolean().default(true),
|
|
18
|
+
accessMode: zod.z.enum(["readonly", "readwrite"]).default("readonly")
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Omada device status code mapping.
|
|
22
|
+
* Status 14 = connected in Omada API.
|
|
23
|
+
*/
|
|
24
|
+
const DEVICE_STATUS_MAP = {
|
|
25
|
+
0: "disconnected",
|
|
26
|
+
1: "disconnected",
|
|
27
|
+
14: "connected",
|
|
28
|
+
4: "upgrading",
|
|
29
|
+
5: "provisioning",
|
|
30
|
+
6: "heartbeat-missed",
|
|
31
|
+
7: "isolated"
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Normalize a MAC address to lowercase colon-separated format.
|
|
35
|
+
* Handles: uppercase, dash-separated, no-separator formats.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* normalizeMac("AA:BB:CC:DD:EE:FF") // "aa:bb:cc:dd:ee:ff"
|
|
39
|
+
* normalizeMac("AA-BB-CC-DD-EE-FF") // "aa:bb:cc:dd:ee:ff"
|
|
40
|
+
* normalizeMac("AABBCCDDEEFF") // "aa:bb:cc:dd:ee:ff"
|
|
41
|
+
*/
|
|
42
|
+
function normalizeMac(mac) {
|
|
43
|
+
const clean = mac.replace(/[:-]/g, "").toLowerCase();
|
|
44
|
+
if (!/^[0-9a-f]{12}$/.test(clean)) throw new Error(`Invalid MAC address: ${mac}`);
|
|
45
|
+
const parts = [];
|
|
46
|
+
for (let i = 0; i < clean.length; i += 2) parts.push(clean.slice(i, i + 2));
|
|
47
|
+
return parts.join(":");
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Map Omada device status code to human-readable string.
|
|
51
|
+
*/
|
|
52
|
+
function mapDeviceStatus(statusCode) {
|
|
53
|
+
return DEVICE_STATUS_MAP[statusCode] ?? `unknown(${statusCode})`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
exports.afsOmadaOptionsSchema = afsOmadaOptionsSchema;
|
|
58
|
+
exports.mapDeviceStatus = mapDeviceStatus;
|
|
59
|
+
exports.normalizeMac = normalizeMac;
|
package/dist/types.d.cts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Zod schema for AFSOmadaProvider configuration.
|
|
6
|
+
*
|
|
7
|
+
* Validates required fields, applies defaults, and marks sensitive credentials.
|
|
8
|
+
*/
|
|
9
|
+
declare const afsOmadaOptionsSchema: z.ZodObject<{
|
|
10
|
+
name: z.ZodDefault<z.ZodString>;
|
|
11
|
+
description: z.ZodOptional<z.ZodString>;
|
|
12
|
+
baseUrl: z.ZodString;
|
|
13
|
+
omadacId: z.ZodOptional<z.ZodString>;
|
|
14
|
+
clientId: z.ZodString;
|
|
15
|
+
clientSecret: z.ZodString;
|
|
16
|
+
cacheTtl: z.ZodDefault<z.ZodNumber>;
|
|
17
|
+
strictSsl: z.ZodDefault<z.ZodBoolean>;
|
|
18
|
+
accessMode: z.ZodDefault<z.ZodEnum<{
|
|
19
|
+
readonly: "readonly";
|
|
20
|
+
readwrite: "readwrite";
|
|
21
|
+
}>>;
|
|
22
|
+
}, z.core.$strip>;
|
|
23
|
+
/** Output type (after parsing with defaults applied) */
|
|
24
|
+
type AFSOmadaOptions = z.infer<typeof afsOmadaOptionsSchema>;
|
|
25
|
+
/** Input type (before parsing — optional fields with defaults are optional) */
|
|
26
|
+
type AFSOmadaOptionsInput = z.input<typeof afsOmadaOptionsSchema>;
|
|
27
|
+
/**
|
|
28
|
+
* Normalize a MAC address to lowercase colon-separated format.
|
|
29
|
+
* Handles: uppercase, dash-separated, no-separator formats.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* normalizeMac("AA:BB:CC:DD:EE:FF") // "aa:bb:cc:dd:ee:ff"
|
|
33
|
+
* normalizeMac("AA-BB-CC-DD-EE-FF") // "aa:bb:cc:dd:ee:ff"
|
|
34
|
+
* normalizeMac("AABBCCDDEEFF") // "aa:bb:cc:dd:ee:ff"
|
|
35
|
+
*/
|
|
36
|
+
declare function normalizeMac(mac: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Map Omada device status code to human-readable string.
|
|
39
|
+
*/
|
|
40
|
+
declare function mapDeviceStatus(statusCode: number): string;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { AFSOmadaOptions, AFSOmadaOptionsInput, afsOmadaOptionsSchema, mapDeviceStatus, normalizeMac };
|
|
43
|
+
//# sourceMappingURL=types.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;AAOA;;;cAAa,qBAAA,EAAqB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;KAqBtB,eAAA,GAAkB,CAAA,CAAE,KAAA,QAAa,qBAAA;;KAGjC,oBAAA,GAAuB,CAAA,CAAE,KAAA,QAAa,qBAAA;;;;;;;;;;iBAyBlC,YAAA,CAAa,GAAA;;;;iBAkBb,eAAA,CAAgB,UAAA"}
|
package/dist/types.d.mts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Zod schema for AFSOmadaProvider configuration.
|
|
6
|
+
*
|
|
7
|
+
* Validates required fields, applies defaults, and marks sensitive credentials.
|
|
8
|
+
*/
|
|
9
|
+
declare const afsOmadaOptionsSchema: z.ZodObject<{
|
|
10
|
+
name: z.ZodDefault<z.ZodString>;
|
|
11
|
+
description: z.ZodOptional<z.ZodString>;
|
|
12
|
+
baseUrl: z.ZodString;
|
|
13
|
+
omadacId: z.ZodOptional<z.ZodString>;
|
|
14
|
+
clientId: z.ZodString;
|
|
15
|
+
clientSecret: z.ZodString;
|
|
16
|
+
cacheTtl: z.ZodDefault<z.ZodNumber>;
|
|
17
|
+
strictSsl: z.ZodDefault<z.ZodBoolean>;
|
|
18
|
+
accessMode: z.ZodDefault<z.ZodEnum<{
|
|
19
|
+
readonly: "readonly";
|
|
20
|
+
readwrite: "readwrite";
|
|
21
|
+
}>>;
|
|
22
|
+
}, z.core.$strip>;
|
|
23
|
+
/** Output type (after parsing with defaults applied) */
|
|
24
|
+
type AFSOmadaOptions = z.infer<typeof afsOmadaOptionsSchema>;
|
|
25
|
+
/** Input type (before parsing — optional fields with defaults are optional) */
|
|
26
|
+
type AFSOmadaOptionsInput = z.input<typeof afsOmadaOptionsSchema>;
|
|
27
|
+
/**
|
|
28
|
+
* Normalize a MAC address to lowercase colon-separated format.
|
|
29
|
+
* Handles: uppercase, dash-separated, no-separator formats.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* normalizeMac("AA:BB:CC:DD:EE:FF") // "aa:bb:cc:dd:ee:ff"
|
|
33
|
+
* normalizeMac("AA-BB-CC-DD-EE-FF") // "aa:bb:cc:dd:ee:ff"
|
|
34
|
+
* normalizeMac("AABBCCDDEEFF") // "aa:bb:cc:dd:ee:ff"
|
|
35
|
+
*/
|
|
36
|
+
declare function normalizeMac(mac: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Map Omada device status code to human-readable string.
|
|
39
|
+
*/
|
|
40
|
+
declare function mapDeviceStatus(statusCode: number): string;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { AFSOmadaOptions, AFSOmadaOptionsInput, afsOmadaOptionsSchema, mapDeviceStatus, normalizeMac };
|
|
43
|
+
//# sourceMappingURL=types.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;AAOA;;;cAAa,qBAAA,EAAqB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;KAqBtB,eAAA,GAAkB,CAAA,CAAE,KAAA,QAAa,qBAAA;;KAGjC,oBAAA,GAAuB,CAAA,CAAE,KAAA,QAAa,qBAAA;;;;;;;;;;iBAyBlC,YAAA,CAAa,GAAA;;;;iBAkBb,eAAA,CAAgB,UAAA"}
|
package/dist/types.mjs
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/types.ts
|
|
4
|
+
/**
|
|
5
|
+
* Zod schema for AFSOmadaProvider configuration.
|
|
6
|
+
*
|
|
7
|
+
* Validates required fields, applies defaults, and marks sensitive credentials.
|
|
8
|
+
*/
|
|
9
|
+
const afsOmadaOptionsSchema = z.object({
|
|
10
|
+
name: z.string().default("omada"),
|
|
11
|
+
description: z.string().optional(),
|
|
12
|
+
baseUrl: z.string().url().refine((url) => /^https?:\/\//i.test(url), { message: "baseUrl must use http:// or https:// protocol" }),
|
|
13
|
+
omadacId: z.string().regex(/^[\w-]+$/, "omadacId must be alphanumeric (with hyphens/underscores)").optional(),
|
|
14
|
+
clientId: z.string().min(1),
|
|
15
|
+
clientSecret: z.string().min(1),
|
|
16
|
+
cacheTtl: z.number().default(60),
|
|
17
|
+
strictSsl: z.boolean().default(true),
|
|
18
|
+
accessMode: z.enum(["readonly", "readwrite"]).default("readonly")
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Omada device status code mapping.
|
|
22
|
+
* Status 14 = connected in Omada API.
|
|
23
|
+
*/
|
|
24
|
+
const DEVICE_STATUS_MAP = {
|
|
25
|
+
0: "disconnected",
|
|
26
|
+
1: "disconnected",
|
|
27
|
+
14: "connected",
|
|
28
|
+
4: "upgrading",
|
|
29
|
+
5: "provisioning",
|
|
30
|
+
6: "heartbeat-missed",
|
|
31
|
+
7: "isolated"
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Normalize a MAC address to lowercase colon-separated format.
|
|
35
|
+
* Handles: uppercase, dash-separated, no-separator formats.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* normalizeMac("AA:BB:CC:DD:EE:FF") // "aa:bb:cc:dd:ee:ff"
|
|
39
|
+
* normalizeMac("AA-BB-CC-DD-EE-FF") // "aa:bb:cc:dd:ee:ff"
|
|
40
|
+
* normalizeMac("AABBCCDDEEFF") // "aa:bb:cc:dd:ee:ff"
|
|
41
|
+
*/
|
|
42
|
+
function normalizeMac(mac) {
|
|
43
|
+
const clean = mac.replace(/[:-]/g, "").toLowerCase();
|
|
44
|
+
if (!/^[0-9a-f]{12}$/.test(clean)) throw new Error(`Invalid MAC address: ${mac}`);
|
|
45
|
+
const parts = [];
|
|
46
|
+
for (let i = 0; i < clean.length; i += 2) parts.push(clean.slice(i, i + 2));
|
|
47
|
+
return parts.join(":");
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Map Omada device status code to human-readable string.
|
|
51
|
+
*/
|
|
52
|
+
function mapDeviceStatus(statusCode) {
|
|
53
|
+
return DEVICE_STATUS_MAP[statusCode] ?? `unknown(${statusCode})`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
export { afsOmadaOptionsSchema, mapDeviceStatus, normalizeMac };
|
|
58
|
+
//# sourceMappingURL=types.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.mjs","names":[],"sources":["../src/types.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/**\n * Zod schema for AFSOmadaProvider configuration.\n *\n * Validates required fields, applies defaults, and marks sensitive credentials.\n */\nexport const afsOmadaOptionsSchema = z.object({\n name: z.string().default(\"omada\"),\n description: z.string().optional(),\n baseUrl: z\n .string()\n .url()\n .refine((url) => /^https?:\\/\\//i.test(url), {\n message: \"baseUrl must use http:// or https:// protocol\",\n }),\n omadacId: z\n .string()\n .regex(/^[\\w-]+$/, \"omadacId must be alphanumeric (with hyphens/underscores)\")\n .optional(),\n clientId: z.string().min(1),\n clientSecret: z.string().min(1),\n cacheTtl: z.number().default(60),\n strictSsl: z.boolean().default(true),\n accessMode: z.enum([\"readonly\", \"readwrite\"]).default(\"readonly\"),\n});\n\n/** Output type (after parsing with defaults applied) */\nexport type AFSOmadaOptions = z.infer<typeof afsOmadaOptionsSchema>;\n\n/** Input type (before parsing — optional fields with defaults are optional) */\nexport type AFSOmadaOptionsInput = z.input<typeof afsOmadaOptionsSchema>;\n\n/**\n * Omada device status code mapping.\n * Status 14 = connected in Omada API.\n */\nexport const DEVICE_STATUS_MAP: Record<number, string> = {\n 0: \"disconnected\",\n 1: \"disconnected\",\n 14: \"connected\",\n 4: \"upgrading\",\n 5: \"provisioning\",\n 6: \"heartbeat-missed\",\n 7: \"isolated\",\n};\n\n/**\n * Normalize a MAC address to lowercase colon-separated format.\n * Handles: uppercase, dash-separated, no-separator formats.\n *\n * @example\n * normalizeMac(\"AA:BB:CC:DD:EE:FF\") // \"aa:bb:cc:dd:ee:ff\"\n * normalizeMac(\"AA-BB-CC-DD-EE-FF\") // \"aa:bb:cc:dd:ee:ff\"\n * normalizeMac(\"AABBCCDDEEFF\") // \"aa:bb:cc:dd:ee:ff\"\n */\nexport function normalizeMac(mac: string): string {\n // Remove all separators and convert to lowercase\n const clean = mac.replace(/[:-]/g, \"\").toLowerCase();\n // Validate: must be exactly 12 hex characters\n if (!/^[0-9a-f]{12}$/.test(clean)) {\n throw new Error(`Invalid MAC address: ${mac}`);\n }\n // Insert colons every 2 characters\n const parts: string[] = [];\n for (let i = 0; i < clean.length; i += 2) {\n parts.push(clean.slice(i, i + 2));\n }\n return parts.join(\":\");\n}\n\n/**\n * Map Omada device status code to human-readable string.\n */\nexport function mapDeviceStatus(statusCode: number): string {\n return DEVICE_STATUS_MAP[statusCode] ?? `unknown(${statusCode})`;\n}\n\n/**\n * Sensitive field names that should not be exposed in serialization.\n */\nexport const SENSITIVE_FIELDS = [\"clientId\", \"clientSecret\"] as const;\n"],"mappings":";;;;;;;;AAOA,MAAa,wBAAwB,EAAE,OAAO;CAC5C,MAAM,EAAE,QAAQ,CAAC,QAAQ,QAAQ;CACjC,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,SAAS,EACN,QAAQ,CACR,KAAK,CACL,QAAQ,QAAQ,gBAAgB,KAAK,IAAI,EAAE,EAC1C,SAAS,iDACV,CAAC;CACJ,UAAU,EACP,QAAQ,CACR,MAAM,YAAY,2DAA2D,CAC7E,UAAU;CACb,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE;CAC3B,cAAc,EAAE,QAAQ,CAAC,IAAI,EAAE;CAC/B,UAAU,EAAE,QAAQ,CAAC,QAAQ,GAAG;CAChC,WAAW,EAAE,SAAS,CAAC,QAAQ,KAAK;CACpC,YAAY,EAAE,KAAK,CAAC,YAAY,YAAY,CAAC,CAAC,QAAQ,WAAW;CAClE,CAAC;;;;;AAYF,MAAa,oBAA4C;CACvD,GAAG;CACH,GAAG;CACH,IAAI;CACJ,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACJ;;;;;;;;;;AAWD,SAAgB,aAAa,KAAqB;CAEhD,MAAM,QAAQ,IAAI,QAAQ,SAAS,GAAG,CAAC,aAAa;AAEpD,KAAI,CAAC,iBAAiB,KAAK,MAAM,CAC/B,OAAM,IAAI,MAAM,wBAAwB,MAAM;CAGhD,MAAM,QAAkB,EAAE;AAC1B,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,EACrC,OAAM,KAAK,MAAM,MAAM,GAAG,IAAI,EAAE,CAAC;AAEnC,QAAO,MAAM,KAAK,IAAI;;;;;AAMxB,SAAgB,gBAAgB,YAA4B;AAC1D,QAAO,kBAAkB,eAAe,WAAW,WAAW"}
|