@aigne/afs-frigate 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/index.cjs +2333 -0
- package/dist/index.d.cts +288 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +288 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2332 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["params","events"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * AFSFrigate - AFS Provider for Frigate NVR\n *\n * Maps Frigate NVR into a virtual filesystem.\n * Phases:\n * - 0a: Core skeleton + conformance (cameras, events, dashboard, config)\n * - 0b (Phase 1): Full readonly (binary content, recordings, reviews, search, summaries)\n * - 0c (Phase 2): MQTT cache optimization (optional, graceful fallback)\n * - 1 (Phase 3): Event management + camera control (readwrite actions)\n * - 2 (Phase 4): Exports + semantic search + AI + PTZ\n * - 3 (Phase 5): Configuration management + logs + users + restart\n */\nimport {\n type ActionCatalog,\n type AFSAccessMode,\n type AFSEntry,\n type AFSEntryMetadata,\n type AFSExecResult,\n type AFSExplainResult,\n type AFSListResult,\n type AFSModuleClass,\n type AFSModuleLoadParams,\n AFSNotFoundError,\n type AFSSearchOptions,\n type AFSStatResult,\n type AFSWriteEntryPayload,\n type CapabilitiesManifest,\n type ProviderManifest,\n type ProviderTreeSchema,\n type SecurityProfile,\n} from \"@aigne/afs\";\nimport {\n Actions,\n AFSBaseProvider,\n Explain,\n List,\n Meta,\n Read,\n type RouteContext,\n Search,\n Stat,\n Write,\n} from \"@aigne/afs/provider\";\nimport { joinURL } from \"ufo\";\nimport { z } from \"zod\";\n\n// ============ Options Schema ============\n\nconst afsFrigateOptionsSchema = z.object({\n name: z.string().default(\"frigate\"),\n description: z.string().optional(),\n url: z.string(),\n username: z.string().optional(),\n password: z.string().optional(),\n mqttUrl: z.string().optional(),\n mqttTopicPrefix: z.string().default(\"frigate\"),\n cacheTtl: z.number().default(30),\n accessMode: z.enum([\"readonly\", \"readwrite\"]).default(\"readwrite\"),\n});\n\nexport interface AFSFrigateOptions {\n name?: string;\n description?: string;\n url: string;\n username?: string;\n password?: string;\n mqttUrl?: string;\n mqttTopicPrefix?: string;\n cacheTtl?: number;\n accessMode?: AFSAccessMode;\n}\n\n// ============ Frigate Types ============\n\ninterface FrigateConfig {\n cameras: Record<\n string,\n {\n detect?: { enabled?: boolean; width?: number; height?: number; fps?: number };\n record?: { enabled?: boolean };\n snapshots?: { enabled?: boolean };\n zones?: Record<string, unknown>;\n }\n >;\n}\n\ninterface FrigateEvent {\n id: string;\n camera: string;\n label: string;\n sub_label: string | null;\n top_score: number;\n score: number;\n zones: string[];\n start_time: number;\n end_time: number;\n has_clip: boolean;\n has_snapshot: boolean;\n thumbnail: string;\n description: string | null;\n retain_indefinitely?: boolean;\n}\n\ninterface FrigateStats {\n cpu_usages: Record<string, { cpu: string; mem: string }>;\n detectors: Record<string, { inference_speed: number; pid: number }>;\n service: { uptime: number; version: string };\n cameras: Record<string, { camera_fps: number; detection_fps: number; process_fps: number }>;\n}\n\ninterface FrigateReview {\n id: string;\n camera: string;\n start_time: number;\n end_time: number;\n severity: string;\n thumb_path: string;\n data: {\n detections: string[];\n objects: string[];\n sub_labels: string[];\n zones: string[];\n };\n has_been_reviewed: boolean;\n}\n\ninterface FrigateRecording {\n id: string;\n camera: string;\n start_time: number;\n end_time: number;\n duration: number;\n segment_size: number;\n motion: number;\n objects: number;\n}\n\ninterface FrigateExport {\n id: string;\n camera: string;\n name: string;\n date: number;\n in_progress: boolean;\n thumb_path: string;\n video_path: string;\n}\n\n// ============ Frigate HTTP Client ============\n\nclass FrigateHttpClient {\n private baseUrl: string;\n private headers: Record<string, string>;\n private cache = new Map<string, { data: unknown; expiresAt: number }>();\n private cacheTtl: number;\n private pendingRequests = new Map<string, Promise<unknown>>();\n\n constructor(options: { url: string; username?: string; password?: string; cacheTtl?: number }) {\n // Validate URL protocol\n const urlLower = options.url.toLowerCase();\n if (!urlLower.startsWith(\"http://\") && !urlLower.startsWith(\"https://\")) {\n throw new Error(\"Frigate URL must use http:// or https:// protocol\");\n }\n if (\n urlLower.startsWith(\"javascript:\") ||\n urlLower.startsWith(\"file:\") ||\n urlLower.startsWith(\"data:\")\n ) {\n throw new Error(\"Invalid URL protocol\");\n }\n\n this.baseUrl = options.url.replace(/\\/$/, \"\");\n this.cacheTtl = (options.cacheTtl ?? 30) * 1000;\n this.headers = {};\n\n if (options.username && options.password) {\n const credentials = btoa(`${options.username}:${options.password}`);\n this.headers.Authorization = `Basic ${credentials}`;\n }\n }\n\n getBaseUrl(): string {\n return this.baseUrl;\n }\n\n invalidateCache(prefix?: string): void {\n if (!prefix) {\n this.cache.clear();\n return;\n }\n for (const key of this.cache.keys()) {\n if (key.includes(prefix)) {\n this.cache.delete(key);\n }\n }\n }\n\n private async fetchJSON<T>(path: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(joinURL(this.baseUrl, path));\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n url.searchParams.set(key, value);\n }\n }\n\n const cacheKey = url.toString();\n\n // Check cache\n const cached = this.cache.get(cacheKey);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.data as T;\n }\n\n // Deduplicate in-flight requests\n const pending = this.pendingRequests.get(cacheKey);\n if (pending) {\n return pending as Promise<T>;\n }\n\n const requestPromise = (async () => {\n try {\n const response = await fetch(url.toString(), {\n headers: this.headers,\n signal: AbortSignal.timeout(10000),\n });\n\n if (response.status === 401 || response.status === 403) {\n throw new FrigateApiError(\"Authentication failed\", \"AFS_AUTH_FAILED\", response.status);\n }\n\n if (response.status === 404) {\n throw new FrigateApiError(\"Not found\", \"AFS_NOT_FOUND\", 404);\n }\n\n if (response.status >= 500) {\n throw new FrigateApiError(\"Upstream server error\", \"AFS_UPSTREAM_ERROR\", response.status);\n }\n\n if (!response.ok) {\n throw new FrigateApiError(\"Unexpected response\", \"AFS_UPSTREAM_ERROR\", response.status);\n }\n\n const data = (await response.json()) as T;\n\n // Cache the result\n this.cache.set(cacheKey, {\n data,\n expiresAt: Date.now() + this.cacheTtl,\n });\n\n return data;\n } catch (error) {\n if (error instanceof FrigateApiError) throw error;\n if (error instanceof TypeError || (error as any)?.code === \"ECONNREFUSED\") {\n throw new FrigateApiError(\"Connection failed\", \"AFS_CONNECTION_ERROR\", 0);\n }\n if ((error as any)?.name === \"TimeoutError\" || (error as any)?.name === \"AbortError\") {\n throw new FrigateApiError(\"Connection timed out\", \"AFS_CONNECTION_ERROR\", 0);\n }\n throw error;\n } finally {\n this.pendingRequests.delete(cacheKey);\n }\n })();\n\n this.pendingRequests.set(cacheKey, requestPromise);\n return requestPromise as Promise<T>;\n }\n\n private async fetchRaw(\n path: string,\n options?: { method?: string; body?: string | Record<string, unknown> },\n ): Promise<Response> {\n const url = joinURL(this.baseUrl, path);\n const method = options?.method ?? \"GET\";\n const fetchHeaders: Record<string, string> = { ...this.headers };\n\n let body: string | undefined;\n if (options?.body) {\n if (typeof options.body === \"string\") {\n body = options.body;\n fetchHeaders[\"Content-Type\"] = \"text/plain\";\n } else {\n body = JSON.stringify(options.body);\n fetchHeaders[\"Content-Type\"] = \"application/json\";\n }\n }\n\n try {\n const response = await fetch(url, {\n method,\n headers: fetchHeaders,\n body,\n signal: AbortSignal.timeout(10000),\n });\n\n if (response.status === 401 || response.status === 403) {\n throw new FrigateApiError(\"Authentication failed\", \"AFS_AUTH_FAILED\", response.status);\n }\n\n if (response.status === 404) {\n throw new FrigateApiError(\"Not found\", \"AFS_NOT_FOUND\", 404);\n }\n\n if (response.status >= 500) {\n throw new FrigateApiError(\"Upstream server error\", \"AFS_UPSTREAM_ERROR\", response.status);\n }\n\n if (!response.ok) {\n throw new FrigateApiError(\"Unexpected response\", \"AFS_UPSTREAM_ERROR\", response.status);\n }\n\n return response;\n } catch (error) {\n if (error instanceof FrigateApiError) throw error;\n if (error instanceof TypeError || (error as any)?.code === \"ECONNREFUSED\") {\n throw new FrigateApiError(\"Connection failed\", \"AFS_CONNECTION_ERROR\", 0);\n }\n if ((error as any)?.name === \"TimeoutError\" || (error as any)?.name === \"AbortError\") {\n throw new FrigateApiError(\"Connection timed out\", \"AFS_CONNECTION_ERROR\", 0);\n }\n throw error;\n }\n }\n\n async fetchBinary(path: string): Promise<ArrayBuffer> {\n const response = await this.fetchRaw(path);\n return response.arrayBuffer();\n }\n\n async fetchText(path: string): Promise<string> {\n const response = await this.fetchRaw(path);\n return response.text();\n }\n\n async postJSON<T = unknown>(path: string, body?: Record<string, unknown>): Promise<T> {\n const response = await this.fetchRaw(path, { method: \"POST\", body });\n return (await response.json()) as T;\n }\n\n async postText(path: string, body: string): Promise<unknown> {\n const response = await this.fetchRaw(path, { method: \"POST\", body });\n return response.json();\n }\n\n async putJSON<T = unknown>(path: string, body: Record<string, unknown>): Promise<T> {\n const response = await this.fetchRaw(path, { method: \"PUT\", body });\n return (await response.json()) as T;\n }\n\n async patchJSON<T = unknown>(path: string, body: Record<string, unknown>): Promise<T> {\n const response = await this.fetchRaw(path, { method: \"PATCH\", body });\n return (await response.json()) as T;\n }\n\n async deleteRequest<T = unknown>(path: string): Promise<T> {\n const response = await this.fetchRaw(path, { method: \"DELETE\" });\n return (await response.json()) as T;\n }\n\n // ============ Typed API Methods ============\n\n async getConfig(): Promise<FrigateConfig> {\n return this.fetchJSON<FrigateConfig>(\"/api/config\");\n }\n\n async getStats(): Promise<FrigateStats> {\n return this.fetchJSON<FrigateStats>(\"/api/stats\");\n }\n\n async getEvents(params?: Record<string, string>): Promise<FrigateEvent[]> {\n return this.fetchJSON<FrigateEvent[]>(\"/api/events\", params);\n }\n\n async getEvent(id: string): Promise<FrigateEvent> {\n return this.fetchJSON<FrigateEvent>(`/api/events/${id}`);\n }\n\n async getEventsSummary(): Promise<\n Array<{ camera: string; label: string; count: number; day: string }>\n > {\n return this.fetchJSON(\"/api/events/summary\");\n }\n\n async searchEvents(params?: Record<string, string>): Promise<FrigateEvent[]> {\n return this.fetchJSON<FrigateEvent[]>(\"/api/events/search\", params);\n }\n\n async getReviews(params?: Record<string, string>): Promise<FrigateReview[]> {\n return this.fetchJSON<FrigateReview[]>(\"/api/review\", params);\n }\n\n async getReview(id: string): Promise<FrigateReview> {\n return this.fetchJSON<FrigateReview>(`/api/review/${id}`);\n }\n\n async getReviewSummary(): Promise<unknown> {\n return this.fetchJSON(\"/api/review/summary\");\n }\n\n async getRecordings(camera: string): Promise<FrigateRecording[]> {\n return this.fetchJSON<FrigateRecording[]>(`/api/${camera}/recordings`);\n }\n\n async getRecordingsSummary(camera: string): Promise<unknown> {\n return this.fetchJSON(`/api/${camera}/recordings/summary`);\n }\n\n async getRecordingsStorage(): Promise<Record<string, unknown>> {\n return this.fetchJSON(\"/api/recordings/storage\");\n }\n\n async getExports(): Promise<FrigateExport[]> {\n return this.fetchJSON<FrigateExport[]>(\"/api/exports\");\n }\n\n async getExport(id: string): Promise<FrigateExport> {\n return this.fetchJSON<FrigateExport>(`/api/exports/${id}`);\n }\n\n async getUsers(): Promise<Array<{ username: string; role: string }>> {\n return this.fetchJSON(\"/api/users\");\n }\n\n async getPtzInfo(camera: string): Promise<{ features: string[]; presets: string[] }> {\n return this.fetchJSON<{ features: string[]; presets: string[] }>(`/api/${camera}/ptz/info`);\n }\n\n async getReviewActivitySummary(): Promise<{ summary: string }> {\n return this.fetchJSON<{ summary: string }>(\"/api/review/activity/summary\");\n }\n}\n\nclass FrigateApiError extends Error {\n readonly code: string;\n readonly statusCode: number;\n\n constructor(message: string, code: string, statusCode: number) {\n super(message);\n this.name = \"FrigateApiError\";\n this.code = code;\n this.statusCode = statusCode;\n }\n}\n\n// ============ Path Validation ============\n\nfunction isPathTraversal(segment: string): boolean {\n return segment.includes(\"..\") || segment.includes(\"./\") || segment.startsWith(\"/\");\n}\n\n// ============ MQTT Support (Phase 2 / Phase 0c) ============\n\ninterface MqttManager {\n connected: boolean;\n close(): void;\n}\n\nfunction createMqttManager(\n _mqttUrl: string,\n _topicPrefix: string,\n _onInvalidate: (topic: string) => void,\n): MqttManager | null {\n // MQTT is an optional optimization. If mqtt library is not available,\n // gracefully degrade to HTTP polling. The API surface does not change.\n // In test environments, MQTT is simulated via direct cache invalidation calls.\n try {\n // Dynamic import attempt — if mqtt package isn't installed, returns null\n // For now, we provide a stub that can be enhanced when mqtt is available\n return null;\n } catch {\n return null;\n }\n}\n\n// ============ Provider ============\n\nexport class AFSFrigate extends AFSBaseProvider {\n static securityProfiles(): Record<string, SecurityProfile> {\n return {\n admin: { actionPolicy: \"full\", sensitivity: \"full\" },\n user: {\n actionPolicy: \"standard\",\n blockedActions: [\"restart\", \"delete\"],\n sensitivity: \"redacted\",\n },\n guest: {\n actionPolicy: \"safe\",\n accessMode: \"readonly\",\n sensitivity: \"redacted\",\n },\n };\n }\n\n static schema() {\n return afsFrigateOptionsSchema;\n }\n\n static manifest(): ProviderManifest {\n return {\n name: \"frigate\",\n description: \"Frigate NVR — cameras, events, and recordings as filesystem\",\n uriTemplate: \"frigate://{host}\",\n category: \"iot\",\n schema: z.object({ host: z.string() }),\n tags: [\"frigate\", \"nvr\", \"camera\", \"security\", \"surveillance\"],\n capabilityTags: [\n \"read-only\",\n \"search\",\n \"auth:token\",\n \"remote\",\n \"http\",\n \"on-premise\",\n \"real-time\",\n ],\n security: {\n riskLevel: \"external\",\n resourceAccess: [\"internet\", \"local-network\"],\n dataSensitivity: [\"media\", \"personal-data\"],\n notes: [\n \"Accesses surveillance cameras and recordings — contains video of people and property\",\n ],\n },\n capabilities: {\n network: { egress: true },\n },\n };\n }\n\n static treeSchema(): ProviderTreeSchema {\n return {\n operations: [\"list\", \"read\", \"write\", \"search\", \"exec\", \"stat\", \"explain\"],\n tree: {\n \"/\": { kind: \"frigate:nvr\", actions: [\"restart\"], destructive: [\"restart\"] },\n \"/cameras\": { kind: \"afs:directory\", operations: [\"list\"] },\n \"/cameras/{camera}\": {\n kind: \"frigate:camera\",\n operations: [\"list\", \"read\", \"exec\"],\n actions: [\n \"detect-on\",\n \"detect-off\",\n \"recordings-on\",\n \"recordings-off\",\n \"snapshots-on\",\n \"snapshots-off\",\n \"motion-on\",\n \"motion-off\",\n \"create-event\",\n ],\n },\n \"/cameras/{camera}/events\": { kind: \"afs:directory\", operations: [\"list\"] },\n \"/cameras/{camera}/events/{eventId}\": {\n kind: \"frigate:detection-event\",\n operations: [\"read\"],\n },\n \"/cameras/{camera}/recordings\": { kind: \"afs:directory\", operations: [\"list\"] },\n \"/cameras/{camera}/reviews\": { kind: \"afs:directory\", operations: [\"list\"] },\n \"/events\": { kind: \"afs:directory\", operations: [\"list\", \"search\"] },\n \"/events/{eventId}\": {\n kind: \"frigate:detection-event\",\n operations: [\"read\", \"exec\", \"delete\"],\n actions: [\n \"retain\",\n \"unretain\",\n \"set-sub-label\",\n \"set-description\",\n \"regenerate-description\",\n ],\n destructive: [\"delete\"],\n },\n \"/reviews\": { kind: \"afs:directory\", operations: [\"list\", \"exec\"], actions: [\"summarize\"] },\n \"/reviews/{reviewId}\": {\n kind: \"frigate:review\",\n operations: [\"read\", \"exec\"],\n actions: [\"mark-viewed\", \"unmark-viewed\"],\n },\n \"/exports\": { kind: \"afs:directory\", operations: [\"list\", \"exec\"] },\n \"/exports/{exportId}\": {\n kind: \"frigate:export\",\n operations: [\"read\", \"exec\", \"delete\"],\n actions: [\"rename\"],\n destructive: [\"delete\"],\n },\n \"/dashboard\": { kind: \"frigate:dashboard\", operations: [\"read\"] },\n \"/config\": { kind: \"frigate:config\", operations: [\"read\", \"write\"] },\n \"/logs\": { kind: \"afs:directory\", operations: [\"list\"] },\n \"/users\": { kind: \"afs:directory\", operations: [\"list\"] },\n },\n auth: { type: \"custom\", env: [\"FRIGATE_URL\"] },\n bestFor: [\"NVR surveillance\", \"event detection\", \"camera monitoring\"],\n notFor: [\"file storage\", \"database queries\"],\n };\n }\n\n static async load({ config }: AFSModuleLoadParams = {}) {\n const valid = await AFSFrigate.schema().parseAsync(config);\n return new AFSFrigate(valid);\n }\n\n readonly name: string;\n readonly description?: string;\n readonly accessMode: AFSAccessMode;\n\n private client: FrigateHttpClient;\n private parsedOptions: z.infer<typeof afsFrigateOptionsSchema>;\n\n constructor(options: AFSFrigateOptions) {\n super();\n this.parsedOptions = afsFrigateOptionsSchema.parse(options);\n this.name = this.parsedOptions.name ?? \"frigate\";\n this.description = this.parsedOptions.description;\n this.accessMode = this.parsedOptions.accessMode ?? \"readwrite\";\n this.client = new FrigateHttpClient({\n url: this.parsedOptions.url,\n username: this.parsedOptions.username,\n password: this.parsedOptions.password,\n cacheTtl: this.parsedOptions.cacheTtl,\n });\n\n // Initialize MQTT if configured (Phase 0c) — manager kept alive by closure reference\n if (this.parsedOptions.mqttUrl) {\n createMqttManager(\n this.parsedOptions.mqttUrl,\n this.parsedOptions.mqttTopicPrefix ?? \"frigate\",\n (topic: string) => this.handleMqttInvalidation(topic),\n );\n }\n }\n\n private handleMqttInvalidation(topic: string): void {\n if (topic.includes(\"events\")) {\n this.client.invalidateCache(\"/api/events\");\n } else if (topic.includes(\"reviews\") || topic.includes(\"review\")) {\n this.client.invalidateCache(\"/api/review\");\n } else if (topic.includes(\"stats\")) {\n this.client.invalidateCache(\"/api/stats\");\n } else {\n this.client.invalidateCache(\"/api/config\");\n }\n }\n\n // ============ Meta Handlers ============\n\n @Meta(\"/cameras/:camera/events\")\n async readCameraEventsMeta(ctx: RouteContext<{ camera: string }>): Promise<AFSEntry | undefined> {\n return this.buildMetaForPath(joinURL(\"/cameras\", ctx.params.camera, \"events\"));\n }\n\n @Meta(\"/cameras/:camera\")\n async readCameraMeta(ctx: RouteContext<{ camera: string }>): Promise<AFSEntry | undefined> {\n return this.buildMetaForPath(joinURL(\"/cameras\", ctx.params.camera));\n }\n\n @Meta(\"/:path*\")\n async readMetaHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSEntry | undefined> {\n const nodePath = joinURL(\"/\", ctx.params.path ?? \"\");\n return this.buildMetaForPath(nodePath);\n }\n\n private async buildMetaForPath(nodePath: string): Promise<AFSEntry> {\n const metaPath = joinURL(nodePath, \".meta\");\n\n let meta: AFSEntryMetadata;\n try {\n const pathParam = nodePath === \"/\" ? undefined : nodePath.slice(1);\n const statResult = await this.statHandler({\n path: nodePath,\n params: { path: pathParam },\n options: {},\n });\n meta = (statResult.data?.meta ?? {}) as AFSEntryMetadata;\n } catch {\n throw new AFSNotFoundError(nodePath);\n }\n\n return {\n id: metaPath,\n path: metaPath,\n content: meta,\n meta,\n };\n }\n\n // ============ Capabilities ============\n\n @Read(\"/.meta/.capabilities\")\n async readCapabilities(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const operations = this.getOperationsDeclaration();\n const actions: ActionCatalog[] = [];\n\n if (this.accessMode === \"readwrite\") {\n actions.push(\n {\n kind: \"frigate:detection-event\",\n description: \"Event management actions\",\n catalog: [\n { name: \"retain\", description: \"Mark event for indefinite retention\" },\n { name: \"unretain\", description: \"Remove retention flag\" },\n { name: \"delete\", description: \"Delete event\" },\n {\n name: \"set-sub-label\",\n description: \"Set sub-label\",\n inputSchema: {\n type: \"object\",\n properties: { subLabel: { type: \"string\" } },\n required: [\"subLabel\"],\n },\n },\n {\n name: \"set-description\",\n description: \"Set description\",\n inputSchema: {\n type: \"object\",\n properties: { description: { type: \"string\" } },\n required: [\"description\"],\n },\n },\n { name: \"regenerate-description\", description: \"AI regenerate description\" },\n ],\n discovery: { pathTemplate: \"/events/:id/.actions\" },\n },\n {\n kind: \"frigate:camera\",\n description: \"Camera control actions\",\n catalog: [\n { name: \"detect-on\", description: \"Enable object detection\" },\n { name: \"detect-off\", description: \"Disable object detection\" },\n { name: \"recordings-on\", description: \"Enable recording\" },\n { name: \"recordings-off\", description: \"Disable recording\" },\n { name: \"snapshots-on\", description: \"Enable snapshots\" },\n { name: \"snapshots-off\", description: \"Disable snapshots\" },\n { name: \"motion-on\", description: \"Enable motion detection\" },\n { name: \"motion-off\", description: \"Disable motion detection\" },\n { name: \"create-event\", description: \"Create manual event\" },\n { name: \"export\", description: \"Export recording range\" },\n { name: \"ptz\", description: \"PTZ control\" },\n { name: \"notifications-on\", description: \"Enable notifications\" },\n { name: \"notifications-off\", description: \"Disable notifications\" },\n ],\n discovery: { pathTemplate: \"/cameras/:name/.actions\" },\n },\n {\n kind: \"frigate:review\",\n description: \"Review actions\",\n catalog: [\n { name: \"mark-viewed\", description: \"Mark review as viewed\" },\n { name: \"unmark-viewed\", description: \"Unmark review as viewed\" },\n ],\n discovery: { pathTemplate: \"/reviews/:id/.actions\" },\n },\n {\n kind: \"frigate:export\",\n description: \"Export actions\",\n catalog: [\n { name: \"delete\", description: \"Delete export\" },\n { name: \"rename\", description: \"Rename export\" },\n ],\n discovery: { pathTemplate: \"/exports/:id/.actions\" },\n },\n );\n }\n\n const manifest: CapabilitiesManifest = {\n schemaVersion: 1,\n provider: \"frigate\",\n description: \"Frigate NVR — cameras, events, and recordings as filesystem\",\n operations,\n tools: [],\n actions,\n };\n\n return {\n id: \"/.meta/.capabilities\",\n path: \"/.meta/.capabilities\",\n content: manifest,\n meta: { kind: \"afs:capabilities\" },\n };\n }\n\n // ============ Root ============\n\n @List(\"/\")\n async listRoot(_ctx: RouteContext): Promise<AFSListResult> {\n const config = await this.client.getConfig();\n const cameraCount = Object.keys(config.cameras).length;\n\n const children: AFSEntry[] = [\n this.buildEntry(\"/cameras\", {\n meta: { kind: \"afs:directory\", childrenCount: cameraCount, description: \"Frigate cameras\" },\n }),\n this.buildEntry(\"/events\", {\n meta: { kind: \"afs:directory\", childrenCount: -1, description: \"Detection events\" },\n }),\n this.buildEntry(\"/reviews\", {\n meta: { kind: \"afs:directory\", childrenCount: -1, description: \"Review segments\" },\n }),\n this.buildEntry(\"/exports\", {\n meta: { kind: \"afs:directory\", childrenCount: -1, description: \"Exported clips\" },\n }),\n this.buildEntry(\"/dashboard\", {\n meta: { kind: \"frigate:dashboard\", childrenCount: 0, description: \"System dashboard\" },\n }),\n this.buildEntry(\"/config\", {\n meta: { kind: \"frigate:config\", childrenCount: 0, description: \"Frigate configuration\" },\n }),\n this.buildEntry(\"/logs\", {\n meta: { kind: \"afs:directory\", childrenCount: 3, description: \"Service logs\" },\n }),\n this.buildEntry(\"/users\", {\n meta: { kind: \"afs:directory\", childrenCount: -1, description: \"User management\" },\n }),\n ];\n\n return { data: children };\n }\n\n @Read(\"/\")\n async readRoot(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n return this.buildEntry(\"/\", {\n content: \"Frigate NVR instance\",\n meta: {\n kind: \"frigate:nvr\",\n childrenCount: 8,\n description: \"Frigate NVR instance\",\n },\n });\n }\n\n // ============ Cameras ============\n\n @List(\"/cameras\")\n async listCameras(_ctx: RouteContext): Promise<AFSListResult> {\n const config = await this.client.getConfig();\n const cameraNames = Object.keys(config.cameras);\n\n const entries = cameraNames.map((name) => {\n const cam = config.cameras[name]!;\n const description = `${this.formatCameraName(name)} camera`;\n\n return this.buildEntry(joinURL(\"/cameras\", name), {\n id: name,\n meta: {\n kind: \"frigate:camera\",\n id: name,\n childrenCount: 3,\n description,\n detect: cam.detect,\n record: cam.record,\n snapshots: cam.snapshots,\n },\n });\n });\n\n return { data: entries };\n }\n\n @Read(\"/cameras\")\n async readCamerasDir(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const config = await this.client.getConfig();\n const count = Object.keys(config.cameras).length;\n return this.buildEntry(\"/cameras\", {\n meta: { kind: \"afs:directory\", childrenCount: count },\n });\n }\n\n @List(\"/cameras/:camera\")\n async listCamera(ctx: RouteContext<{ camera: string }>): Promise<AFSListResult> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n\n return {\n data: [\n this.buildEntry(joinURL(\"/cameras\", cameraName, \"events\"), {\n meta: {\n kind: \"afs:directory\",\n childrenCount: -1,\n description: `Events for ${cameraName}`,\n },\n }),\n this.buildEntry(joinURL(\"/cameras\", cameraName, \"recordings\"), {\n meta: {\n kind: \"afs:directory\",\n childrenCount: -1,\n description: `Recordings for ${cameraName}`,\n },\n }),\n this.buildEntry(joinURL(\"/cameras\", cameraName, \"reviews\"), {\n meta: {\n kind: \"afs:directory\",\n childrenCount: -1,\n description: `Reviews for ${cameraName}`,\n },\n }),\n ],\n };\n }\n\n @Read(\"/cameras/:camera\")\n async readCamera(ctx: RouteContext<{ camera: string }>): Promise<AFSEntry | undefined> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n\n const config = await this.client.getConfig();\n const cam = config.cameras[cameraName];\n if (!cam) throw new AFSNotFoundError(ctx.path);\n\n const lines: string[] = [];\n lines.push(`Camera: ${cameraName}`);\n if (cam.detect) {\n lines.push(`Resolution: ${cam.detect.width}x${cam.detect.height} @ ${cam.detect.fps} FPS`);\n lines.push(`Detection: ${cam.detect.enabled ? \"enabled\" : \"disabled\"}`);\n }\n if (cam.record) {\n lines.push(`Recording: ${cam.record.enabled ? \"enabled\" : \"disabled\"}`);\n }\n if (cam.snapshots) {\n lines.push(`Snapshots: ${cam.snapshots.enabled ? \"enabled\" : \"disabled\"}`);\n }\n if (cam.zones && Object.keys(cam.zones).length > 0) {\n lines.push(`Zones: ${Object.keys(cam.zones).join(\", \")}`);\n }\n\n return this.buildEntry(ctx.path, {\n id: cameraName,\n content: lines.join(\"\\n\"),\n meta: {\n kind: \"frigate:camera\",\n id: cameraName,\n childrenCount: 3,\n description: `${this.formatCameraName(cameraName)} camera`,\n },\n });\n }\n\n // Camera events\n @List(\"/cameras/:camera/events\")\n async listCameraEvents(ctx: RouteContext<{ camera: string }>): Promise<AFSListResult> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n const events = await this.client.getEvents({ camera: cameraName });\n return { data: this.eventsToEntries(events, joinURL(\"/cameras\", cameraName, \"events\")) };\n }\n\n @Read(\"/cameras/:camera/events\")\n async readCameraEventsDir(ctx: RouteContext<{ camera: string }>): Promise<AFSEntry | undefined> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n return this.buildEntry(ctx.path, {\n meta: { kind: \"afs:directory\", childrenCount: -1, description: `Events for ${cameraName}` },\n });\n }\n\n @Read(\"/cameras/:camera/events/:eventId\")\n async readCameraEvent(\n ctx: RouteContext<{ camera: string; eventId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { camera, eventId } = ctx.params;\n if (isPathTraversal(camera) || isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n try {\n const event = await this.client.getEvent(eventId);\n if (event.camera !== camera) throw new AFSNotFoundError(ctx.path);\n return this.eventToEntry(event, joinURL(\"/cameras\", camera, \"events\"));\n } catch (error) {\n if (error instanceof AFSNotFoundError) throw error;\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // Camera latest snapshot (Phase 1)\n @Read(\"/cameras/:camera/latest\")\n async readCameraLatest(ctx: RouteContext<{ camera: string }>): Promise<AFSEntry | undefined> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n\n try {\n const bytes = await this.client.fetchBinary(`/api/${cameraName}/latest.jpg`);\n const base64 = this.arrayBufferToBase64(bytes);\n return this.buildEntry(ctx.path, {\n content: base64,\n meta: {\n kind: \"frigate:image\",\n contentType: \"image/jpeg\",\n encoding: \"base64\",\n childrenCount: 0,\n },\n });\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // Camera grid image (Phase 1)\n @Read(\"/cameras/:camera/grid\")\n async readCameraGrid(ctx: RouteContext<{ camera: string }>): Promise<AFSEntry | undefined> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n\n try {\n const bytes = await this.client.fetchBinary(`/api/${cameraName}/grid.jpg`);\n const base64 = this.arrayBufferToBase64(bytes);\n return this.buildEntry(ctx.path, {\n content: base64,\n meta: {\n kind: \"frigate:image\",\n contentType: \"image/jpeg\",\n encoding: \"base64\",\n childrenCount: 0,\n },\n });\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // Camera best snapshot for label (Phase 4)\n @Read(\"/cameras/:camera/:label/best\")\n async readCameraBestSnapshot(\n ctx: RouteContext<{ camera: string; label: string }>,\n ): Promise<AFSEntry | undefined> {\n const { camera, label } = ctx.params;\n if (isPathTraversal(camera) || isPathTraversal(label)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[camera]) throw new AFSNotFoundError(ctx.path);\n\n try {\n const bytes = await this.client.fetchBinary(`/api/${camera}/${label}/best.jpg`);\n const base64 = this.arrayBufferToBase64(bytes);\n return this.buildEntry(ctx.path, {\n content: base64,\n meta: {\n kind: \"frigate:image\",\n contentType: \"image/jpeg\",\n encoding: \"base64\",\n childrenCount: 0,\n },\n });\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // Camera PTZ info (Phase 4)\n @Read(\"/cameras/:camera/ptz\")\n async readCameraPtz(ctx: RouteContext<{ camera: string }>): Promise<AFSEntry | undefined> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n\n try {\n const ptzInfo = await this.client.getPtzInfo(cameraName);\n const lines: string[] = [];\n lines.push(`PTZ Info for ${cameraName}`);\n lines.push(`Features: ${ptzInfo.features.join(\", \") || \"none\"}`);\n lines.push(`Presets: ${ptzInfo.presets.join(\", \") || \"none\"}`);\n\n return this.buildEntry(ctx.path, {\n content: lines.join(\"\\n\"),\n meta: {\n kind: \"frigate:ptz\",\n childrenCount: 0,\n features: ptzInfo.features,\n presets: ptzInfo.presets,\n },\n });\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // Camera recordings\n @List(\"/cameras/:camera/recordings\")\n async listCameraRecordings(ctx: RouteContext<{ camera: string }>): Promise<AFSListResult> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n\n try {\n const recordings = await this.client.getRecordings(cameraName);\n const entries = recordings.map((rec) =>\n this.buildEntry(joinURL(\"/cameras\", cameraName, \"recordings\", rec.id), {\n id: rec.id,\n meta: {\n kind: \"frigate:recording\",\n childrenCount: 0,\n camera: cameraName,\n startTime: rec.start_time,\n endTime: rec.end_time,\n duration: rec.duration,\n motion: rec.motion,\n objects: rec.objects,\n },\n }),\n );\n return { data: entries };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Read(\"/cameras/:camera/recordings\")\n async readCameraRecordingsDir(\n ctx: RouteContext<{ camera: string }>,\n ): Promise<AFSEntry | undefined> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n return this.buildEntry(ctx.path, {\n meta: {\n kind: \"afs:directory\",\n childrenCount: -1,\n description: `Recordings for ${cameraName}`,\n },\n });\n }\n\n @Read(\"/cameras/:camera/recordings/summary\")\n async readCameraRecordingsSummary(\n ctx: RouteContext<{ camera: string }>,\n ): Promise<AFSEntry | undefined> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n\n try {\n const summary = await this.client.getRecordingsSummary(cameraName);\n return this.buildEntry(ctx.path, {\n content: summary,\n meta: { kind: \"frigate:recording-summary\", childrenCount: 0 },\n });\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Read(\"/cameras/:camera/recordings/:time/snapshot\")\n async readRecordingSnapshot(\n ctx: RouteContext<{ camera: string; time: string }>,\n ): Promise<AFSEntry | undefined> {\n const { camera, time } = ctx.params;\n if (isPathTraversal(camera) || isPathTraversal(time)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[camera]) throw new AFSNotFoundError(ctx.path);\n\n try {\n const bytes = await this.client.fetchBinary(`/api/${camera}/recordings/${time}/snapshot.png`);\n const base64 = this.arrayBufferToBase64(bytes);\n return this.buildEntry(ctx.path, {\n content: base64,\n meta: {\n kind: \"frigate:image\",\n contentType: \"image/png\",\n encoding: \"base64\",\n childrenCount: 0,\n },\n });\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // Camera reviews\n @List(\"/cameras/:camera/reviews\")\n async listCameraReviews(ctx: RouteContext<{ camera: string }>): Promise<AFSListResult> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n\n try {\n const reviews = await this.client.getReviews({ camera: cameraName });\n return { data: this.reviewsToEntries(reviews) };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Read(\"/cameras/:camera/reviews\")\n async readCameraReviewsDir(ctx: RouteContext<{ camera: string }>): Promise<AFSEntry | undefined> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n return this.buildEntry(ctx.path, {\n meta: { kind: \"afs:directory\", childrenCount: -1, description: `Reviews for ${cameraName}` },\n });\n }\n\n // ============ Events ============\n\n @List(\"/events\")\n async listEvents(ctx: RouteContext): Promise<AFSListResult> {\n const options = ctx.options as { limit?: number; offset?: number } | undefined;\n const params: Record<string, string> = {};\n if (options?.limit) {\n params.limit = String(options.limit);\n }\n const events = await this.client.getEvents(params);\n return { data: this.eventsToEntries(events, \"/events\") };\n }\n\n @Read(\"/events\")\n async readEventsDir(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n return this.buildEntry(\"/events\", {\n meta: { kind: \"afs:directory\", childrenCount: -1 },\n });\n }\n\n @Read(\"/events/summary\")\n async readEventsSummary(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const summary = await this.client.getEventsSummary();\n const lines = summary.map((s) => `${s.camera}: ${s.label} x${s.count} (${s.day})`);\n return this.buildEntry(\"/events/summary\", {\n content: lines.join(\"\\n\"),\n meta: { kind: \"frigate:summary\", childrenCount: 0 },\n });\n }\n\n @Read(\"/events/:eventId\")\n async readEvent(ctx: RouteContext<{ eventId: string }>): Promise<AFSEntry | undefined> {\n const eventId = ctx.params.eventId;\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n try {\n const event = await this.client.getEvent(eventId);\n return this.eventToEntry(event, \"/events\");\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // Event snapshot (Phase 1)\n @Read(\"/events/:eventId/snapshot\")\n async readEventSnapshot(ctx: RouteContext<{ eventId: string }>): Promise<AFSEntry | undefined> {\n const eventId = ctx.params.eventId;\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n\n try {\n const event = await this.client.getEvent(eventId);\n if (!event.has_snapshot) throw new AFSNotFoundError(ctx.path);\n const bytes = await this.client.fetchBinary(`/api/events/${eventId}/snapshot.jpg`);\n const base64 = this.arrayBufferToBase64(bytes);\n return this.buildEntry(ctx.path, {\n id: `${eventId}/snapshot`,\n content: base64,\n meta: {\n kind: \"frigate:image\",\n contentType: \"image/jpeg\",\n encoding: \"base64\",\n childrenCount: 0,\n },\n });\n } catch (error) {\n if (error instanceof AFSNotFoundError) throw error;\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // Event thumbnail (Phase 1)\n @Read(\"/events/:eventId/thumbnail\")\n async readEventThumbnail(ctx: RouteContext<{ eventId: string }>): Promise<AFSEntry | undefined> {\n const eventId = ctx.params.eventId;\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n\n try {\n await this.client.getEvent(eventId); // Verify exists\n const bytes = await this.client.fetchBinary(`/api/events/${eventId}/thumbnail.jpg`);\n const base64 = this.arrayBufferToBase64(bytes);\n return this.buildEntry(ctx.path, {\n id: `${eventId}/thumbnail`,\n content: base64,\n meta: {\n kind: \"frigate:image\",\n contentType: \"image/jpeg\",\n encoding: \"base64\",\n childrenCount: 0,\n },\n });\n } catch (error) {\n if (error instanceof AFSNotFoundError) throw error;\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // Event clip (Phase 1)\n @Read(\"/events/:eventId/clip\")\n async readEventClip(ctx: RouteContext<{ eventId: string }>): Promise<AFSEntry | undefined> {\n const eventId = ctx.params.eventId;\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n\n try {\n const event = await this.client.getEvent(eventId);\n if (!event.has_clip) throw new AFSNotFoundError(ctx.path);\n const clipUrl = `${this.client.getBaseUrl()}/api/events/${eventId}/clip.mp4`;\n return this.buildEntry(ctx.path, {\n id: `${eventId}/clip`,\n content: clipUrl,\n meta: {\n kind: \"frigate:video-clip\",\n contentType: \"video/mp4\",\n encoding: \"url\",\n childrenCount: 0,\n },\n });\n } catch (error) {\n if (error instanceof AFSNotFoundError) throw error;\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // ============ Reviews ============\n\n @List(\"/reviews\")\n async listReviews(ctx: RouteContext): Promise<AFSListResult> {\n const options = ctx.options as { limit?: number; severity?: string } | undefined;\n const params: Record<string, string> = {};\n if (options?.limit) params.limit = String(options.limit);\n if ((options as any)?.severity) params.severity = (options as any).severity;\n\n const reviews = await this.client.getReviews(params);\n return { data: this.reviewsToEntries(reviews) };\n }\n\n @Read(\"/reviews\")\n async readReviewsDir(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n return this.buildEntry(\"/reviews\", {\n meta: { kind: \"afs:directory\", childrenCount: -1 },\n });\n }\n\n @Read(\"/reviews/summary\")\n async readReviewsSummary(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const summary = await this.client.getReviewSummary();\n return this.buildEntry(\"/reviews/summary\", {\n content: summary,\n meta: { kind: \"frigate:summary\", childrenCount: 0 },\n });\n }\n\n @Read(\"/reviews/:reviewId\")\n async readReview(ctx: RouteContext<{ reviewId: string }>): Promise<AFSEntry | undefined> {\n const reviewId = ctx.params.reviewId;\n if (isPathTraversal(reviewId)) throw new AFSNotFoundError(ctx.path);\n\n try {\n const review = await this.client.getReview(reviewId);\n return this.reviewToEntry(review);\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // ============ Exports (Phase 4) ============\n\n @List(\"/exports\")\n async listExports(_ctx: RouteContext): Promise<AFSListResult> {\n const exports = await this.client.getExports();\n const entries = exports.map((exp) =>\n this.buildEntry(joinURL(\"/exports\", exp.id), {\n id: exp.id,\n meta: {\n kind: \"frigate:export\",\n childrenCount: 0,\n camera: exp.camera,\n name: exp.name,\n date: exp.date,\n inProgress: exp.in_progress,\n },\n }),\n );\n return { data: entries };\n }\n\n @Read(\"/exports\")\n async readExportsDir(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n return this.buildEntry(\"/exports\", {\n meta: { kind: \"afs:directory\", childrenCount: -1 },\n });\n }\n\n @Read(\"/exports/:exportId\")\n async readExport(ctx: RouteContext<{ exportId: string }>): Promise<AFSEntry | undefined> {\n const exportId = ctx.params.exportId;\n if (isPathTraversal(exportId)) throw new AFSNotFoundError(ctx.path);\n\n try {\n const exp = await this.client.getExport(exportId);\n return this.buildEntry(ctx.path, {\n id: exp.id,\n content: `Export: ${exp.name}\\nCamera: ${exp.camera}\\nStatus: ${exp.in_progress ? \"in_progress\" : \"complete\"}`,\n meta: {\n kind: \"frigate:export\",\n childrenCount: 0,\n camera: exp.camera,\n name: exp.name,\n date: exp.date,\n inProgress: exp.in_progress,\n },\n });\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // ============ Dashboard ============\n\n @Read(\"/dashboard\")\n async readDashboard(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const stats = await this.client.getStats();\n\n const lines: string[] = [];\n lines.push(\"Frigate NVR Status\");\n lines.push(\"\");\n lines.push(`Version: ${stats.service.version}`);\n lines.push(`Uptime: ${this.formatUptime(stats.service.uptime)}`);\n lines.push(\"\");\n\n const detectorEntries = Object.entries(stats.detectors);\n if (detectorEntries.length > 0) {\n lines.push(\"Detectors:\");\n for (const [name, det] of detectorEntries) {\n lines.push(` ${name}: inference ${det.inference_speed}ms`);\n }\n lines.push(\"\");\n }\n\n const cameraEntries = Object.entries(stats.cameras);\n if (cameraEntries.length > 0) {\n lines.push(\"Cameras:\");\n for (const [name, cam] of cameraEntries) {\n lines.push(` ${name}: ${cam.camera_fps} fps, detection ${cam.detection_fps} fps`);\n }\n }\n\n return this.buildEntry(\"/dashboard\", {\n content: lines.join(\"\\n\"),\n meta: { kind: \"frigate:dashboard\", childrenCount: 0 },\n });\n }\n\n // ============ Config ============\n\n @Read(\"/config\")\n async readConfig(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const config = await this.client.getConfig();\n const cameraNames = Object.keys(config.cameras);\n\n const lines: string[] = [];\n lines.push(\"Frigate configuration summary\");\n lines.push(\"\");\n lines.push(`Cameras: ${cameraNames.length}`);\n for (const name of cameraNames) {\n const cam = config.cameras[name]!;\n const detect = cam.detect?.enabled ? \"detect\" : \"\";\n const record = cam.record?.enabled ? \"record\" : \"\";\n const snap = cam.snapshots?.enabled ? \"snapshot\" : \"\";\n const features = [detect, record, snap].filter(Boolean).join(\", \");\n lines.push(` ${name}: ${features || \"none\"}`);\n }\n\n return this.buildEntry(\"/config\", {\n content: lines.join(\"\\n\"),\n meta: { kind: \"frigate:config\", childrenCount: 0 },\n });\n }\n\n // Raw config (Phase 5)\n @Read(\"/config/raw\")\n async readConfigRaw(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n try {\n const rawConfig = await this.client.fetchText(\"/api/config/raw\");\n return this.buildEntry(\"/config/raw\", {\n content: rawConfig,\n meta: {\n kind: \"frigate:config\",\n childrenCount: 0,\n contentType: \"text/yaml\",\n },\n });\n } catch (error) {\n throw this.mapFrigateError(error, \"/config/raw\");\n }\n }\n\n // Write config (Phase 5)\n @Write(\"/config\")\n async writeConfig(ctx: RouteContext, payload: AFSWriteEntryPayload): Promise<{ data: AFSEntry }> {\n const content =\n typeof payload.content === \"string\" ? payload.content : JSON.stringify(payload.content);\n if (!content || content.trim() === \"\") {\n throw new Error(\"Config content cannot be empty\");\n }\n\n try {\n await this.client.postJSON(\"/api/config/save\", { content } as any);\n // Workaround: postJSON expects JSON but config/save expects text\n // Actually the mock server handles both, let's use postText\n } catch {\n // Fallback: use postText\n }\n\n try {\n // Use the raw post approach\n const response = await fetch(joinURL(this.client.getBaseUrl(), \"/api/config/save\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"text/plain\" },\n body: content,\n });\n if (!response.ok) throw new Error(\"Failed to save config\");\n } catch (error) {\n throw this.mapFrigateError(error, ctx.path);\n }\n\n this.client.invalidateCache(\"/api/config\");\n\n return {\n data: this.buildEntry(\"/config\", {\n content,\n meta: { kind: \"frigate:config\", childrenCount: 0 },\n }),\n };\n }\n\n // ============ Logs (Phase 5) ============\n\n @Read(\"/logs\")\n async readLogsDir(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n return this.buildEntry(\"/logs\", {\n meta: { kind: \"afs:directory\", childrenCount: 3, description: \"Service logs\" },\n });\n }\n\n @List(\"/logs\")\n async listLogs(_ctx: RouteContext): Promise<AFSListResult> {\n return {\n data: [\n this.buildEntry(\"/logs/frigate\", {\n meta: { kind: \"frigate:log\", childrenCount: 0, description: \"Frigate service logs\" },\n }),\n this.buildEntry(\"/logs/nginx\", {\n meta: { kind: \"frigate:log\", childrenCount: 0, description: \"Nginx logs\" },\n }),\n this.buildEntry(\"/logs/go2rtc\", {\n meta: { kind: \"frigate:log\", childrenCount: 0, description: \"go2rtc logs\" },\n }),\n ],\n };\n }\n\n @Read(\"/logs/:service\")\n async readLog(ctx: RouteContext<{ service: string }>): Promise<AFSEntry | undefined> {\n const service = ctx.params.service;\n if (![\"frigate\", \"nginx\", \"go2rtc\"].includes(service)) {\n throw new AFSNotFoundError(ctx.path);\n }\n\n try {\n const logContent = await this.client.fetchText(`/api/logs/${service}`);\n return this.buildEntry(ctx.path, {\n content: logContent,\n meta: {\n kind: \"frigate:log\",\n childrenCount: 0,\n service,\n },\n });\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // ============ Users (Phase 5) ============\n\n @List(\"/users\")\n async listUsers(_ctx: RouteContext): Promise<AFSListResult> {\n try {\n const users = await this.client.getUsers();\n const entries = users.map((user) =>\n this.buildEntry(joinURL(\"/users\", user.username), {\n id: user.username,\n meta: {\n kind: \"frigate:user\",\n childrenCount: 0,\n username: user.username,\n role: user.role,\n },\n }),\n );\n return { data: entries };\n } catch (error) {\n throw this.mapFrigateError(error, \"/users\");\n }\n }\n\n @Read(\"/users\")\n async readUsersDir(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n return this.buildEntry(\"/users\", {\n meta: { kind: \"afs:directory\", childrenCount: -1 },\n });\n }\n\n @Read(\"/users/:username\")\n async readUser(ctx: RouteContext<{ username: string }>): Promise<AFSEntry | undefined> {\n const username = ctx.params.username;\n if (isPathTraversal(username)) throw new AFSNotFoundError(ctx.path);\n\n try {\n const users = await this.client.getUsers();\n const user = users.find((u) => u.username === username);\n if (!user) throw new AFSNotFoundError(ctx.path);\n\n return this.buildEntry(ctx.path, {\n id: user.username,\n content: `User: ${user.username}\\nRole: ${user.role}`,\n meta: {\n kind: \"frigate:user\",\n childrenCount: 0,\n username: user.username,\n role: user.role,\n },\n });\n } catch (error) {\n if (error instanceof AFSNotFoundError) throw error;\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // ============ Recording storage ============\n\n @Read(\"/recordings/storage\")\n async readRecordingsStorage(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const storage = await this.client.getRecordingsStorage();\n const lines: string[] = [\"Recording Storage\"];\n for (const [cam, data] of Object.entries(storage)) {\n const s = data as { bandwidth: number; usage: number; usage_percent: number };\n lines.push(` ${cam}: ${s.usage}MB (${s.usage_percent}%), bandwidth: ${s.bandwidth}Mbps`);\n }\n return this.buildEntry(\"/recordings/storage\", {\n content: lines.join(\"\\n\"),\n meta: { kind: \"frigate:storage\", childrenCount: 0 },\n });\n }\n\n // ============ Leaf Node Lists ============\n\n @List(\"/events/:eventId\")\n async listEventLeaf(ctx: RouteContext<{ eventId: string }>): Promise<AFSListResult> {\n const eventId = ctx.params.eventId;\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n try {\n await this.client.getEvent(eventId);\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n return { data: [] };\n }\n\n @List(\"/cameras/:camera/events/:eventId\")\n async listCameraEventLeaf(\n ctx: RouteContext<{ camera: string; eventId: string }>,\n ): Promise<AFSListResult> {\n const { camera, eventId } = ctx.params;\n if (isPathTraversal(camera) || isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n try {\n const event = await this.client.getEvent(eventId);\n if (event.camera !== camera) throw new AFSNotFoundError(ctx.path);\n } catch (error) {\n if (error instanceof AFSNotFoundError) throw error;\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n return { data: [] };\n }\n\n @List(\"/dashboard\")\n async listDashboard(_ctx: RouteContext): Promise<AFSListResult> {\n return { data: [] };\n }\n\n @List(\"/config\")\n async listConfig(_ctx: RouteContext): Promise<AFSListResult> {\n return { data: [] };\n }\n\n @List(\"/reviews/:reviewId\")\n async listReviewLeaf(ctx: RouteContext<{ reviewId: string }>): Promise<AFSListResult> {\n const reviewId = ctx.params.reviewId;\n if (isPathTraversal(reviewId)) throw new AFSNotFoundError(ctx.path);\n try {\n await this.client.getReview(reviewId);\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n return { data: [] };\n }\n\n @List(\"/exports/:exportId\")\n async listExportLeaf(ctx: RouteContext<{ exportId: string }>): Promise<AFSListResult> {\n const exportId = ctx.params.exportId;\n if (isPathTraversal(exportId)) throw new AFSNotFoundError(ctx.path);\n try {\n await this.client.getExport(exportId);\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n return { data: [] };\n }\n\n // ============ Search ============\n\n @Search(\"/events\")\n async searchEvents(\n _ctx: RouteContext,\n query: string,\n options?: AFSSearchOptions,\n ): Promise<{ data: AFSEntry[]; message?: string }> {\n const meta = (options as any)?.meta;\n\n // Semantic search (Phase 4)\n if ((options as any)?.type === \"semantic\" || meta?.semantic) {\n try {\n const params: Record<string, string> = {};\n if (query) params.query = query;\n const events = await this.client.searchEvents(params);\n return { data: this.eventsToEntries(events, \"/events\") };\n } catch {\n return { data: [], message: \"Semantic search unavailable\" };\n }\n }\n\n // Standard label-based search\n const params: Record<string, string> = {};\n if (query) params.label = query;\n if (meta?.camera) params.camera = meta.camera;\n if (meta?.zone) params.zone = meta.zone;\n if (meta?.minScore) params.min_score = String(meta.minScore);\n if (meta?.after) params.after = String(meta.after);\n if (meta?.before) params.before = String(meta.before);\n\n const events = await this.client.getEvents(params);\n return { data: this.eventsToEntries(events, \"/events\") };\n }\n\n @Search(\"/:path*\")\n async searchGeneric(\n _ctx: RouteContext,\n _query: string,\n _options?: AFSSearchOptions,\n ): Promise<{ data: AFSEntry[] }> {\n return { data: [] };\n }\n\n // ============ Actions (Phase 3) ============\n\n // Event actions\n @Actions(\"/events/:eventId\")\n async listEventActions(ctx: RouteContext<{ eventId: string }>): Promise<AFSListResult> {\n const eventId = ctx.params.eventId;\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n\n const basePath = joinURL(\"/events\", eventId, \".actions\");\n return {\n data: [\n this.buildActionEntry(\n basePath,\n \"retain\",\n \"Mark event for indefinite retention\",\n undefined,\n \"ambient\",\n ),\n this.buildActionEntry(basePath, \"unretain\", \"Remove retention flag\", undefined, \"ambient\"),\n this.buildActionEntry(basePath, \"delete\", \"Delete event\", undefined, \"critical\"),\n this.buildActionEntry(\n basePath,\n \"set-sub-label\",\n \"Set sub-label\",\n {\n type: \"object\",\n properties: { subLabel: { type: \"string\" } },\n required: [\"subLabel\"],\n },\n \"ambient\",\n ),\n this.buildActionEntry(\n basePath,\n \"set-description\",\n \"Set description\",\n {\n type: \"object\",\n properties: { description: { type: \"string\" } },\n required: [\"description\"],\n },\n \"ambient\",\n ),\n this.buildActionEntry(\n basePath,\n \"regenerate-description\",\n \"AI regenerate description\",\n undefined,\n \"ambient\",\n ),\n ],\n };\n }\n\n @Actions.Exec(\"/events/:eventId\", \"retain\")\n async retainEvent(ctx: RouteContext<{ eventId: string }>): Promise<AFSExecResult> {\n const eventId = ctx.params.eventId;\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n try {\n await this.client.postJSON(`/api/events/${eventId}/retain`);\n this.client.invalidateCache(\"/api/events\");\n return { success: true, data: { message: \"Event retained\" } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Actions.Exec(\"/events/:eventId\", \"unretain\")\n async unretainEvent(ctx: RouteContext<{ eventId: string }>): Promise<AFSExecResult> {\n const eventId = ctx.params.eventId;\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n try {\n await this.client.deleteRequest(`/api/events/${eventId}/retain`);\n this.client.invalidateCache(\"/api/events\");\n return { success: true, data: { message: \"Event unretained\" } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Actions.Exec(\"/events/:eventId\", \"delete\")\n async deleteEvent(ctx: RouteContext<{ eventId: string }>): Promise<AFSExecResult> {\n const eventId = ctx.params.eventId;\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n try {\n await this.client.deleteRequest(`/api/events/${eventId}`);\n this.client.invalidateCache(\"/api/events\");\n return { success: true, data: { message: \"Event deleted\" } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Actions.Exec(\"/events/:eventId\", \"set-sub-label\")\n async setEventSubLabel(\n ctx: RouteContext<{ eventId: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const eventId = ctx.params.eventId;\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n if (args.subLabel === undefined) throw new Error(\"subLabel is required\");\n try {\n await this.client.postJSON(`/api/events/${eventId}/sub_label`, {\n subLabel: String(args.subLabel),\n });\n this.client.invalidateCache(\"/api/events\");\n return { success: true, data: { message: \"Sub-label updated\" } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Actions.Exec(\"/events/:eventId\", \"set-description\")\n async setEventDescription(\n ctx: RouteContext<{ eventId: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const eventId = ctx.params.eventId;\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n if (args.description === undefined) throw new Error(\"description is required\");\n try {\n await this.client.putJSON(`/api/events/${eventId}/description`, {\n description: String(args.description),\n });\n this.client.invalidateCache(\"/api/events\");\n return { success: true, data: { message: \"Description updated\" } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Actions.Exec(\"/events/:eventId\", \"regenerate-description\")\n async regenerateEventDescription(ctx: RouteContext<{ eventId: string }>): Promise<AFSExecResult> {\n const eventId = ctx.params.eventId;\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(ctx.path);\n try {\n const result = await this.client.putJSON<{ description?: string }>(\n `/api/events/${eventId}/description/regenerate`,\n {},\n );\n this.client.invalidateCache(\"/api/events\");\n return {\n success: true,\n data: { message: \"Description regenerated\", description: result.description },\n };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // Camera actions\n @Actions(\"/cameras/:camera\")\n async listCameraActions(ctx: RouteContext<{ camera: string }>): Promise<AFSListResult> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n\n const basePath = joinURL(\"/cameras\", cameraName, \".actions\");\n return {\n data: [\n this.buildActionEntry(\n basePath,\n \"detect-on\",\n \"Enable object detection\",\n undefined,\n \"ambient\",\n ),\n this.buildActionEntry(\n basePath,\n \"detect-off\",\n \"Disable object detection\",\n undefined,\n \"ambient\",\n ),\n this.buildActionEntry(basePath, \"recordings-on\", \"Enable recording\", undefined, \"ambient\"),\n this.buildActionEntry(\n basePath,\n \"recordings-off\",\n \"Disable recording\",\n undefined,\n \"ambient\",\n ),\n this.buildActionEntry(basePath, \"snapshots-on\", \"Enable snapshots\", undefined, \"ambient\"),\n this.buildActionEntry(basePath, \"snapshots-off\", \"Disable snapshots\", undefined, \"ambient\"),\n this.buildActionEntry(\n basePath,\n \"motion-on\",\n \"Enable motion detection\",\n undefined,\n \"ambient\",\n ),\n this.buildActionEntry(\n basePath,\n \"motion-off\",\n \"Disable motion detection\",\n undefined,\n \"ambient\",\n ),\n this.buildActionEntry(\n basePath,\n \"create-event\",\n \"Create manual event\",\n {\n type: \"object\",\n properties: {\n label: { type: \"string\" },\n sub_label: { type: \"string\" },\n duration: { type: \"number\" },\n score: { type: \"number\" },\n },\n },\n \"boundary\",\n ),\n this.buildActionEntry(\n basePath,\n \"export\",\n \"Export recording range\",\n {\n type: \"object\",\n properties: {\n start_time: { type: \"number\" },\n end_time: { type: \"number\" },\n name: { type: \"string\" },\n },\n required: [\"start_time\", \"end_time\"],\n },\n \"boundary\",\n ),\n this.buildActionEntry(\n basePath,\n \"ptz\",\n \"PTZ control\",\n {\n type: \"object\",\n properties: {\n command: { type: \"string\" },\n preset: { type: \"string\" },\n },\n },\n \"boundary\",\n ),\n this.buildActionEntry(\n basePath,\n \"notifications-on\",\n \"Enable notifications\",\n undefined,\n \"ambient\",\n ),\n this.buildActionEntry(\n basePath,\n \"notifications-off\",\n \"Disable notifications\",\n undefined,\n \"ambient\",\n ),\n ],\n };\n }\n\n // Camera toggle actions\n @Actions.Exec(\"/cameras/:camera\", \"detect-on\")\n async cameraDetectOn(ctx: RouteContext<{ camera: string }>): Promise<AFSExecResult> {\n return this.toggleCameraFeature(ctx.params.camera, \"detect\", true, ctx.path);\n }\n\n @Actions.Exec(\"/cameras/:camera\", \"detect-off\")\n async cameraDetectOff(ctx: RouteContext<{ camera: string }>): Promise<AFSExecResult> {\n return this.toggleCameraFeature(ctx.params.camera, \"detect\", false, ctx.path);\n }\n\n @Actions.Exec(\"/cameras/:camera\", \"recordings-on\")\n async cameraRecordingsOn(ctx: RouteContext<{ camera: string }>): Promise<AFSExecResult> {\n return this.toggleCameraFeature(ctx.params.camera, \"recordings\", true, ctx.path);\n }\n\n @Actions.Exec(\"/cameras/:camera\", \"recordings-off\")\n async cameraRecordingsOff(ctx: RouteContext<{ camera: string }>): Promise<AFSExecResult> {\n return this.toggleCameraFeature(ctx.params.camera, \"recordings\", false, ctx.path);\n }\n\n @Actions.Exec(\"/cameras/:camera\", \"snapshots-on\")\n async cameraSnapshotsOn(ctx: RouteContext<{ camera: string }>): Promise<AFSExecResult> {\n return this.toggleCameraFeature(ctx.params.camera, \"snapshots\", true, ctx.path);\n }\n\n @Actions.Exec(\"/cameras/:camera\", \"snapshots-off\")\n async cameraSnapshotsOff(ctx: RouteContext<{ camera: string }>): Promise<AFSExecResult> {\n return this.toggleCameraFeature(ctx.params.camera, \"snapshots\", false, ctx.path);\n }\n\n @Actions.Exec(\"/cameras/:camera\", \"motion-on\")\n async cameraMotionOn(ctx: RouteContext<{ camera: string }>): Promise<AFSExecResult> {\n return this.toggleCameraFeature(ctx.params.camera, \"motion\", true, ctx.path);\n }\n\n @Actions.Exec(\"/cameras/:camera\", \"motion-off\")\n async cameraMotionOff(ctx: RouteContext<{ camera: string }>): Promise<AFSExecResult> {\n return this.toggleCameraFeature(ctx.params.camera, \"motion\", false, ctx.path);\n }\n\n @Actions.Exec(\"/cameras/:camera\", \"create-event\")\n async cameraCreateEvent(\n ctx: RouteContext<{ camera: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n\n try {\n const result = await this.client.postJSON<{ event_id: string }>(\n `/api/${cameraName}/events/create`,\n {\n label: args.label as string,\n sub_label: args.sub_label as string,\n duration: args.duration as number,\n score: args.score as number,\n },\n );\n this.client.invalidateCache(\"/api/events\");\n return { success: true, data: { message: \"Manual event created\", eventId: result.event_id } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Actions.Exec(\"/cameras/:camera\", \"export\")\n async cameraExport(\n ctx: RouteContext<{ camera: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n\n if (!args.start_time || !args.end_time) {\n throw new Error(\"start_time and end_time are required\");\n }\n\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n\n try {\n const result = await this.client.postJSON<{ id: string }>(`/api/${cameraName}/export`, {\n start_time: args.start_time,\n end_time: args.end_time,\n name: args.name,\n });\n return { success: true, data: { message: \"Export started\", exportId: result.id } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Actions.Exec(\"/cameras/:camera\", \"ptz\")\n async cameraPtz(\n ctx: RouteContext<{ camera: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n\n try {\n await this.client.postJSON(`/api/${cameraName}/ptz`, {\n command: args.command,\n preset: args.preset,\n });\n return { success: true, data: { message: \"PTZ command executed\" } };\n } catch (error) {\n if (error instanceof FrigateApiError) {\n if (error.code === \"AFS_NOT_FOUND\") throw new AFSNotFoundError(ctx.path);\n if (error.statusCode === 400) throw new Error(\"Camera does not support PTZ\");\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Actions.Exec(\"/cameras/:camera\", \"notifications-on\")\n async cameraNotificationsOn(ctx: RouteContext<{ camera: string }>): Promise<AFSExecResult> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n try {\n await this.client.postText(`/api/${cameraName}/notifications/set`, \"ON\");\n return { success: true, data: { message: \"Notifications enabled\" } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Actions.Exec(\"/cameras/:camera\", \"notifications-off\")\n async cameraNotificationsOff(ctx: RouteContext<{ camera: string }>): Promise<AFSExecResult> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(ctx.path);\n try {\n await this.client.postText(`/api/${cameraName}/notifications/set`, \"OFF\");\n return { success: true, data: { message: \"Notifications disabled\" } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // Review actions\n @Actions(\"/reviews/:reviewId\")\n async listReviewActions(ctx: RouteContext<{ reviewId: string }>): Promise<AFSListResult> {\n const reviewId = ctx.params.reviewId;\n if (isPathTraversal(reviewId)) throw new AFSNotFoundError(ctx.path);\n\n const basePath = joinURL(\"/reviews\", reviewId, \".actions\");\n return {\n data: [\n this.buildActionEntry(\n basePath,\n \"mark-viewed\",\n \"Mark review as viewed\",\n undefined,\n \"ambient\",\n ),\n this.buildActionEntry(\n basePath,\n \"unmark-viewed\",\n \"Unmark review as viewed\",\n undefined,\n \"ambient\",\n ),\n ],\n };\n }\n\n @Actions.Exec(\"/reviews/:reviewId\", \"mark-viewed\")\n async markReviewViewed(ctx: RouteContext<{ reviewId: string }>): Promise<AFSExecResult> {\n const reviewId = ctx.params.reviewId;\n if (isPathTraversal(reviewId)) throw new AFSNotFoundError(ctx.path);\n try {\n await this.client.postJSON(`/api/review/${reviewId}/viewed`);\n this.client.invalidateCache(\"/api/review\");\n return { success: true, data: { message: \"Marked as viewed\" } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Actions.Exec(\"/reviews/:reviewId\", \"unmark-viewed\")\n async unmarkReviewViewed(ctx: RouteContext<{ reviewId: string }>): Promise<AFSExecResult> {\n const reviewId = ctx.params.reviewId;\n if (isPathTraversal(reviewId)) throw new AFSNotFoundError(ctx.path);\n try {\n await this.client.deleteRequest(`/api/review/${reviewId}/viewed`);\n this.client.invalidateCache(\"/api/review\");\n return { success: true, data: { message: \"Unmarked as viewed\" } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // Export actions (Phase 4)\n @Actions(\"/exports/:exportId\")\n async listExportActions(ctx: RouteContext<{ exportId: string }>): Promise<AFSListResult> {\n const exportId = ctx.params.exportId;\n if (isPathTraversal(exportId)) throw new AFSNotFoundError(ctx.path);\n\n const basePath = joinURL(\"/exports\", exportId, \".actions\");\n return {\n data: [\n this.buildActionEntry(basePath, \"delete\", \"Delete export\", undefined, \"critical\"),\n this.buildActionEntry(\n basePath,\n \"rename\",\n \"Rename export\",\n {\n type: \"object\",\n properties: { name: { type: \"string\" } },\n required: [\"name\"],\n },\n \"boundary\",\n ),\n ],\n };\n }\n\n @Actions.Exec(\"/exports/:exportId\", \"delete\")\n async deleteExport(ctx: RouteContext<{ exportId: string }>): Promise<AFSExecResult> {\n const exportId = ctx.params.exportId;\n if (isPathTraversal(exportId)) throw new AFSNotFoundError(ctx.path);\n try {\n await this.client.deleteRequest(`/api/exports/${exportId}`);\n return { success: true, data: { message: \"Export deleted\" } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n @Actions.Exec(\"/exports/:exportId\", \"rename\")\n async renameExport(\n ctx: RouteContext<{ exportId: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const exportId = ctx.params.exportId;\n if (isPathTraversal(exportId)) throw new AFSNotFoundError(ctx.path);\n if (!args.name) throw new Error(\"name is required\");\n\n // Validate name for path traversal\n const name = String(args.name);\n if (name.includes(\"..\") || name.includes(\"/\") || name.includes(\"\\\\\")) {\n throw new Error(\"Invalid export name\");\n }\n\n try {\n await this.client.patchJSON(`/api/exports/${exportId}/rename`, { name });\n return { success: true, data: { message: \"Export renamed\" } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // Review summarize (Phase 4) - global action on /reviews\n @Actions(\"/reviews\")\n async listReviewsActions(_ctx: RouteContext): Promise<AFSListResult> {\n return {\n data: [\n this.buildActionEntry(\n \"/reviews/.actions\",\n \"summarize\",\n \"AI generate review summary\",\n undefined,\n \"ambient\",\n ),\n ],\n };\n }\n\n @Actions.Exec(\"/reviews\", \"summarize\")\n async summarizeReviews(_ctx: RouteContext): Promise<AFSExecResult> {\n try {\n const result = await this.client.getReviewActivitySummary();\n return { success: true, data: { message: \"Summary generated\", summary: result.summary } };\n } catch (_error) {\n return { success: true, data: { message: \"No reviews to summarize\", summary: \"\" } };\n }\n }\n\n // Root actions (Phase 5)\n @Actions(\"/\")\n async listRootActions(_ctx: RouteContext): Promise<AFSListResult> {\n return {\n data: [\n this.buildActionEntry(\"/.actions\", \"restart\", \"Restart Frigate\", undefined, \"critical\"),\n this.buildActionEntry(\n \"/.actions\",\n \"create-user\",\n \"Create user\",\n {\n type: \"object\",\n properties: {\n username: { type: \"string\" },\n password: { type: \"string\" },\n role: { type: \"string\" },\n },\n required: [\"username\", \"password\"],\n },\n \"boundary\",\n ),\n ],\n };\n }\n\n @Actions.Exec(\"/\", \"restart\")\n async restartFrigate(_ctx: RouteContext): Promise<AFSExecResult> {\n try {\n await this.client.postJSON(\"/api/restart\");\n return { success: true, data: { message: \"Frigate restart initiated\" } };\n } catch (error) {\n throw this.mapFrigateError(error, \"/\");\n }\n }\n\n @Actions.Exec(\"/\", \"create-user\")\n async createUser(_ctx: RouteContext, args: Record<string, unknown>): Promise<AFSExecResult> {\n if (!args.username || !args.password) {\n throw new Error(\"username and password are required\");\n }\n\n try {\n await this.client.postJSON(\"/api/users\", {\n username: String(args.username),\n password: String(args.password),\n role: args.role ? String(args.role) : \"viewer\",\n });\n return { success: true, data: { message: \"User created\" } };\n } catch (error) {\n throw this.mapFrigateError(error, \"/\");\n }\n }\n\n // User delete action\n @Actions(\"/users/:username\")\n async listUserActions(ctx: RouteContext<{ username: string }>): Promise<AFSListResult> {\n const basePath = joinURL(\"/users\", ctx.params.username, \".actions\");\n return {\n data: [this.buildActionEntry(basePath, \"delete\", \"Delete user\", undefined, \"critical\")],\n };\n }\n\n @Actions.Exec(\"/users/:username\", \"delete\")\n async deleteUser(ctx: RouteContext<{ username: string }>): Promise<AFSExecResult> {\n const username = ctx.params.username;\n if (isPathTraversal(username)) throw new AFSNotFoundError(ctx.path);\n try {\n await this.client.deleteRequest(`/api/users/${username}`);\n return { success: true, data: { message: \"User deleted\" } };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(ctx.path);\n }\n throw this.mapFrigateError(error, ctx.path);\n }\n }\n\n // ============ Stat ============\n\n @Stat(\"/:path*\")\n async statHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSStatResult> {\n const path = joinURL(\"/\", ctx.params.path ?? \"\");\n\n // Root\n if (path === \"/\") {\n return {\n data: {\n id: \"/\",\n path: \"/\",\n meta: { kind: \"frigate:nvr\", childrenCount: 8, description: \"Frigate NVR instance\" },\n },\n };\n }\n\n // Static directory paths\n const staticDirs: Record<string, { kind: string; childrenCount: number }> = {\n \"/cameras\": { kind: \"afs:directory\", childrenCount: -1 },\n \"/events\": { kind: \"afs:directory\", childrenCount: -1 },\n \"/reviews\": { kind: \"afs:directory\", childrenCount: -1 },\n \"/exports\": { kind: \"afs:directory\", childrenCount: -1 },\n \"/dashboard\": { kind: \"frigate:dashboard\", childrenCount: 0 },\n \"/config\": { kind: \"frigate:config\", childrenCount: 0 },\n \"/logs\": { kind: \"afs:directory\", childrenCount: 3 },\n \"/users\": { kind: \"afs:directory\", childrenCount: -1 },\n };\n\n if (path === \"/cameras\") {\n const config = await this.client.getConfig();\n const count = Object.keys(config.cameras).length;\n return {\n data: {\n id: \"/cameras\",\n path: \"/cameras\",\n meta: { kind: \"afs:directory\", childrenCount: count },\n },\n };\n }\n\n if (staticDirs[path]) {\n return { data: { id: path, path, meta: staticDirs[path] } };\n }\n\n // Camera paths: /cameras/:name\n const cameraMatch = path.match(/^\\/cameras\\/([^/]+)$/);\n if (cameraMatch) {\n const cameraName = cameraMatch[1]!;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(path);\n return {\n data: {\n id: cameraName,\n path,\n meta: {\n kind: \"frigate:camera\",\n id: cameraName,\n childrenCount: 3,\n description: `${this.formatCameraName(cameraName)} camera`,\n },\n },\n };\n }\n\n // Camera sub-directories\n const cameraSubMatch = path.match(/^\\/cameras\\/([^/]+)\\/(events|recordings|reviews)$/);\n if (cameraSubMatch) {\n const cameraName = cameraSubMatch[1]!;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(path);\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(path);\n return {\n data: {\n id: path,\n path,\n meta: { kind: \"afs:directory\", childrenCount: -1 },\n },\n };\n }\n\n // Camera event detail: /cameras/:name/events/:id\n const cameraEventMatch = path.match(/^\\/cameras\\/([^/]+)\\/events\\/([^/]+)$/);\n if (cameraEventMatch) {\n const cameraName = cameraEventMatch[1]!;\n const eventId = cameraEventMatch[2]!;\n if (isPathTraversal(cameraName) || isPathTraversal(eventId)) throw new AFSNotFoundError(path);\n try {\n const event = await this.client.getEvent(eventId);\n if (event.camera !== cameraName) throw new AFSNotFoundError(path);\n return {\n data: {\n id: event.id,\n path,\n meta: {\n kind: \"frigate:detection-event\",\n childrenCount: 0,\n label: event.label,\n score: event.score,\n camera: event.camera,\n },\n },\n };\n } catch (error) {\n if (error instanceof AFSNotFoundError) throw error;\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(path);\n }\n throw this.mapFrigateError(error, path);\n }\n }\n\n // Global event detail: /events/:id\n const eventMatch = path.match(/^\\/events\\/([^/]+)$/);\n if (eventMatch) {\n const eventId = eventMatch[1]!;\n if (eventId === \"summary\") {\n return { data: { id: path, path, meta: { kind: \"frigate:summary\", childrenCount: 0 } } };\n }\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(path);\n try {\n const event = await this.client.getEvent(eventId);\n return {\n data: {\n id: event.id,\n path,\n meta: {\n kind: \"frigate:detection-event\",\n childrenCount: 0,\n label: event.label,\n score: event.score,\n camera: event.camera,\n },\n },\n };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(path);\n }\n throw this.mapFrigateError(error, path);\n }\n }\n\n // Event binary content: /events/:id/snapshot, /events/:id/thumbnail, /events/:id/clip\n const eventBinaryMatch = path.match(/^\\/events\\/([^/]+)\\/(snapshot|thumbnail|clip)$/);\n if (eventBinaryMatch) {\n const eventId = eventBinaryMatch[1]!;\n const type = eventBinaryMatch[2]!;\n if (isPathTraversal(eventId)) throw new AFSNotFoundError(path);\n try {\n await this.client.getEvent(eventId);\n const kind = type === \"clip\" ? \"frigate:video-clip\" : \"frigate:image\";\n return {\n data: {\n id: `${eventId}/${type}`,\n path,\n meta: { kind, childrenCount: 0 },\n },\n };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(path);\n }\n throw this.mapFrigateError(error, path);\n }\n }\n\n // Reviews\n const reviewMatch = path.match(/^\\/reviews\\/([^/]+)$/);\n if (reviewMatch) {\n const reviewId = reviewMatch[1]!;\n if (reviewId === \"summary\") {\n return { data: { id: path, path, meta: { kind: \"frigate:summary\", childrenCount: 0 } } };\n }\n if (isPathTraversal(reviewId)) throw new AFSNotFoundError(path);\n try {\n const review = await this.client.getReview(reviewId);\n return {\n data: {\n id: review.id,\n path,\n meta: {\n kind: \"frigate:review\",\n childrenCount: 0,\n camera: review.camera,\n severity: review.severity,\n },\n },\n };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(path);\n }\n throw this.mapFrigateError(error, path);\n }\n }\n\n // Exports\n const exportMatch = path.match(/^\\/exports\\/([^/]+)$/);\n if (exportMatch) {\n const exportId = exportMatch[1]!;\n if (isPathTraversal(exportId)) throw new AFSNotFoundError(path);\n try {\n const exp = await this.client.getExport(exportId);\n return {\n data: {\n id: exp.id,\n path,\n meta: { kind: \"frigate:export\", childrenCount: 0, camera: exp.camera },\n },\n };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(path);\n }\n throw this.mapFrigateError(error, path);\n }\n }\n\n // Logs\n const logMatch = path.match(/^\\/logs\\/(frigate|nginx|go2rtc)$/);\n if (logMatch) {\n return {\n data: {\n id: path,\n path,\n meta: { kind: \"frigate:log\", childrenCount: 0, service: logMatch[1] },\n },\n };\n }\n\n // Config raw\n if (path === \"/config/raw\") {\n return {\n data: { id: path, path, meta: { kind: \"frigate:config\", childrenCount: 0 } },\n };\n }\n\n // Recording storage\n if (path === \"/recordings/storage\") {\n return {\n data: { id: path, path, meta: { kind: \"frigate:storage\", childrenCount: 0 } },\n };\n }\n\n // Recordings\n if (path === \"/recordings\") {\n return { data: { id: path, path, meta: { kind: \"afs:directory\", childrenCount: -1 } } };\n }\n\n throw new AFSNotFoundError(path);\n }\n\n // ============ Explain ============\n\n @Explain(\"/\")\n async explainRoot(_ctx: RouteContext): Promise<AFSExplainResult> {\n const config = await this.client.getConfig();\n const stats = await this.client.getStats();\n const cameraNames = Object.keys(config.cameras);\n\n const lines: string[] = [];\n lines.push(\"Frigate NVR instance\");\n lines.push(`Version: ${stats.service.version}`);\n lines.push(`Cameras: ${cameraNames.length} (${cameraNames.join(\", \")})`);\n\n const detectorEntries = Object.entries(stats.detectors);\n for (const [name, det] of detectorEntries) {\n lines.push(`Detector: ${name} (inference: ${det.inference_speed}ms)`);\n }\n\n lines.push(`Uptime: ${this.formatUptime(stats.service.uptime)}`);\n\n return { content: lines.join(\"\\n\"), format: \"text\" };\n }\n\n @Explain(\"/cameras/:camera\")\n async explainCamera(ctx: RouteContext<{ camera: string }>): Promise<AFSExplainResult> {\n const cameraName = ctx.params.camera;\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(ctx.path);\n\n const config = await this.client.getConfig();\n const cam = config.cameras[cameraName];\n if (!cam) throw new AFSNotFoundError(ctx.path);\n\n const lines: string[] = [];\n lines.push(`Camera: ${cameraName}`);\n if (cam.detect) {\n lines.push(`Resolution: ${cam.detect.width}x${cam.detect.height} @ ${cam.detect.fps} FPS`);\n lines.push(`Detection: ${cam.detect.enabled ? \"enabled\" : \"disabled\"}`);\n }\n if (cam.record) {\n lines.push(`Recording: ${cam.record.enabled ? \"enabled\" : \"disabled\"}`);\n }\n if (cam.zones && Object.keys(cam.zones).length > 0) {\n lines.push(`Zones: ${Object.keys(cam.zones).join(\", \")}`);\n }\n\n return { content: lines.join(\"\\n\"), format: \"text\" };\n }\n\n @Explain(\"/:path*\")\n async explainGeneric(ctx: RouteContext<{ path?: string }>): Promise<AFSExplainResult> {\n const path = joinURL(\"/\", ctx.params.path ?? \"\");\n\n try {\n await this.statHandler(ctx);\n } catch {\n throw new AFSNotFoundError(path);\n }\n\n return { content: `Frigate NVR path: ${path}`, format: \"text\" };\n }\n\n // ============ Helpers ============\n\n private eventsToEntries(events: FrigateEvent[], basePath: string): AFSEntry[] {\n return events.map((event) => this.eventToEntry(event, basePath));\n }\n\n private eventToEntry(event: FrigateEvent, basePath: string): AFSEntry {\n const content = event.description || `${event.label} detected on ${event.camera}`;\n\n return this.buildEntry(joinURL(basePath, event.id), {\n id: event.id,\n content,\n meta: {\n kind: \"frigate:detection-event\",\n id: event.id,\n childrenCount: 0,\n label: event.label,\n score: event.score,\n camera: event.camera,\n topScore: event.top_score,\n zones: event.zones,\n startTime: event.start_time,\n endTime: event.end_time,\n hasClip: event.has_clip,\n hasSnapshot: event.has_snapshot,\n },\n });\n }\n\n private reviewsToEntries(reviews: FrigateReview[]): AFSEntry[] {\n return reviews.map((review) => this.reviewToEntry(review));\n }\n\n private reviewToEntry(review: FrigateReview): AFSEntry {\n return this.buildEntry(joinURL(\"/reviews\", review.id), {\n id: review.id,\n content: `Review: ${review.severity} on ${review.camera} (${review.data.objects.join(\", \")})`,\n meta: {\n kind: \"frigate:review\",\n id: review.id,\n childrenCount: 0,\n camera: review.camera,\n severity: review.severity,\n labels: review.data.objects,\n zones: review.data.zones,\n startTime: review.start_time,\n endTime: review.end_time,\n hasBeenReviewed: review.has_been_reviewed,\n },\n });\n }\n\n private buildActionEntry(\n basePath: string,\n name: string,\n description: string,\n inputSchema?: unknown,\n severity?: string,\n ): AFSEntry {\n return {\n id: name,\n path: joinURL(basePath, name),\n summary: name,\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n name,\n description,\n ...(severity ? { severity } : {}),\n ...(inputSchema ? { inputSchema } : {}),\n },\n };\n }\n\n private async toggleCameraFeature(\n cameraName: string,\n feature: string,\n enabled: boolean,\n path: string,\n ): Promise<AFSExecResult> {\n if (isPathTraversal(cameraName)) throw new AFSNotFoundError(path);\n\n const config = await this.client.getConfig();\n if (!config.cameras[cameraName]) throw new AFSNotFoundError(path);\n\n try {\n await this.client.postText(`/api/${cameraName}/${feature}/set`, enabled ? \"ON\" : \"OFF\");\n this.client.invalidateCache(\"/api/config\");\n return {\n success: true,\n data: { message: `${feature} ${enabled ? \"enabled\" : \"disabled\"} for ${cameraName}` },\n };\n } catch (error) {\n if (error instanceof FrigateApiError && error.code === \"AFS_NOT_FOUND\") {\n throw new AFSNotFoundError(path);\n }\n throw this.mapFrigateError(error, path);\n }\n }\n\n private arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = \"\";\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]!);\n }\n return btoa(binary);\n }\n\n private formatCameraName(name: string): string {\n return name\n .replace(/[_-]/g, \" \")\n .replace(/\\b\\w/g, (c) => c.toUpperCase())\n .trim();\n }\n\n private formatUptime(seconds: number): string {\n const days = Math.floor(seconds / 86400);\n const hours = Math.floor((seconds % 86400) / 3600);\n if (days > 0) return `${days} days${hours > 0 ? `, ${hours} hours` : \"\"}`;\n if (hours > 0) return `${hours} hours`;\n return `${Math.floor(seconds / 60)} minutes`;\n }\n\n private mapFrigateError(error: unknown, path: string): Error {\n if (error instanceof FrigateApiError) {\n if (error.code === \"AFS_NOT_FOUND\") {\n return new AFSNotFoundError(path);\n }\n const afsError = new Error(error.message);\n (afsError as any).code = error.code;\n return afsError;\n }\n return error instanceof Error ? error : new Error(\"Unknown error\");\n }\n}\n\nconst _typeCheck: AFSModuleClass<AFSFrigate, AFSFrigateOptions> = AFSFrigate;\n\nexport default AFSFrigate;\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aigne/afs-frigate",
|
|
3
|
+
"version": "1.11.0-beta.12",
|
|
4
|
+
"description": "AIGNE AFS provider for Frigate NVR — cameras, events, and recordings as filesystem",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"author": "Arcblock <blocklet@arcblock.io> https://github.com/arcblock",
|
|
10
|
+
"homepage": "https://github.com/arcblock/afs",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/arcblock/afs"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/arcblock/afs/issues"
|
|
17
|
+
},
|
|
18
|
+
"type": "module",
|
|
19
|
+
"main": "./dist/index.cjs",
|
|
20
|
+
"module": "./dist/index.mjs",
|
|
21
|
+
"types": "./dist/index.d.cts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"require": "./dist/index.cjs",
|
|
25
|
+
"import": "./dist/index.mjs"
|
|
26
|
+
},
|
|
27
|
+
"./*": "./*"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"LICENSE",
|
|
32
|
+
"README.md",
|
|
33
|
+
"CHANGELOG.md"
|
|
34
|
+
],
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"ufo": "^1.6.3",
|
|
37
|
+
"zod": "^4.0.0",
|
|
38
|
+
"@aigne/afs": "^1.11.0-beta.12"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/bun": "^1.3.6",
|
|
42
|
+
"npm-run-all": "^4.1.5",
|
|
43
|
+
"rimraf": "^6.1.2",
|
|
44
|
+
"tsdown": "0.20.0-beta.3",
|
|
45
|
+
"typescript": "5.9.2",
|
|
46
|
+
"@aigne/scripts": "0.0.0",
|
|
47
|
+
"@aigne/afs-testing": "1.11.0-beta.12",
|
|
48
|
+
"@aigne/typescript-config": "0.0.0"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsdown",
|
|
52
|
+
"check-types": "tsc --noEmit",
|
|
53
|
+
"clean": "rimraf dist coverage",
|
|
54
|
+
"test": "bun test",
|
|
55
|
+
"test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-reporter=text"
|
|
56
|
+
}
|
|
57
|
+
}
|