@camstack/core 0.1.13 → 0.1.15

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.
Files changed (161) hide show
  1. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +220 -0
  2. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js.map +1 -0
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +9 -0
  4. package/dist/builtins/addon-pages-aggregator/index.js +222 -0
  5. package/dist/builtins/addon-pages-aggregator/index.js.map +1 -0
  6. package/dist/builtins/addon-pages-aggregator/index.mjs +9 -0
  7. package/dist/builtins/addon-pages-aggregator/index.mjs.map +1 -0
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +200 -0
  9. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js.map +1 -0
  10. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +9 -0
  11. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs.map +1 -0
  12. package/dist/builtins/addon-widgets-aggregator/index.js +202 -0
  13. package/dist/builtins/addon-widgets-aggregator/index.js.map +1 -0
  14. package/dist/builtins/addon-widgets-aggregator/index.mjs +9 -0
  15. package/dist/builtins/addon-widgets-aggregator/index.mjs.map +1 -0
  16. package/dist/builtins/alerts/alerts.addon.js +443 -0
  17. package/dist/builtins/alerts/alerts.addon.js.map +1 -0
  18. package/dist/builtins/alerts/alerts.addon.mjs +9 -0
  19. package/dist/builtins/alerts/alerts.addon.mjs.map +1 -0
  20. package/dist/builtins/alerts/index.js +443 -0
  21. package/dist/builtins/alerts/index.js.map +1 -0
  22. package/dist/builtins/alerts/index.mjs +8 -0
  23. package/dist/builtins/alerts/index.mjs.map +1 -0
  24. package/dist/builtins/console-logging/index.js +242 -0
  25. package/dist/builtins/console-logging/index.js.map +1 -0
  26. package/dist/builtins/console-logging/index.mjs +11 -0
  27. package/dist/builtins/console-logging/index.mjs.map +1 -0
  28. package/dist/builtins/device-manager/device-manager.addon.js +2155 -0
  29. package/dist/builtins/device-manager/device-manager.addon.js.map +1 -0
  30. package/dist/builtins/device-manager/device-manager.addon.mjs +9 -0
  31. package/dist/builtins/device-manager/device-manager.addon.mjs.map +1 -0
  32. package/dist/builtins/device-manager/index.js +2157 -0
  33. package/dist/builtins/device-manager/index.js.map +1 -0
  34. package/dist/builtins/device-manager/index.mjs +10 -0
  35. package/dist/builtins/device-manager/index.mjs.map +1 -0
  36. package/dist/builtins/hub-forwarder/index.js +297 -0
  37. package/dist/builtins/hub-forwarder/index.js.map +1 -0
  38. package/dist/builtins/hub-forwarder/index.mjs +11 -0
  39. package/dist/builtins/hub-forwarder/index.mjs.map +1 -0
  40. package/dist/builtins/local-auth/index.js +623 -0
  41. package/dist/builtins/local-auth/index.js.map +1 -0
  42. package/dist/builtins/local-auth/index.mjs +8 -0
  43. package/dist/builtins/local-auth/index.mjs.map +1 -0
  44. package/dist/builtins/local-auth/local-auth.addon.js +623 -0
  45. package/dist/builtins/local-auth/local-auth.addon.js.map +1 -0
  46. package/dist/builtins/local-auth/local-auth.addon.mjs +9 -0
  47. package/dist/builtins/local-auth/local-auth.addon.mjs.map +1 -0
  48. package/dist/builtins/local-backup/index.js +53 -68
  49. package/dist/builtins/local-backup/index.js.map +1 -1
  50. package/dist/builtins/local-backup/index.mjs +1 -1
  51. package/dist/builtins/native-metrics/native-metrics.addon.js +898 -0
  52. package/dist/builtins/native-metrics/native-metrics.addon.js.map +1 -0
  53. package/dist/builtins/native-metrics/native-metrics.addon.mjs +7 -0
  54. package/dist/builtins/native-metrics/native-metrics.addon.mjs.map +1 -0
  55. package/dist/builtins/snapshot/index.js +504 -0
  56. package/dist/builtins/snapshot/index.js.map +1 -0
  57. package/dist/builtins/snapshot/index.mjs +477 -0
  58. package/dist/builtins/snapshot/index.mjs.map +1 -0
  59. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +16 -166
  60. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js.map +1 -1
  61. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  62. package/dist/builtins/sqlite-storage/index.js +554 -621
  63. package/dist/builtins/sqlite-storage/index.js.map +1 -1
  64. package/dist/builtins/sqlite-storage/index.mjs +9 -11
  65. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +368 -130
  66. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js.map +1 -1
  67. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
  68. package/dist/builtins/system-config/index.js +189 -0
  69. package/dist/builtins/system-config/index.js.map +1 -0
  70. package/dist/builtins/system-config/index.mjs +10 -0
  71. package/dist/builtins/system-config/index.mjs.map +1 -0
  72. package/dist/builtins/system-config/system-config.addon.js +187 -0
  73. package/dist/builtins/system-config/system-config.addon.js.map +1 -0
  74. package/dist/builtins/system-config/system-config.addon.mjs +9 -0
  75. package/dist/builtins/system-config/system-config.addon.mjs.map +1 -0
  76. package/dist/builtins/winston-logging/index.js +185 -65
  77. package/dist/builtins/winston-logging/index.js.map +1 -1
  78. package/dist/builtins/winston-logging/index.mjs +2 -1
  79. package/dist/chunk-2CIYKDRN.mjs +1 -0
  80. package/dist/chunk-2CIYKDRN.mjs.map +1 -0
  81. package/dist/chunk-2F76X6NL.mjs +136 -0
  82. package/dist/chunk-2F76X6NL.mjs.map +1 -0
  83. package/dist/chunk-2QUFBZ7M.mjs +1 -0
  84. package/dist/chunk-2QUFBZ7M.mjs.map +1 -0
  85. package/dist/chunk-3BK2Y7GY.mjs +593 -0
  86. package/dist/chunk-3BK2Y7GY.mjs.map +1 -0
  87. package/dist/chunk-4OOHFJHT.mjs +421 -0
  88. package/dist/chunk-4OOHFJHT.mjs.map +1 -0
  89. package/dist/chunk-4XHB7IHT.mjs +809 -0
  90. package/dist/chunk-4XHB7IHT.mjs.map +1 -0
  91. package/dist/{chunk-2F3XZYRW.mjs → chunk-6M2HSSTQ.mjs} +16 -7
  92. package/dist/chunk-6M2HSSTQ.mjs.map +1 -0
  93. package/dist/{chunk-SO4LROOT.mjs → chunk-7FI7SQS7.mjs} +54 -69
  94. package/dist/chunk-7FI7SQS7.mjs.map +1 -0
  95. package/dist/chunk-ED57RCQE.mjs +171 -0
  96. package/dist/chunk-ED57RCQE.mjs.map +1 -0
  97. package/dist/chunk-FZN56HGQ.mjs +626 -0
  98. package/dist/chunk-FZN56HGQ.mjs.map +1 -0
  99. package/dist/chunk-GL4OOB25.mjs +51 -0
  100. package/dist/chunk-GL4OOB25.mjs.map +1 -0
  101. package/dist/chunk-KDG2NTDB.mjs +137 -0
  102. package/dist/chunk-KDG2NTDB.mjs.map +1 -0
  103. package/dist/chunk-NRBQWBDM.mjs +191 -0
  104. package/dist/chunk-NRBQWBDM.mjs.map +1 -0
  105. package/dist/chunk-O4V246GG.mjs +2137 -0
  106. package/dist/chunk-O4V246GG.mjs.map +1 -0
  107. package/dist/chunk-QT57H266.mjs +163 -0
  108. package/dist/chunk-QT57H266.mjs.map +1 -0
  109. package/dist/chunk-QX4RH25I.mjs +141 -0
  110. package/dist/chunk-QX4RH25I.mjs.map +1 -0
  111. package/dist/chunk-TB562PZX.mjs +86 -0
  112. package/dist/chunk-TB562PZX.mjs.map +1 -0
  113. package/dist/chunk-TDYPZXK5.mjs +1 -0
  114. package/dist/chunk-TDYPZXK5.mjs.map +1 -0
  115. package/dist/chunk-UJI4LN5P.mjs +36 -0
  116. package/dist/chunk-UJI4LN5P.mjs.map +1 -0
  117. package/dist/chunk-W6RTHQGP.mjs +1 -0
  118. package/dist/chunk-W6RTHQGP.mjs.map +1 -0
  119. package/dist/chunk-ZELBCPDC.mjs +369 -0
  120. package/dist/chunk-ZELBCPDC.mjs.map +1 -0
  121. package/dist/index.d.mts +1103 -544
  122. package/dist/index.d.ts +1103 -544
  123. package/dist/index.js +7032 -6033
  124. package/dist/index.js.map +1 -1
  125. package/dist/index.mjs +568 -2226
  126. package/dist/index.mjs.map +1 -1
  127. package/dist/resource-monitor-UZUGPIAU.mjs +9 -0
  128. package/dist/resource-monitor-UZUGPIAU.mjs.map +1 -0
  129. package/dist/storage-location-manager-HFNB3PCS.mjs +7 -0
  130. package/dist/storage-location-manager-HFNB3PCS.mjs.map +1 -0
  131. package/package.json +123 -2
  132. package/dist/builtins/local-backup/index.d.mts +0 -42
  133. package/dist/builtins/local-backup/index.d.ts +0 -42
  134. package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.mts +0 -2
  135. package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.ts +0 -2
  136. package/dist/builtins/sqlite-storage/index.d.mts +0 -4
  137. package/dist/builtins/sqlite-storage/index.d.ts +0 -4
  138. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.mts +0 -2
  139. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +0 -2
  140. package/dist/builtins/winston-logging/index.d.mts +0 -30
  141. package/dist/builtins/winston-logging/index.d.ts +0 -30
  142. package/dist/chunk-2F3XZYRW.mjs.map +0 -1
  143. package/dist/chunk-LQFPAEQF.mjs +0 -147
  144. package/dist/chunk-LQFPAEQF.mjs.map +0 -1
  145. package/dist/chunk-R3DIIBBX.mjs +0 -532
  146. package/dist/chunk-R3DIIBBX.mjs.map +0 -1
  147. package/dist/chunk-SMNR44VG.mjs +0 -386
  148. package/dist/chunk-SMNR44VG.mjs.map +0 -1
  149. package/dist/chunk-SO4LROOT.mjs.map +0 -1
  150. package/dist/chunk-SPA4JBKN.mjs +0 -175
  151. package/dist/chunk-SPA4JBKN.mjs.map +0 -1
  152. package/dist/dist-3BY63UQ5.mjs +0 -2151
  153. package/dist/dist-3BY63UQ5.mjs.map +0 -1
  154. package/dist/filesystem-storage.addon-C42r589X.d.mts +0 -57
  155. package/dist/filesystem-storage.addon-C42r589X.d.ts +0 -57
  156. package/dist/sql-schema-CKz78rId.d.mts +0 -97
  157. package/dist/sql-schema-CKz78rId.d.ts +0 -97
  158. package/dist/sqlite-settings.addon-KwG-uKMP.d.mts +0 -79
  159. package/dist/sqlite-settings.addon-KwG-uKMP.d.ts +0 -79
  160. package/dist/storage-location-manager-KKDQNAKA.mjs +0 -7
  161. /package/dist/{storage-location-manager-KKDQNAKA.mjs.map → builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs.map} +0 -0
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/storage/fs-storage-backend.ts","../src/storage/storage-location-manager.ts","../../../node_modules/node_modules/.pnpm/@oxc-project+runtime@0.72.2/node_modules/@oxc-project/runtime/src/helpers/typeof.js","../../../node_modules/node_modules/.pnpm/@oxc-project+runtime@0.72.2/node_modules/@oxc-project/runtime/src/helpers/toPrimitive.js","../../../node_modules/node_modules/.pnpm/@oxc-project+runtime@0.72.2/node_modules/@oxc-project/runtime/src/helpers/toPropertyKey.js","../../../node_modules/node_modules/.pnpm/@oxc-project+runtime@0.72.2/node_modules/@oxc-project/runtime/src/helpers/defineProperty.js","../../../node_modules/node_modules/.pnpm/@oxc-project+runtime@0.72.2/node_modules/@oxc-project/runtime/src/helpers/objectSpread2.js","../../../node_modules/@trpc/client/src/links/internals/createChain.ts","../../../node_modules/@trpc/client/src/links/splitLink.ts","../../../node_modules/@trpc/client/src/TRPCClientError.ts","../../../node_modules/@trpc/client/src/internals/transformer.ts","../../../node_modules/@trpc/client/src/getFetch.ts","../../../node_modules/@trpc/client/src/links/internals/httpUtils.ts","../../../node_modules/@trpc/client/src/links/internals/contentTypes.ts","../../../node_modules/@trpc/client/src/links/httpLink.ts","../../../node_modules/@trpc/client/src/internals/dataLoader.ts","../../../node_modules/@trpc/client/src/internals/signals.ts","../../../node_modules/@trpc/client/src/links/httpBatchLink.ts","../../../node_modules/@trpc/client/src/links/loggerLink.ts","../../../node_modules/@trpc/client/src/links/wsLink/wsClient/encoder.ts","../../../node_modules/@trpc/client/src/links/wsLink/wsClient/options.ts","../../../node_modules/@trpc/client/src/links/internals/urlWithConnectionParams.ts","../../../node_modules/@trpc/client/src/links/wsLink/wsClient/utils.ts","../../../node_modules/@trpc/client/src/links/wsLink/wsClient/requestManager.ts","../../../node_modules/@trpc/client/src/links/wsLink/wsClient/wsConnection.ts","../../../node_modules/@trpc/client/src/links/wsLink/wsClient/wsClient.ts","../../../node_modules/@trpc/client/src/links/wsLink/createWsClient.ts","../../../node_modules/@trpc/client/src/links/wsLink/wsLink.ts","../../../node_modules/@trpc/client/src/internals/TRPCUntypedClient.ts","../../../node_modules/@trpc/client/src/createTRPCUntypedClient.ts","../../../node_modules/@trpc/client/src/createTRPCClient.ts","../../../node_modules/@trpc/client/src/links/httpBatchStreamLink.ts","../../../node_modules/@trpc/client/src/internals/inputWithTrackedEventId.ts","../../../node_modules/node_modules/.pnpm/@oxc-project+runtime@0.72.2/node_modules/@oxc-project/runtime/src/helpers/asyncIterator.js","../../../node_modules/@trpc/client/src/links/httpSubscriptionLink.ts","../../../node_modules/@trpc/client/src/links/retryLink.ts","../../../node_modules/node_modules/.pnpm/@oxc-project+runtime@0.72.2/node_modules/@oxc-project/runtime/src/helpers/usingCtx.js","../../../node_modules/node_modules/.pnpm/@oxc-project+runtime@0.72.2/node_modules/@oxc-project/runtime/src/helpers/OverloadYield.js","../../../node_modules/node_modules/.pnpm/@oxc-project+runtime@0.72.2/node_modules/@oxc-project/runtime/src/helpers/awaitAsyncGenerator.js","../../../node_modules/node_modules/.pnpm/@oxc-project+runtime@0.72.2/node_modules/@oxc-project/runtime/src/helpers/wrapAsyncGenerator.js","../../../node_modules/@trpc/client/src/links/localLink.ts","../src/index.ts","../src/deps/binary-downloader.ts","../src/deps/ffmpeg-downloader.ts","../src/deps/python-downloader.ts","../src/events/event-bus.ts","../src/download/model-downloader.ts","../src/download/model-download-service.ts","../src/python/python-env-manager.ts","../src/pipeline/pipeline-validator.ts","../src/pipeline/pipeline-runner.ts","../src/process/managed-process.ts","../src/process/process-manager.ts","../src/network/network-quality.ts","../src/repl/repl-engine.ts","../src/agent/agent-registry.ts","../src/agent/task-dispatcher.ts","../src/agent/agent-client.ts","../src/agent/agent-task-runner.ts","../src/agent/pipeline-task-handlers.ts","../src/builtins/sqlite-storage/filesystem-storage-provider.ts","../src/builtins/sqlite-storage/sqlite-settings-backend.ts","../src/builtins/sqlite-storage/sqlite-storage.provider.ts","../src/builtins/sqlite-storage/sqlite-storage.addon.ts","../src/builtins/sqlite-storage/settings-store.ts","../src/builtins/sqlite-storage/sql-schema.ts","../src/builtins/winston-logging/winston-destination.ts","../src/builtins/winston-logging/winston-logging.addon.ts","../src/builtins/local-backup/local-backup.ts","../src/builtins/local-backup/local-backup.addon.ts","../src/lifecycle/lifecycle-state-machine.ts","../src/feature/feature-manager.ts","../src/events/system-event-bus.ts","../src/logging/log-ring-buffer.ts","../src/logging/scoped-logger.ts","../src/logging/log-manager.ts","../src/storage/storage-manager.ts","../src/auth/auth-manager.ts","../src/auth/api-key-manager.ts","../src/auth/user-manager.ts","../src/auth/scoped-token-manager.ts","../src/notification/notification-service.ts","../src/notification/toast-service.ts","../src/addon-routes/addon-route-registry.ts","../src/device/device-registry.ts","../src/device/capability-resolver.ts","../src/tls/cert-manager.ts","../src/addon/addon-api-factory.ts","../src/platform/platform-scorer.ts","../src/platform/inference-config-resolver.ts","../src/builtins/sqlite-storage/integration-registry.ts","../src/provider/provider-manager.ts"],"sourcesContent":["import { existsSync, mkdirSync, accessSync, constants } from 'node:fs'\nimport { join, resolve, isAbsolute } from 'node:path'\n\nexport interface IStorageBackend {\n /** Backend type identifier */\n readonly type: string\n /** Base path of this backend */\n readonly basePath: string\n /** Resolve a subpath to an absolute path */\n resolve(subpath: string): string\n /** Check if the backend path exists and is writable */\n isAvailable(): boolean\n /** Ensure base directory exists (mkdir -p equivalent) */\n initialize(): Promise<void>\n}\n\nexport class FsStorageBackend implements IStorageBackend {\n readonly type = 'local'\n readonly basePath: string\n\n constructor(basePath: string) {\n this.basePath = resolve(basePath)\n }\n\n resolve(subpath: string): string {\n if (isAbsolute(subpath)) return subpath\n return join(this.basePath, subpath)\n }\n\n isAvailable(): boolean {\n try {\n if (!existsSync(this.basePath)) return false\n accessSync(this.basePath, constants.W_OK)\n return true\n } catch {\n return false\n }\n }\n\n async initialize(): Promise<void> {\n mkdirSync(this.basePath, { recursive: true })\n }\n}\n","import { join, isAbsolute } from 'node:path'\nimport { FsStorageBackend, type IStorageBackend } from './fs-storage-backend.js'\n\nexport type StorageLocationName = 'data' | 'media' | 'recordings' | 'models' | 'cache' | 'logs'\n\nexport class StorageLocationManager {\n private readonly backends: Map<StorageLocationName, IStorageBackend> = new Map()\n private readonly dataPath: string\n\n constructor(dataPath: string) {\n this.dataPath = dataPath\n }\n\n /** Initialize all locations with default paths */\n async initializeDefaults(): Promise<void> {\n const defaults: Record<StorageLocationName, string> = {\n data: join(this.dataPath, 'db'),\n media: join(this.dataPath, 'media'),\n recordings: join(this.dataPath, 'recordings'),\n models: join(this.dataPath, 'models'),\n cache: '/tmp/camstack-cache',\n logs: join(this.dataPath, 'logs'),\n }\n\n for (const [name, path] of Object.entries(defaults)) {\n const backend = new FsStorageBackend(path)\n await backend.initialize()\n this.backends.set(name as StorageLocationName, backend)\n }\n }\n\n /** Override a specific location's backend path */\n async setLocationPath(name: StorageLocationName, basePath: string): Promise<void> {\n const resolved = isAbsolute(basePath) ? basePath : join(this.dataPath, basePath)\n const backend = new FsStorageBackend(resolved)\n await backend.initialize()\n this.backends.set(name, backend)\n }\n\n /** Get the backend for a location */\n getBackend(name: StorageLocationName): IStorageBackend {\n const backend = this.backends.get(name)\n if (!backend) throw new Error(`Storage location \"${name}\" not initialized`)\n return backend\n }\n\n /** Resolve a path within a location */\n resolve(location: StorageLocationName, subpath: string): string {\n return this.getBackend(location).resolve(subpath)\n }\n\n /** Check if all locations are available */\n getStatus(): Array<{ name: StorageLocationName; available: boolean; path: string }> {\n return Array.from(this.backends.entries()).map(([name, backend]) => ({\n name,\n available: backend.isAvailable(),\n path: backend.basePath,\n }))\n }\n\n /** All location names */\n getLocationNames(): StorageLocationName[] {\n return Array.from(this.backends.keys())\n }\n}\n","function _typeof(o) {\n \"@babel/helpers - typeof\";\n\n return module.exports = _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (o) {\n return typeof o;\n } : function (o) {\n return o && \"function\" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? \"symbol\" : typeof o;\n }, module.exports.__esModule = true, module.exports[\"default\"] = module.exports, _typeof(o);\n}\nmodule.exports = _typeof, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var _typeof = require(\"./typeof.js\")[\"default\"];\nfunction toPrimitive(t, r) {\n if (\"object\" != _typeof(t) || !t) return t;\n var e = t[Symbol.toPrimitive];\n if (void 0 !== e) {\n var i = e.call(t, r || \"default\");\n if (\"object\" != _typeof(i)) return i;\n throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n }\n return (\"string\" === r ? String : Number)(t);\n}\nmodule.exports = toPrimitive, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var _typeof = require(\"./typeof.js\")[\"default\"];\nvar toPrimitive = require(\"./toPrimitive.js\");\nfunction toPropertyKey(t) {\n var i = toPrimitive(t, \"string\");\n return \"symbol\" == _typeof(i) ? i : i + \"\";\n}\nmodule.exports = toPropertyKey, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var toPropertyKey = require(\"./toPropertyKey.js\");\nfunction _defineProperty(e, r, t) {\n return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {\n value: t,\n enumerable: !0,\n configurable: !0,\n writable: !0\n }) : e[r] = t, e;\n}\nmodule.exports = _defineProperty, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var defineProperty = require(\"./defineProperty.js\");\nfunction ownKeys(e, r) {\n var t = Object.keys(e);\n if (Object.getOwnPropertySymbols) {\n var o = Object.getOwnPropertySymbols(e);\n r && (o = o.filter(function (r) {\n return Object.getOwnPropertyDescriptor(e, r).enumerable;\n })), t.push.apply(t, o);\n }\n return t;\n}\nfunction _objectSpread2(e) {\n for (var r = 1; r < arguments.length; r++) {\n var t = null != arguments[r] ? arguments[r] : {};\n r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {\n defineProperty(e, r, t[r]);\n }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {\n Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));\n });\n }\n return e;\n}\nmodule.exports = _objectSpread2, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","import { observable } from '@trpc/server/observable';\nimport type { AnyRouter } from '@trpc/server/unstable-core-do-not-import';\nimport type {\n Operation,\n OperationLink,\n OperationResultObservable,\n} from '../types';\n\n/** @internal */\nexport function createChain<\n TRouter extends AnyRouter,\n TInput = unknown,\n TOutput = unknown,\n>(opts: {\n links: OperationLink<TRouter, TInput, TOutput>[];\n op: Operation<TInput>;\n}): OperationResultObservable<TRouter, TOutput> {\n return observable((observer) => {\n function execute(index = 0, op = opts.op) {\n const next = opts.links[index];\n if (!next) {\n throw new Error(\n 'No more links to execute - did you forget to add an ending link?',\n );\n }\n const subscription = next({\n op,\n next(nextOp) {\n const nextObserver = execute(index + 1, nextOp);\n\n return nextObserver;\n },\n });\n return subscription;\n }\n\n const obs$ = execute();\n return obs$.subscribe(observer);\n });\n}\n","import { observable } from '@trpc/server/observable';\nimport type { AnyRouter } from '@trpc/server/unstable-core-do-not-import';\nimport { createChain } from './internals/createChain';\nimport type { Operation, TRPCLink } from './types';\n\nfunction asArray<TType>(value: TType | TType[]) {\n return Array.isArray(value) ? value : [value];\n}\nexport function splitLink<TRouter extends AnyRouter = AnyRouter>(opts: {\n condition: (op: Operation) => boolean;\n /**\n * The link to execute next if the test function returns `true`.\n */\n true: TRPCLink<TRouter> | TRPCLink<TRouter>[];\n /**\n * The link to execute next if the test function returns `false`.\n */\n false: TRPCLink<TRouter> | TRPCLink<TRouter>[];\n}): TRPCLink<TRouter> {\n return (runtime) => {\n const yes = asArray(opts.true).map((link) => link(runtime));\n const no = asArray(opts.false).map((link) => link(runtime));\n return (props) => {\n return observable((observer) => {\n const links = opts.condition(props.op) ? yes : no;\n return createChain({ op: props.op, links }).subscribe(observer);\n });\n };\n };\n}\n","import type {\n inferClientTypes,\n InferrableClientTypes,\n Maybe,\n TRPCErrorResponse,\n} from '@trpc/server/unstable-core-do-not-import';\nimport {\n isObject,\n type DefaultErrorShape,\n} from '@trpc/server/unstable-core-do-not-import';\n\ntype inferErrorShape<TInferrable extends InferrableClientTypes> =\n inferClientTypes<TInferrable>['errorShape'];\nexport interface TRPCClientErrorBase<TShape extends DefaultErrorShape> {\n readonly message: string;\n readonly shape: Maybe<TShape>;\n readonly data: Maybe<TShape['data']>;\n}\nexport type TRPCClientErrorLike<TInferrable extends InferrableClientTypes> =\n TRPCClientErrorBase<inferErrorShape<TInferrable>>;\n\nexport function isTRPCClientError<TInferrable extends InferrableClientTypes>(\n cause: unknown,\n): cause is TRPCClientError<TInferrable> {\n return cause instanceof TRPCClientError;\n}\n\nfunction isTRPCErrorResponse(obj: unknown): obj is TRPCErrorResponse<any> {\n return (\n isObject(obj) &&\n isObject(obj['error']) &&\n typeof obj['error']['code'] === 'number' &&\n typeof obj['error']['message'] === 'string'\n );\n}\n\nfunction getMessageFromUnknownError(err: unknown, fallback: string): string {\n if (typeof err === 'string') {\n return err;\n }\n if (isObject(err) && typeof err['message'] === 'string') {\n return err['message'];\n }\n return fallback;\n}\n\nexport class TRPCClientError<TRouterOrProcedure extends InferrableClientTypes>\n extends Error\n implements TRPCClientErrorBase<inferErrorShape<TRouterOrProcedure>>\n{\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore override doesn't work in all environments due to \"This member cannot have an 'override' modifier because it is not declared in the base class 'Error'\"\n public override readonly cause;\n public readonly shape: Maybe<inferErrorShape<TRouterOrProcedure>>;\n public readonly data: Maybe<inferErrorShape<TRouterOrProcedure>['data']>;\n\n /**\n * Additional meta data about the error\n * In the case of HTTP-errors, we'll have `response` and potentially `responseJSON` here\n */\n public meta;\n\n constructor(\n message: string,\n opts?: {\n result?: Maybe<TRPCErrorResponse<inferErrorShape<TRouterOrProcedure>>>;\n cause?: Error;\n meta?: Record<string, unknown>;\n },\n ) {\n const cause = opts?.cause;\n\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore https://github.com/tc39/proposal-error-cause\n super(message, { cause });\n\n this.meta = opts?.meta;\n\n this.cause = cause;\n this.shape = opts?.result?.error;\n this.data = opts?.result?.error.data;\n this.name = 'TRPCClientError';\n\n Object.setPrototypeOf(this, TRPCClientError.prototype);\n }\n\n public static from<TRouterOrProcedure extends InferrableClientTypes>(\n _cause: Error | TRPCErrorResponse<any> | object,\n opts: { meta?: Record<string, unknown>; cause?: Error } = {},\n ): TRPCClientError<TRouterOrProcedure> {\n const cause = _cause as unknown;\n\n if (isTRPCClientError(cause)) {\n if (opts.meta) {\n // Decorate with meta error data\n cause.meta = {\n ...cause.meta,\n ...opts.meta,\n };\n }\n return cause;\n }\n if (isTRPCErrorResponse(cause)) {\n return new TRPCClientError(cause.error.message, {\n ...opts,\n result: cause,\n cause: opts.cause,\n });\n }\n return new TRPCClientError(\n getMessageFromUnknownError(cause, 'Unknown error'),\n {\n ...opts,\n cause: cause as any,\n },\n );\n }\n}\n","import type {\n AnyClientTypes,\n CombinedDataTransformer,\n DataTransformerOptions,\n TypeError,\n} from '@trpc/server/unstable-core-do-not-import';\n\n/**\n * @internal\n */\nexport type CoercedTransformerParameters = {\n transformer?: DataTransformerOptions;\n};\n\ntype TransformerOptionYes = {\n /**\n * Data transformer\n *\n * You must use the same transformer on the backend and frontend\n * @see https://trpc.io/docs/v11/data-transformers\n **/\n transformer: DataTransformerOptions;\n};\ntype TransformerOptionNo = {\n /**\n * Data transformer\n *\n * You must use the same transformer on the backend and frontend\n * @see https://trpc.io/docs/v11/data-transformers\n **/\n transformer?: TypeError<'You must define a transformer on your your `initTRPC`-object first'>;\n};\n\n/**\n * @internal\n */\nexport type TransformerOptions<\n TRoot extends Pick<AnyClientTypes, 'transformer'>,\n> = TRoot['transformer'] extends true\n ? TransformerOptionYes\n : TransformerOptionNo;\n/**\n * @internal\n */\n\n/**\n * @internal\n */\nexport function getTransformer(\n transformer:\n | TransformerOptions<{ transformer: false }>['transformer']\n | TransformerOptions<{ transformer: true }>['transformer']\n | undefined,\n): CombinedDataTransformer {\n const _transformer =\n transformer as CoercedTransformerParameters['transformer'];\n if (!_transformer) {\n return {\n input: {\n serialize: (data) => data,\n deserialize: (data) => data,\n },\n output: {\n serialize: (data) => data,\n deserialize: (data) => data,\n },\n };\n }\n if ('input' in _transformer) {\n return _transformer;\n }\n return {\n input: _transformer,\n output: _transformer,\n };\n}\n","import type { FetchEsque, NativeFetchEsque } from './internals/types';\n\ntype AnyFn = (...args: any[]) => unknown;\n\nconst isFunction = (fn: unknown): fn is AnyFn => typeof fn === 'function';\n\nexport function getFetch(\n customFetchImpl?: FetchEsque | NativeFetchEsque,\n): FetchEsque {\n if (customFetchImpl) {\n return customFetchImpl as FetchEsque;\n }\n\n if (typeof window !== 'undefined' && isFunction(window.fetch)) {\n return window.fetch as FetchEsque;\n }\n\n if (typeof globalThis !== 'undefined' && isFunction(globalThis.fetch)) {\n return globalThis.fetch as FetchEsque;\n }\n\n throw new Error('No fetch implementation found');\n}\n","import type {\n AnyClientTypes,\n CombinedDataTransformer,\n Maybe,\n ProcedureType,\n TRPCAcceptHeader,\n TRPCResponse,\n} from '@trpc/server/unstable-core-do-not-import';\nimport { getFetch } from '../../getFetch';\nimport type {\n FetchEsque,\n RequestInitEsque,\n ResponseEsque,\n} from '../../internals/types';\nimport type { TransformerOptions } from '../../unstable-internals';\nimport { getTransformer } from '../../unstable-internals';\nimport type { HTTPHeaders } from '../types';\n\n/**\n * @internal\n */\nexport type HTTPLinkBaseOptions<\n TRoot extends Pick<AnyClientTypes, 'transformer'>,\n> = {\n url: string | URL;\n /**\n * Add ponyfill for fetch\n */\n fetch?: FetchEsque;\n /**\n * Send all requests `as POST`s requests regardless of the procedure type\n * The HTTP handler must separately allow overriding the method. See:\n * @see https://trpc.io/docs/rpc\n */\n methodOverride?: 'POST';\n} & TransformerOptions<TRoot>;\n\nexport interface ResolvedHTTPLinkOptions {\n url: string;\n fetch?: FetchEsque;\n transformer: CombinedDataTransformer;\n methodOverride?: 'POST';\n}\n\nexport function resolveHTTPLinkOptions(\n opts: HTTPLinkBaseOptions<AnyClientTypes>,\n): ResolvedHTTPLinkOptions {\n return {\n url: opts.url.toString(),\n fetch: opts.fetch,\n transformer: getTransformer(opts.transformer),\n methodOverride: opts.methodOverride,\n };\n}\n\n// https://github.com/trpc/trpc/pull/669\nfunction arrayToDict(array: unknown[]) {\n const dict: Record<number, unknown> = {};\n for (let index = 0; index < array.length; index++) {\n const element = array[index];\n dict[index] = element;\n }\n return dict;\n}\n\nconst METHOD = {\n query: 'GET',\n mutation: 'POST',\n subscription: 'PATCH',\n} as const;\n\nexport interface HTTPResult {\n json: TRPCResponse;\n meta: {\n response: ResponseEsque;\n responseJSON?: unknown;\n };\n}\n\ntype GetInputOptions = {\n transformer: CombinedDataTransformer;\n} & ({ input: unknown } | { inputs: unknown[] });\n\nexport function getInput(opts: GetInputOptions) {\n return 'input' in opts\n ? opts.transformer.input.serialize(opts.input)\n : arrayToDict(\n opts.inputs.map((_input) => opts.transformer.input.serialize(_input)),\n );\n}\n\nexport type HTTPBaseRequestOptions = GetInputOptions &\n ResolvedHTTPLinkOptions & {\n type: ProcedureType;\n path: string;\n signal: Maybe<AbortSignal>;\n };\n\ntype GetUrl = (opts: HTTPBaseRequestOptions) => string;\ntype GetBody = (opts: HTTPBaseRequestOptions) => RequestInitEsque['body'];\n\nexport type ContentOptions = {\n trpcAcceptHeader?: TRPCAcceptHeader;\n trpcAcceptHeaderKey?: 'trpc-accept' | 'accept';\n contentTypeHeader?: string;\n getUrl: GetUrl;\n getBody: GetBody;\n};\n\nexport const getUrl: GetUrl = (opts) => {\n const parts = opts.url.split('?') as [string, string?];\n const base = parts[0].replace(/\\/$/, ''); // Remove any trailing slashes\n\n let url = base + '/' + opts.path;\n const queryParts: string[] = [];\n\n if (parts[1]) {\n queryParts.push(parts[1]);\n }\n if ('inputs' in opts) {\n queryParts.push('batch=1');\n }\n if (opts.type === 'query' || opts.type === 'subscription') {\n const input = getInput(opts);\n if (input !== undefined && opts.methodOverride !== 'POST') {\n queryParts.push(`input=${encodeURIComponent(JSON.stringify(input))}`);\n }\n }\n if (queryParts.length) {\n url += '?' + queryParts.join('&');\n }\n return url;\n};\n\nexport const getBody: GetBody = (opts) => {\n if (opts.type === 'query' && opts.methodOverride !== 'POST') {\n return undefined;\n }\n const input = getInput(opts);\n return input !== undefined ? JSON.stringify(input) : undefined;\n};\n\nexport type Requester = (\n opts: HTTPBaseRequestOptions & {\n headers: () => HTTPHeaders | Promise<HTTPHeaders>;\n },\n) => Promise<HTTPResult>;\n\nexport const jsonHttpRequester: Requester = (opts) => {\n return httpRequest({\n ...opts,\n contentTypeHeader: 'application/json',\n getUrl,\n getBody,\n });\n};\n\n/**\n * Polyfill for DOMException with AbortError name\n */\nclass AbortError extends Error {\n constructor() {\n const name = 'AbortError';\n super(name);\n this.name = name;\n this.message = name;\n }\n}\n\nexport type HTTPRequestOptions = ContentOptions &\n HTTPBaseRequestOptions & {\n headers: () => HTTPHeaders | Promise<HTTPHeaders>;\n };\n\n/**\n * Polyfill for `signal.throwIfAborted()`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted\n */\nconst throwIfAborted = (signal: Maybe<AbortSignal>) => {\n if (!signal?.aborted) {\n return;\n }\n // If available, use the native implementation\n signal.throwIfAborted?.();\n\n // If we have `DOMException`, use it\n if (typeof DOMException !== 'undefined') {\n throw new DOMException('AbortError', 'AbortError');\n }\n\n // Otherwise, use our own implementation\n throw new AbortError();\n};\n\nexport async function fetchHTTPResponse(opts: HTTPRequestOptions) {\n throwIfAborted(opts.signal);\n\n const url = opts.getUrl(opts);\n const body = opts.getBody(opts);\n const method = opts.methodOverride ?? METHOD[opts.type];\n const resolvedHeaders = await (async () => {\n const heads = await opts.headers();\n if (Symbol.iterator in heads) {\n return Object.fromEntries(heads);\n }\n return heads;\n })();\n const headers = {\n ...(opts.contentTypeHeader && method !== 'GET'\n ? { 'content-type': opts.contentTypeHeader }\n : {}),\n ...(opts.trpcAcceptHeader\n ? { [opts.trpcAcceptHeaderKey ?? 'trpc-accept']: opts.trpcAcceptHeader }\n : undefined),\n ...resolvedHeaders,\n };\n\n return getFetch(opts.fetch)(url, {\n method,\n signal: opts.signal,\n body,\n headers,\n });\n}\n\nexport async function httpRequest(\n opts: HTTPRequestOptions,\n): Promise<HTTPResult> {\n const meta = {} as HTTPResult['meta'];\n\n const res = await fetchHTTPResponse(opts);\n meta.response = res;\n\n const json = await res.json();\n\n meta.responseJSON = json;\n\n return {\n json: json as TRPCResponse,\n meta,\n };\n}\n","export function isOctetType(\n input: unknown,\n): input is Uint8Array<ArrayBuffer> | Blob {\n return (\n input instanceof Uint8Array ||\n // File extends from Blob but is only available in nodejs from v20\n input instanceof Blob\n );\n}\n\nexport function isFormData(input: unknown) {\n return input instanceof FormData;\n}\n\nexport function isNonJsonSerializable(input: unknown) {\n return isOctetType(input) || isFormData(input);\n}\n","import { observable } from '@trpc/server/observable';\nimport type {\n AnyClientTypes,\n AnyRouter,\n} from '@trpc/server/unstable-core-do-not-import';\nimport { transformResult } from '@trpc/server/unstable-core-do-not-import';\nimport { TRPCClientError } from '../TRPCClientError';\nimport type {\n HTTPLinkBaseOptions,\n HTTPResult,\n Requester,\n} from './internals/httpUtils';\nimport {\n getUrl,\n httpRequest,\n jsonHttpRequester,\n resolveHTTPLinkOptions,\n} from './internals/httpUtils';\nimport {\n isFormData,\n isOctetType,\n type HTTPHeaders,\n type Operation,\n type TRPCLink,\n} from './types';\n\nexport type HTTPLinkOptions<TRoot extends AnyClientTypes> =\n HTTPLinkBaseOptions<TRoot> & {\n /**\n * Headers to be set on outgoing requests or a callback that of said headers\n * @see http://trpc.io/docs/client/headers\n */\n headers?:\n | HTTPHeaders\n | ((opts: { op: Operation }) => HTTPHeaders | Promise<HTTPHeaders>);\n };\n\nconst universalRequester: Requester = (opts) => {\n if ('input' in opts) {\n const { input } = opts;\n if (isFormData(input)) {\n if (opts.type !== 'mutation' && opts.methodOverride !== 'POST') {\n throw new Error('FormData is only supported for mutations');\n }\n\n return httpRequest({\n ...opts,\n // The browser will set this automatically and include the boundary= in it\n contentTypeHeader: undefined,\n getUrl,\n getBody: () => input,\n });\n }\n\n if (isOctetType(input)) {\n if (opts.type !== 'mutation' && opts.methodOverride !== 'POST') {\n throw new Error('Octet type input is only supported for mutations');\n }\n\n return httpRequest({\n ...opts,\n contentTypeHeader: 'application/octet-stream',\n getUrl,\n getBody: () => input,\n });\n }\n }\n\n return jsonHttpRequester(opts);\n};\n\n/**\n * @see https://trpc.io/docs/client/links/httpLink\n */\nexport function httpLink<TRouter extends AnyRouter = AnyRouter>(\n opts: HTTPLinkOptions<TRouter['_def']['_config']['$types']>,\n): TRPCLink<TRouter> {\n const resolvedOpts = resolveHTTPLinkOptions(opts);\n return () => {\n return (operationOpts) => {\n const { op } = operationOpts;\n return observable((observer) => {\n const { path, input, type } = op;\n /* istanbul ignore if -- @preserve */\n if (type === 'subscription') {\n throw new Error(\n 'Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`',\n );\n }\n\n const request = universalRequester({\n ...resolvedOpts,\n type,\n path,\n input,\n signal: op.signal,\n headers() {\n if (!opts.headers) {\n return {};\n }\n if (typeof opts.headers === 'function') {\n return opts.headers({\n op,\n });\n }\n return opts.headers;\n },\n });\n let meta: HTTPResult['meta'] | undefined = undefined;\n request\n .then((res) => {\n meta = res.meta;\n const transformed = transformResult(\n res.json,\n resolvedOpts.transformer.output,\n );\n\n if (!transformed.ok) {\n observer.error(\n TRPCClientError.from(transformed.error, {\n meta,\n }),\n );\n return;\n }\n observer.next({\n context: res.meta,\n result: transformed.result,\n });\n observer.complete();\n })\n .catch((cause) => {\n observer.error(TRPCClientError.from(cause, { meta }));\n });\n\n return () => {\n // noop\n };\n });\n };\n };\n}\n","/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\ntype BatchItem<TKey, TValue> = {\n aborted: boolean;\n key: TKey;\n resolve: ((value: TValue) => void) | null;\n reject: ((error: Error) => void) | null;\n batch: Batch<TKey, TValue> | null;\n};\ntype Batch<TKey, TValue> = {\n items: BatchItem<TKey, TValue>[];\n};\nexport type BatchLoader<TKey, TValue> = {\n validate: (keys: TKey[]) => boolean;\n fetch: (keys: TKey[]) => Promise<TValue[] | Promise<TValue>[]>;\n};\n\n/**\n * A function that should never be called unless we messed something up.\n */\nconst throwFatalError = () => {\n throw new Error(\n 'Something went wrong. Please submit an issue at https://github.com/trpc/trpc/issues/new',\n );\n};\n\n/**\n * Dataloader that's very inspired by https://github.com/graphql/dataloader\n * Less configuration, no caching, and allows you to cancel requests\n * When cancelling a single fetch the whole batch will be cancelled only when _all_ items are cancelled\n */\nexport function dataLoader<TKey, TValue>(\n batchLoader: BatchLoader<TKey, TValue>,\n) {\n let pendingItems: BatchItem<TKey, TValue>[] | null = null;\n let dispatchTimer: ReturnType<typeof setTimeout> | null = null;\n\n const destroyTimerAndPendingItems = () => {\n clearTimeout(dispatchTimer as any);\n dispatchTimer = null;\n pendingItems = null;\n };\n\n /**\n * Iterate through the items and split them into groups based on the `batchLoader`'s validate function\n */\n function groupItems(items: BatchItem<TKey, TValue>[]) {\n const groupedItems: BatchItem<TKey, TValue>[][] = [[]];\n let index = 0;\n while (true) {\n const item = items[index];\n if (!item) {\n // we're done\n break;\n }\n const lastGroup = groupedItems[groupedItems.length - 1]!;\n\n if (item.aborted) {\n // Item was aborted before it was dispatched\n item.reject?.(new Error('Aborted'));\n index++;\n continue;\n }\n\n const isValid = batchLoader.validate(\n lastGroup.concat(item).map((it) => it.key),\n );\n\n if (isValid) {\n lastGroup.push(item);\n index++;\n continue;\n }\n\n if (lastGroup.length === 0) {\n item.reject?.(new Error('Input is too big for a single dispatch'));\n index++;\n continue;\n }\n // Create new group, next iteration will try to add the item to that\n groupedItems.push([]);\n }\n return groupedItems;\n }\n\n function dispatch() {\n const groupedItems = groupItems(pendingItems!);\n destroyTimerAndPendingItems();\n\n // Create batches for each group of items\n for (const items of groupedItems) {\n if (!items.length) {\n continue;\n }\n const batch: Batch<TKey, TValue> = {\n items,\n };\n for (const item of items) {\n item.batch = batch;\n }\n const promise = batchLoader.fetch(batch.items.map((_item) => _item.key));\n\n promise\n .then(async (result) => {\n await Promise.all(\n result.map(async (valueOrPromise, index) => {\n const item = batch.items[index]!;\n try {\n const value = await Promise.resolve(valueOrPromise);\n\n item.resolve?.(value);\n } catch (cause) {\n item.reject?.(cause as Error);\n }\n\n item.batch = null;\n item.reject = null;\n item.resolve = null;\n }),\n );\n\n for (const item of batch.items) {\n item.reject?.(new Error('Missing result'));\n item.batch = null;\n }\n })\n .catch((cause) => {\n for (const item of batch.items) {\n item.reject?.(cause);\n item.batch = null;\n }\n });\n }\n }\n function load(key: TKey): Promise<TValue> {\n const item: BatchItem<TKey, TValue> = {\n aborted: false,\n key,\n batch: null,\n resolve: throwFatalError,\n reject: throwFatalError,\n };\n\n const promise = new Promise<TValue>((resolve, reject) => {\n item.reject = reject;\n item.resolve = resolve;\n\n pendingItems ??= [];\n pendingItems.push(item);\n });\n\n dispatchTimer ??= setTimeout(dispatch);\n\n return promise;\n }\n\n return {\n load,\n };\n}\n","import type { Maybe } from '@trpc/server/unstable-core-do-not-import';\n\n/**\n * Like `Promise.all()` but for abort signals\n * - When all signals have been aborted, the merged signal will be aborted\n * - If one signal is `null`, no signal will be aborted\n */\nexport function allAbortSignals(...signals: Maybe<AbortSignal>[]): AbortSignal {\n const ac = new AbortController();\n\n const count = signals.length;\n\n let abortedCount = 0;\n\n const onAbort = () => {\n if (++abortedCount === count) {\n ac.abort();\n }\n };\n\n for (const signal of signals) {\n if (signal?.aborted) {\n onAbort();\n } else {\n signal?.addEventListener('abort', onAbort, {\n once: true,\n });\n }\n }\n\n return ac.signal;\n}\n\n/**\n * Like `Promise.race` but for abort signals\n *\n * Basically, a ponyfill for\n * [`AbortSignal.any`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static).\n */\nexport function raceAbortSignals(\n ...signals: Maybe<AbortSignal>[]\n): AbortSignal {\n const ac = new AbortController();\n\n for (const signal of signals) {\n if (signal?.aborted) {\n ac.abort();\n } else {\n signal?.addEventListener('abort', () => ac.abort(), { once: true });\n }\n }\n\n return ac.signal;\n}\n\nexport function abortSignalToPromise(signal: AbortSignal): Promise<never> {\n return new Promise((_, reject) => {\n if (signal.aborted) {\n reject(signal.reason);\n return;\n }\n signal.addEventListener(\n 'abort',\n () => {\n reject(signal.reason);\n },\n { once: true },\n );\n });\n}\n","import type { AnyRouter, ProcedureType } from '@trpc/server';\nimport { observable } from '@trpc/server/observable';\nimport { transformResult } from '@trpc/server/unstable-core-do-not-import';\nimport type { BatchLoader } from '../internals/dataLoader';\nimport { dataLoader } from '../internals/dataLoader';\nimport { allAbortSignals } from '../internals/signals';\nimport type { NonEmptyArray } from '../internals/types';\nimport { TRPCClientError } from '../TRPCClientError';\nimport type { HTTPBatchLinkOptions } from './HTTPBatchLinkOptions';\nimport type { HTTPResult } from './internals/httpUtils';\nimport {\n getUrl,\n jsonHttpRequester,\n resolveHTTPLinkOptions,\n} from './internals/httpUtils';\nimport type { Operation, TRPCLink } from './types';\n\n/**\n * @see https://trpc.io/docs/client/links/httpBatchLink\n */\nexport function httpBatchLink<TRouter extends AnyRouter>(\n opts: HTTPBatchLinkOptions<TRouter['_def']['_config']['$types']>,\n): TRPCLink<TRouter> {\n const resolvedOpts = resolveHTTPLinkOptions(opts);\n const maxURLLength = opts.maxURLLength ?? Infinity;\n const maxItems = opts.maxItems ?? Infinity;\n\n return () => {\n const batchLoader = (\n type: ProcedureType,\n ): BatchLoader<Operation, HTTPResult> => {\n return {\n validate(batchOps) {\n if (maxURLLength === Infinity && maxItems === Infinity) {\n // escape hatch for quick calcs\n return true;\n }\n if (batchOps.length > maxItems) {\n return false;\n }\n const path = batchOps.map((op) => op.path).join(',');\n const inputs = batchOps.map((op) => op.input);\n\n const url = getUrl({\n ...resolvedOpts,\n type,\n path,\n inputs,\n signal: null,\n });\n\n return url.length <= maxURLLength;\n },\n async fetch(batchOps) {\n const path = batchOps.map((op) => op.path).join(',');\n const inputs = batchOps.map((op) => op.input);\n const signal = allAbortSignals(...batchOps.map((op) => op.signal));\n\n const res = await jsonHttpRequester({\n ...resolvedOpts,\n path,\n inputs,\n type,\n headers() {\n if (!opts.headers) {\n return {};\n }\n if (typeof opts.headers === 'function') {\n return opts.headers({\n opList: batchOps as NonEmptyArray<Operation>,\n });\n }\n return opts.headers;\n },\n signal,\n });\n const resJSON = Array.isArray(res.json)\n ? res.json\n : batchOps.map(() => res.json);\n const result = resJSON.map((item) => ({\n meta: res.meta,\n json: item,\n }));\n return result;\n },\n };\n };\n\n const query = dataLoader(batchLoader('query'));\n const mutation = dataLoader(batchLoader('mutation'));\n\n const loaders = { query, mutation };\n return ({ op }) => {\n return observable((observer) => {\n /* istanbul ignore if -- @preserve */\n if (op.type === 'subscription') {\n throw new Error(\n 'Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`',\n );\n }\n const loader = loaders[op.type];\n const promise = loader.load(op);\n\n let _res = undefined as HTTPResult | undefined;\n promise\n .then((res) => {\n _res = res;\n const transformed = transformResult(\n res.json,\n resolvedOpts.transformer.output,\n );\n\n if (!transformed.ok) {\n observer.error(\n TRPCClientError.from(transformed.error, {\n meta: res.meta,\n }),\n );\n return;\n }\n observer.next({\n context: res.meta,\n result: transformed.result,\n });\n observer.complete();\n })\n .catch((err) => {\n observer.error(\n TRPCClientError.from(err, {\n meta: _res?.meta,\n }),\n );\n });\n\n return () => {\n // noop\n };\n });\n };\n };\n}\n","/// <reference lib=\"dom.iterable\" />\n\n// `dom.iterable` types are explicitly required for extracting `FormData` values,\n// as all implementations of `Symbol.iterable` are separated from the main `dom` types.\n// Using triple-slash directive makes sure that it will be available,\n// even if end-user `tsconfig.json` omits it in the `lib` array.\n\nimport { observable, tap } from '@trpc/server/observable';\nimport type {\n AnyRouter,\n InferrableClientTypes,\n} from '@trpc/server/unstable-core-do-not-import';\nimport type { TRPCClientError } from '../TRPCClientError';\nimport type { Operation, OperationResultEnvelope, TRPCLink } from './types';\n\ntype ConsoleEsque = {\n log: (...args: any[]) => void;\n error: (...args: any[]) => void;\n};\n\ntype EnableFnOptions<TRouter extends InferrableClientTypes> =\n | {\n direction: 'down';\n result:\n | OperationResultEnvelope<unknown, TRPCClientError<TRouter>>\n | TRPCClientError<TRouter>;\n }\n | (Operation & {\n direction: 'up';\n });\ntype EnabledFn<TRouter extends AnyRouter> = (\n opts: EnableFnOptions<TRouter>,\n) => boolean;\n\ntype LoggerLinkFnOptions<TRouter extends AnyRouter> = Operation &\n (\n | {\n /**\n * Request result\n */\n direction: 'down';\n result:\n | OperationResultEnvelope<unknown, TRPCClientError<TRouter>>\n | TRPCClientError<TRouter>;\n elapsedMs: number;\n }\n | {\n /**\n * Request was just initialized\n */\n direction: 'up';\n }\n );\n\ntype LoggerLinkFn<TRouter extends AnyRouter> = (\n opts: LoggerLinkFnOptions<TRouter>,\n) => void;\n\ntype ColorMode = 'ansi' | 'css' | 'none';\n\nexport interface LoggerLinkOptions<TRouter extends AnyRouter> {\n logger?: LoggerLinkFn<TRouter>;\n enabled?: EnabledFn<TRouter>;\n /**\n * Used in the built-in defaultLogger\n */\n console?: ConsoleEsque;\n /**\n * Color mode\n * @default typeof window === 'undefined' ? 'ansi' : 'css'\n */\n colorMode?: ColorMode;\n\n /**\n * Include context in the log - defaults to false unless `colorMode` is 'css'\n */\n withContext?: boolean;\n}\n\nfunction isFormData(value: unknown): value is FormData {\n if (typeof FormData === 'undefined') {\n // FormData is not supported\n return false;\n }\n return value instanceof FormData;\n}\n\nconst palettes = {\n css: {\n query: ['72e3ff', '3fb0d8'],\n mutation: ['c5a3fc', '904dfc'],\n subscription: ['ff49e1', 'd83fbe'],\n },\n ansi: {\n regular: {\n // Cyan background, black and white text respectively\n query: ['\\x1b[30;46m', '\\x1b[97;46m'],\n // Magenta background, black and white text respectively\n mutation: ['\\x1b[30;45m', '\\x1b[97;45m'],\n // Green background, black and white text respectively\n subscription: ['\\x1b[30;42m', '\\x1b[97;42m'],\n },\n bold: {\n query: ['\\x1b[1;30;46m', '\\x1b[1;97;46m'],\n mutation: ['\\x1b[1;30;45m', '\\x1b[1;97;45m'],\n subscription: ['\\x1b[1;30;42m', '\\x1b[1;97;42m'],\n },\n },\n} as const;\n\nfunction constructPartsAndArgs(\n opts: LoggerLinkFnOptions<any> & {\n colorMode: ColorMode;\n withContext?: boolean;\n },\n) {\n const { direction, type, withContext, path, id, input } = opts;\n\n const parts: string[] = [];\n const args: any[] = [];\n\n if (opts.colorMode === 'none') {\n parts.push(direction === 'up' ? '>>' : '<<', type, `#${id}`, path);\n } else if (opts.colorMode === 'ansi') {\n const [lightRegular, darkRegular] = palettes.ansi.regular[type];\n const [lightBold, darkBold] = palettes.ansi.bold[type];\n const reset = '\\x1b[0m';\n\n parts.push(\n direction === 'up' ? lightRegular : darkRegular,\n direction === 'up' ? '>>' : '<<',\n type,\n direction === 'up' ? lightBold : darkBold,\n `#${id}`,\n path,\n reset,\n );\n } else {\n // css color mode\n const [light, dark] = palettes.css[type];\n const css = `\n background-color: #${direction === 'up' ? light : dark};\n color: ${direction === 'up' ? 'black' : 'white'};\n padding: 2px;\n `;\n\n parts.push(\n '%c',\n direction === 'up' ? '>>' : '<<',\n type,\n `#${id}`,\n `%c${path}%c`,\n '%O',\n );\n args.push(\n css,\n `${css}; font-weight: bold;`,\n `${css}; font-weight: normal;`,\n );\n }\n\n if (direction === 'up') {\n args.push(withContext ? { input, context: opts.context } : { input });\n } else {\n args.push({\n input,\n result: opts.result,\n elapsedMs: opts.elapsedMs,\n ...(withContext && { context: opts.context }),\n });\n }\n\n return { parts, args };\n}\n\n// maybe this should be moved to it's own package\nconst defaultLogger =\n <TRouter extends AnyRouter>({\n c = console,\n colorMode = 'css',\n withContext,\n }: {\n c?: ConsoleEsque;\n colorMode?: ColorMode;\n withContext?: boolean;\n }): LoggerLinkFn<TRouter> =>\n (props) => {\n const rawInput = props.input;\n const input = isFormData(rawInput)\n ? Object.fromEntries(rawInput)\n : rawInput;\n\n const { parts, args } = constructPartsAndArgs({\n ...props,\n colorMode,\n input,\n withContext,\n });\n\n const fn: 'error' | 'log' =\n props.direction === 'down' &&\n props.result &&\n (props.result instanceof Error ||\n ('error' in props.result.result && props.result.result.error))\n ? 'error'\n : 'log';\n\n c[fn].apply(null, [parts.join(' ')].concat(args));\n };\n\n/**\n * @see https://trpc.io/docs/v11/client/links/loggerLink\n */\nexport function loggerLink<TRouter extends AnyRouter = AnyRouter>(\n opts: LoggerLinkOptions<TRouter> = {},\n): TRPCLink<TRouter> {\n const { enabled = () => true } = opts;\n\n const colorMode =\n opts.colorMode ?? (typeof window === 'undefined' ? 'ansi' : 'css');\n const withContext = opts.withContext ?? colorMode === 'css';\n const {\n logger = defaultLogger({ c: opts.console, colorMode, withContext }),\n } = opts;\n\n return () => {\n return ({ op, next }) => {\n return observable((observer) => {\n // ->\n if (enabled({ ...op, direction: 'up' })) {\n logger({\n ...op,\n direction: 'up',\n });\n }\n const requestStartTime = Date.now();\n function logResult(\n result:\n | OperationResultEnvelope<unknown, TRPCClientError<TRouter>>\n | TRPCClientError<TRouter>,\n ) {\n const elapsedMs = Date.now() - requestStartTime;\n\n if (enabled({ ...op, direction: 'down', result })) {\n logger({\n ...op,\n direction: 'down',\n elapsedMs,\n result,\n });\n }\n }\n return next(op)\n .pipe(\n tap({\n next(result) {\n logResult(result);\n },\n error(result) {\n logResult(result);\n },\n }),\n )\n .subscribe(observer);\n });\n };\n };\n}\n","import type { Encoder } from '@trpc/server/adapters/ws';\n\nexport type { Encoder };\n\nexport const jsonEncoder: Encoder = {\n encode: (data) => JSON.stringify(data),\n decode: (data) => {\n if (typeof data !== 'string') {\n throw new Error(\n 'jsonEncoder received binary data. JSON uses text frames. ' +\n 'Use a binary encoder for binary data.',\n );\n }\n return JSON.parse(data);\n },\n};\n","import type { UrlOptionsWithConnectionParams } from '../../internals/urlWithConnectionParams';\nimport type { Encoder } from './encoder';\n\nexport interface WebSocketClientOptions extends UrlOptionsWithConnectionParams {\n /**\n * Ponyfill which WebSocket implementation to use\n */\n WebSocket?: typeof WebSocket;\n /**\n * The number of milliseconds before a reconnect is attempted.\n * @default {@link exponentialBackoff}\n */\n retryDelayMs?: (attemptIndex: number) => number;\n /**\n * Triggered when a WebSocket connection is established\n */\n onOpen?: () => void;\n /**\n * Triggered when a WebSocket connection encounters an error\n */\n onError?: (evt?: Event) => void;\n /**\n * Triggered when a WebSocket connection is closed\n */\n onClose?: (cause?: { code?: number }) => void;\n /**\n * Lazy mode will close the WebSocket automatically after a period of inactivity (no messages sent or received and no pending requests)\n */\n lazy?: {\n /**\n * Enable lazy mode\n * @default false\n */\n enabled: boolean;\n /**\n * Close the WebSocket after this many milliseconds\n * @default 0\n */\n closeMs: number;\n };\n /**\n * Send ping messages to the server and kill the connection if no pong message is returned\n */\n keepAlive?: {\n /**\n * @default false\n */\n enabled: boolean;\n /**\n * Send a ping message every this many milliseconds\n * @default 5_000\n */\n intervalMs?: number;\n /**\n * Close the WebSocket after this many milliseconds if the server does not respond\n * @default 1_000\n */\n pongTimeoutMs?: number;\n };\n /**\n * Custom encoder for wire encoding (e.g. custom binary formats)\n * @default jsonEncoder\n */\n experimental_encoder?: Encoder;\n}\n\n/**\n * Default options for lazy WebSocket connections.\n * Determines whether the connection should be established lazily and defines the delay before closure.\n */\nexport type LazyOptions = Required<NonNullable<WebSocketClientOptions['lazy']>>;\nexport const lazyDefaults: LazyOptions = {\n enabled: false,\n closeMs: 0,\n};\n\n/**\n * Default options for the WebSocket keep-alive mechanism.\n * Configures whether keep-alive is enabled and specifies the timeout and interval for ping-pong messages.\n */\nexport type KeepAliveOptions = Required<\n NonNullable<WebSocketClientOptions['keepAlive']>\n>;\nexport const keepAliveDefaults: KeepAliveOptions = {\n enabled: false,\n pongTimeoutMs: 1_000,\n intervalMs: 5_000,\n};\n\n/**\n * Calculates a delay for exponential backoff based on the retry attempt index.\n * The delay starts at 0 for the first attempt and doubles for each subsequent attempt,\n * capped at 30 seconds.\n */\nexport const exponentialBackoff = (attemptIndex: number) => {\n return attemptIndex === 0 ? 0 : Math.min(1000 * 2 ** attemptIndex, 30000);\n};\n","import { type TRPCRequestInfo } from '@trpc/server/http';\n\n/**\n * Get the result of a value or function that returns a value\n * It also optionally accepts typesafe arguments for the function\n */\nexport const resultOf = <T, TArgs extends any[]>(\n value: T | ((...args: TArgs) => T),\n ...args: TArgs\n): T => {\n return typeof value === 'function'\n ? (value as (...args: TArgs) => T)(...args)\n : value;\n};\n\n/**\n * A value that can be wrapped in callback\n */\nexport type CallbackOrValue<T> = T | (() => T | Promise<T>);\n\nexport interface UrlOptionsWithConnectionParams {\n /**\n * The URL to connect to (can be a function that returns a URL)\n */\n url: CallbackOrValue<string>;\n\n /**\n * Connection params that are available in `createContext()`\n * - For `wsLink`/`wsClient`, these are sent as the first message\n * - For `httpSubscriptionLink`, these are serialized as part of the URL under the `connectionParams` query\n */\n connectionParams?: CallbackOrValue<TRPCRequestInfo['connectionParams']>;\n}\n","import type {\n TRPCConnectionParamsMessage,\n TRPCRequestInfo,\n} from '@trpc/server/unstable-core-do-not-import';\nimport type {\n CallbackOrValue,\n UrlOptionsWithConnectionParams,\n} from '../../internals/urlWithConnectionParams';\nimport { resultOf } from '../../internals/urlWithConnectionParams';\nimport type { Encoder } from './encoder';\n\nexport class TRPCWebSocketClosedError extends Error {\n constructor(opts: { message: string; cause?: unknown }) {\n super(opts.message, {\n cause: opts.cause,\n });\n this.name = 'TRPCWebSocketClosedError';\n Object.setPrototypeOf(this, TRPCWebSocketClosedError.prototype);\n }\n}\n\n/**\n * Utility class for managing a timeout that can be started, stopped, and reset.\n * Useful for scenarios where the timeout duration is reset dynamically based on events.\n */\nexport class ResettableTimeout {\n private timeout: ReturnType<typeof setTimeout> | undefined;\n\n constructor(\n private readonly onTimeout: () => void,\n private readonly timeoutMs: number,\n ) {}\n\n /**\n * Resets the current timeout, restarting it with the same duration.\n * Does nothing if no timeout is active.\n */\n public reset() {\n if (!this.timeout) return;\n\n clearTimeout(this.timeout);\n this.timeout = setTimeout(this.onTimeout, this.timeoutMs);\n }\n\n public start() {\n clearTimeout(this.timeout);\n this.timeout = setTimeout(this.onTimeout, this.timeoutMs);\n }\n\n public stop() {\n clearTimeout(this.timeout);\n this.timeout = undefined;\n }\n}\n\n// Ponyfill for Promise.withResolvers https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers\nexport function withResolvers<T>() {\n let resolve: (value: T | PromiseLike<T>) => void;\n let reject: (reason?: any) => void;\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return { promise, resolve: resolve!, reject: reject! };\n}\n\n/**\n * Resolves a WebSocket URL and optionally appends connection parameters.\n *\n * If connectionParams are provided, appends 'connectionParams=1' query parameter.\n */\nexport async function prepareUrl(urlOptions: UrlOptionsWithConnectionParams) {\n const url = await resultOf(urlOptions.url);\n\n if (!urlOptions.connectionParams) return url;\n\n // append `?connectionParams=1` when connection params are used\n const prefix = url.includes('?') ? '&' : '?';\n const connectionParams = `${prefix}connectionParams=1`;\n\n return url + connectionParams;\n}\n\nexport async function buildConnectionMessage(\n connectionParams: CallbackOrValue<TRPCRequestInfo['connectionParams']>,\n encoder: Encoder,\n) {\n const message: TRPCConnectionParamsMessage = {\n method: 'connectionParams',\n data: await resultOf(connectionParams),\n };\n\n return encoder.encode(message);\n}\n","import type { AnyTRPCRouter, inferRouterError } from '@trpc/server';\nimport type { Observer } from '@trpc/server/observable';\nimport type {\n TRPCClientOutgoingMessage,\n TRPCResponseMessage,\n} from '@trpc/server/unstable-core-do-not-import';\nimport type { TRPCClientError } from '../../../TRPCClientError';\nimport { withResolvers } from './utils';\n\nexport type TCallbacks = Observer<\n TRPCResponseMessage<unknown, inferRouterError<AnyTRPCRouter>>,\n TRPCClientError<AnyTRPCRouter>\n>;\n\ntype MessageId = string;\ntype MessageIdLike = string | number | null;\n\n/**\n * Represents a WebSocket request managed by the RequestManager.\n * Combines the network message, a utility promise (`end`) that mirrors the lifecycle\n * handled by `callbacks`, and a set of state monitoring callbacks.\n */\ninterface Request {\n message: TRPCClientOutgoingMessage;\n end: Promise<void>;\n callbacks: TCallbacks;\n}\n\n/**\n * Manages WebSocket requests, tracking their lifecycle and providing utility methods\n * for handling outgoing and pending requests.\n *\n * - **Outgoing requests**: Requests that are queued and waiting to be sent.\n * - **Pending requests**: Requests that have been sent and are in flight awaiting a response.\n * For subscriptions, multiple responses may be received until the subscription is closed.\n */\nexport class RequestManager {\n /**\n * Stores requests that are outgoing, meaning they are registered but not yet sent over the WebSocket.\n */\n private outgoingRequests = new Array<Request & { id: MessageId }>();\n\n /**\n * Stores requests that are pending (in flight), meaning they have been sent over the WebSocket\n * and are awaiting responses. For subscriptions, this includes requests\n * that may receive multiple responses.\n */\n private pendingRequests: Record<MessageId, Request> = {};\n\n /**\n * Registers a new request by adding it to the outgoing queue and setting up\n * callbacks for lifecycle events such as completion or error.\n *\n * @param message - The outgoing message to be sent.\n * @param callbacks - Callback functions to observe the request's state.\n * @returns A cleanup function to manually remove the request.\n */\n public register(message: TRPCClientOutgoingMessage, callbacks: TCallbacks) {\n const { promise: end, resolve } = withResolvers<void>();\n\n this.outgoingRequests.push({\n id: String(message.id),\n message,\n end,\n callbacks: {\n next: callbacks.next,\n complete: () => {\n callbacks.complete();\n resolve();\n },\n error: (e) => {\n callbacks.error(e);\n resolve();\n },\n },\n });\n\n return () => {\n this.delete(message.id);\n callbacks.complete();\n resolve();\n };\n }\n\n /**\n * Deletes a request from both the outgoing and pending collections, if it exists.\n */\n public delete(messageId: MessageIdLike) {\n if (messageId === null) return;\n\n this.outgoingRequests = this.outgoingRequests.filter(\n ({ id }) => id !== String(messageId),\n );\n delete this.pendingRequests[String(messageId)];\n }\n\n /**\n * Moves all outgoing requests to the pending state and clears the outgoing queue.\n *\n * The caller is expected to handle the actual sending of the requests\n * (e.g., sending them over the network) after this method is called.\n *\n * @returns The list of requests that were transitioned to the pending state.\n */\n public flush() {\n const requests = this.outgoingRequests;\n this.outgoingRequests = [];\n\n for (const request of requests) {\n this.pendingRequests[request.id] = request;\n }\n return requests;\n }\n\n /**\n * Retrieves all currently pending requests, which are in flight awaiting responses\n * or handling ongoing subscriptions.\n */\n public getPendingRequests() {\n return Object.values(this.pendingRequests);\n }\n\n /**\n * Retrieves a specific pending request by its message ID.\n */\n public getPendingRequest(messageId: MessageIdLike) {\n if (messageId === null) return null;\n\n return this.pendingRequests[String(messageId)];\n }\n\n /**\n * Retrieves all outgoing requests, which are waiting to be sent.\n */\n public getOutgoingRequests() {\n return this.outgoingRequests;\n }\n\n /**\n * Retrieves all requests, both outgoing and pending, with their respective states.\n *\n * @returns An array of all requests with their state (\"outgoing\" or \"pending\").\n */\n public getRequests() {\n return [\n ...this.getOutgoingRequests().map((request) => ({\n state: 'outgoing' as const,\n message: request.message,\n end: request.end,\n callbacks: request.callbacks,\n })),\n ...this.getPendingRequests().map((request) => ({\n state: 'pending' as const,\n message: request.message,\n end: request.end,\n callbacks: request.callbacks,\n })),\n ];\n }\n\n /**\n * Checks if there are any pending requests, including ongoing subscriptions.\n */\n public hasPendingRequests() {\n return this.getPendingRequests().length > 0;\n }\n\n /**\n * Checks if there are any pending subscriptions\n */\n public hasPendingSubscriptions() {\n return this.getPendingRequests().some(\n (request) => request.message.method === 'subscription',\n );\n }\n\n /**\n * Checks if there are any outgoing requests waiting to be sent.\n */\n public hasOutgoingRequests() {\n return this.outgoingRequests.length > 0;\n }\n}\n","import { behaviorSubject } from '@trpc/server/observable';\nimport type { UrlOptionsWithConnectionParams } from '../../internals/urlWithConnectionParams';\nimport type { Encoder } from './encoder';\nimport { buildConnectionMessage, prepareUrl, withResolvers } from './utils';\n\n/**\n * Opens a WebSocket connection asynchronously and returns a promise\n * that resolves when the connection is successfully established.\n * The promise rejects if an error occurs during the connection attempt.\n */\nfunction asyncWsOpen(ws: WebSocket) {\n const { promise, resolve, reject } = withResolvers<void>();\n\n ws.addEventListener('open', () => {\n ws.removeEventListener('error', reject);\n resolve();\n });\n ws.addEventListener('error', reject);\n\n return promise;\n}\n\ninterface PingPongOptions {\n /**\n * The interval (in milliseconds) between \"PING\" messages.\n */\n intervalMs: number;\n\n /**\n * The timeout (in milliseconds) to wait for a \"PONG\" response before closing the connection.\n */\n pongTimeoutMs: number;\n}\n\n/**\n * Sets up a periodic ping-pong mechanism to keep the WebSocket connection alive.\n *\n * - Sends \"PING\" messages at regular intervals defined by `intervalMs`.\n * - If a \"PONG\" response is not received within the `pongTimeoutMs`, the WebSocket is closed.\n * - The ping timer resets upon receiving any message to maintain activity.\n * - Automatically starts the ping process when the WebSocket connection is opened.\n * - Cleans up timers when the WebSocket is closed.\n *\n * @param ws - The WebSocket instance to manage.\n * @param options - Configuration options for ping-pong intervals and timeouts.\n */\nfunction setupPingInterval(\n ws: WebSocket,\n { intervalMs, pongTimeoutMs }: PingPongOptions,\n) {\n let pingTimeout: ReturnType<typeof setTimeout> | undefined;\n let pongTimeout: ReturnType<typeof setTimeout> | undefined;\n\n function start() {\n pingTimeout = setTimeout(() => {\n ws.send('PING');\n pongTimeout = setTimeout(() => {\n ws.close();\n }, pongTimeoutMs);\n }, intervalMs);\n }\n\n function reset() {\n clearTimeout(pingTimeout);\n start();\n }\n\n function pong() {\n clearTimeout(pongTimeout);\n reset();\n }\n\n ws.addEventListener('open', start);\n ws.addEventListener('message', ({ data }) => {\n clearTimeout(pingTimeout);\n start();\n\n if (data === 'PONG') {\n pong();\n }\n });\n ws.addEventListener('close', () => {\n clearTimeout(pingTimeout);\n clearTimeout(pongTimeout);\n });\n}\n\nexport interface WebSocketConnectionOptions {\n WebSocketPonyfill?: typeof WebSocket;\n urlOptions: UrlOptionsWithConnectionParams;\n keepAlive: PingPongOptions & {\n enabled: boolean;\n };\n encoder: Encoder;\n}\n\n/**\n * Manages a WebSocket connection with support for reconnection, keep-alive mechanisms,\n * and observable state tracking.\n */\nexport class WsConnection {\n static connectCount = 0;\n public id = ++WsConnection.connectCount;\n\n private readonly WebSocketPonyfill: typeof WebSocket;\n private readonly urlOptions: UrlOptionsWithConnectionParams;\n private readonly keepAliveOpts: WebSocketConnectionOptions['keepAlive'];\n private readonly encoder: Encoder;\n public readonly wsObservable = behaviorSubject<WebSocket | null>(null);\n\n constructor(opts: WebSocketConnectionOptions) {\n this.WebSocketPonyfill = opts.WebSocketPonyfill ?? WebSocket;\n if (!this.WebSocketPonyfill) {\n throw new Error(\n \"No WebSocket implementation found - you probably don't want to use this on the server, but if you do you need to pass a `WebSocket`-ponyfill\",\n );\n }\n\n this.urlOptions = opts.urlOptions;\n this.keepAliveOpts = opts.keepAlive;\n this.encoder = opts.encoder;\n }\n\n public get ws() {\n return this.wsObservable.get();\n }\n\n private set ws(ws) {\n this.wsObservable.next(ws);\n }\n\n /**\n * Checks if the WebSocket connection is open and ready to communicate.\n */\n public isOpen(): this is { ws: WebSocket } {\n return (\n !!this.ws &&\n this.ws.readyState === this.WebSocketPonyfill.OPEN &&\n !this.openPromise\n );\n }\n\n /**\n * Checks if the WebSocket connection is closed or in the process of closing.\n */\n public isClosed(): this is { ws: WebSocket } {\n return (\n !!this.ws &&\n (this.ws.readyState === this.WebSocketPonyfill.CLOSING ||\n this.ws.readyState === this.WebSocketPonyfill.CLOSED)\n );\n }\n\n /**\n * Manages the WebSocket opening process, ensuring that only one open operation\n * occurs at a time. Tracks the ongoing operation with `openPromise` to avoid\n * redundant calls and ensure proper synchronization.\n *\n * Sets up the keep-alive mechanism and necessary event listeners for the connection.\n *\n * @returns A promise that resolves once the WebSocket connection is successfully opened.\n */\n private openPromise: Promise<void> | null = null;\n public async open() {\n if (this.openPromise) return this.openPromise;\n\n this.id = ++WsConnection.connectCount;\n const wsPromise = prepareUrl(this.urlOptions).then(\n (url) => new this.WebSocketPonyfill(url),\n );\n this.openPromise = wsPromise.then(async (ws) => {\n this.ws = ws;\n\n // Set binaryType to handle both text and binary messages consistently\n ws.binaryType = 'arraybuffer';\n\n // Setup ping listener\n ws.addEventListener('message', function ({ data }) {\n if (data === 'PING') {\n this.send('PONG');\n }\n });\n\n if (this.keepAliveOpts.enabled) {\n setupPingInterval(ws, this.keepAliveOpts);\n }\n\n ws.addEventListener('close', () => {\n if (this.ws === ws) {\n this.ws = null;\n }\n });\n\n await asyncWsOpen(ws);\n\n if (this.urlOptions.connectionParams) {\n ws.send(\n await buildConnectionMessage(\n this.urlOptions.connectionParams,\n this.encoder,\n ),\n );\n }\n });\n\n try {\n await this.openPromise;\n } finally {\n this.openPromise = null;\n }\n }\n\n /**\n * Closes the WebSocket connection gracefully.\n * Waits for any ongoing open operation to complete before closing.\n */\n public async close() {\n try {\n await this.openPromise;\n } finally {\n this.ws?.close();\n }\n }\n}\n\n/**\n * Provides a backward-compatible representation of the connection state.\n */\nexport function backwardCompatibility(connection: WsConnection) {\n if (connection.isOpen()) {\n return {\n id: connection.id,\n state: 'open',\n ws: connection.ws,\n } as const;\n }\n\n if (connection.isClosed()) {\n return {\n id: connection.id,\n state: 'closed',\n ws: connection.ws,\n } as const;\n }\n\n if (!connection.ws) {\n return null;\n }\n\n return {\n id: connection.id,\n state: 'connecting',\n ws: connection.ws,\n } as const;\n}\n","import type { AnyTRPCRouter } from '@trpc/server';\nimport type { BehaviorSubject } from '@trpc/server/observable';\nimport { behaviorSubject, observable } from '@trpc/server/observable';\nimport type {\n CombinedDataTransformer,\n TRPCClientIncomingMessage,\n TRPCClientIncomingRequest,\n TRPCClientOutgoingMessage,\n TRPCResponseMessage,\n} from '@trpc/server/unstable-core-do-not-import';\nimport {\n run,\n sleep,\n transformResult,\n} from '@trpc/server/unstable-core-do-not-import';\nimport { TRPCClientError } from '../../../TRPCClientError';\nimport type { TRPCConnectionState } from '../../internals/subscriptions';\nimport type { Operation, OperationResultEnvelope } from '../../types';\nimport type { Encoder } from './encoder';\nimport { jsonEncoder } from './encoder';\nimport type { WebSocketClientOptions } from './options';\nimport { exponentialBackoff, keepAliveDefaults, lazyDefaults } from './options';\nimport type { TCallbacks } from './requestManager';\nimport { RequestManager } from './requestManager';\nimport { ResettableTimeout, TRPCWebSocketClosedError } from './utils';\nimport { backwardCompatibility, WsConnection } from './wsConnection';\n\n/**\n * A WebSocket client for managing TRPC operations, supporting lazy initialization,\n * reconnection, keep-alive, and request management.\n */\nexport class WsClient {\n /**\n * Observable tracking the current connection state, including errors.\n */\n public readonly connectionState: BehaviorSubject<\n TRPCConnectionState<TRPCClientError<AnyTRPCRouter>>\n >;\n\n private allowReconnect = false;\n private requestManager = new RequestManager();\n private readonly activeConnection: WsConnection;\n private readonly reconnectRetryDelay: (attemptIndex: number) => number;\n private inactivityTimeout: ResettableTimeout;\n private readonly callbacks: Pick<\n WebSocketClientOptions,\n 'onOpen' | 'onClose' | 'onError'\n >;\n private readonly lazyMode: boolean;\n private readonly encoder: Encoder;\n\n constructor(opts: WebSocketClientOptions) {\n this.encoder = opts.experimental_encoder ?? jsonEncoder;\n // Initialize callbacks, connection parameters, and options.\n this.callbacks = {\n onOpen: opts.onOpen,\n onClose: opts.onClose,\n onError: opts.onError,\n };\n\n const lazyOptions = {\n ...lazyDefaults,\n ...opts.lazy,\n };\n\n // Set up inactivity timeout for lazy connections.\n this.inactivityTimeout = new ResettableTimeout(() => {\n if (\n this.requestManager.hasOutgoingRequests() ||\n this.requestManager.hasPendingRequests()\n ) {\n this.inactivityTimeout.reset();\n return;\n }\n\n this.close().catch(() => null);\n }, lazyOptions.closeMs);\n\n // Initialize the WebSocket connection.\n this.activeConnection = new WsConnection({\n WebSocketPonyfill: opts.WebSocket,\n urlOptions: opts,\n keepAlive: {\n ...keepAliveDefaults,\n ...opts.keepAlive,\n },\n encoder: this.encoder,\n });\n this.activeConnection.wsObservable.subscribe({\n next: (ws) => {\n if (!ws) return;\n this.setupWebSocketListeners(ws);\n },\n });\n this.reconnectRetryDelay = opts.retryDelayMs ?? exponentialBackoff;\n\n this.lazyMode = lazyOptions.enabled;\n\n this.connectionState = behaviorSubject<\n TRPCConnectionState<TRPCClientError<AnyTRPCRouter>>\n >({\n type: 'state',\n state: lazyOptions.enabled ? 'idle' : 'connecting',\n error: null,\n });\n\n // Automatically open the connection if lazy mode is disabled.\n if (!this.lazyMode) {\n this.open().catch(() => null);\n }\n }\n\n /**\n * Opens the WebSocket connection. Handles reconnection attempts and updates\n * the connection state accordingly.\n */\n private async open() {\n this.allowReconnect = true;\n if (this.connectionState.get().state === 'idle') {\n this.connectionState.next({\n type: 'state',\n state: 'connecting',\n error: null,\n });\n }\n\n try {\n await this.activeConnection.open();\n } catch (error) {\n this.reconnect(\n new TRPCWebSocketClosedError({\n message: 'Initialization error',\n cause: error,\n }),\n );\n return this.reconnecting;\n }\n }\n\n /**\n * Closes the WebSocket connection and stops managing requests.\n * Ensures all outgoing and pending requests are properly finalized.\n */\n public async close() {\n this.allowReconnect = false;\n this.inactivityTimeout.stop();\n\n const requestsToAwait: Promise<void>[] = [];\n for (const request of this.requestManager.getRequests()) {\n if (request.message.method === 'subscription') {\n request.callbacks.complete();\n } else if (request.state === 'outgoing') {\n request.callbacks.error(\n TRPCClientError.from(\n new TRPCWebSocketClosedError({\n message: 'Closed before connection was established',\n }),\n ),\n );\n } else {\n requestsToAwait.push(request.end);\n }\n }\n\n await Promise.all(requestsToAwait).catch(() => null);\n await this.activeConnection.close().catch(() => null);\n\n this.connectionState.next({\n type: 'state',\n state: 'idle',\n error: null,\n });\n }\n\n /**\n * Method to request the server.\n * Handles data transformation, batching of requests, and subscription lifecycle.\n *\n * @param op - The operation details including id, type, path, input and signal\n * @param transformer - Data transformer for serializing requests and deserializing responses\n * @param lastEventId - Optional ID of the last received event for subscriptions\n *\n * @returns An observable that emits operation results and handles cleanup\n */\n public request({\n op: { id, type, path, input, signal },\n transformer,\n lastEventId,\n }: {\n op: Pick<Operation, 'id' | 'type' | 'path' | 'input' | 'signal'>;\n transformer: CombinedDataTransformer;\n lastEventId?: string;\n }) {\n return observable<\n OperationResultEnvelope<unknown, TRPCClientError<AnyTRPCRouter>>,\n TRPCClientError<AnyTRPCRouter>\n >((observer) => {\n const abort = this.batchSend(\n {\n id,\n method: type,\n params: {\n input: transformer.input.serialize(input),\n path,\n lastEventId,\n },\n },\n {\n ...observer,\n next(event) {\n const transformed = transformResult(event, transformer.output);\n\n if (!transformed.ok) {\n observer.error(TRPCClientError.from(transformed.error));\n return;\n }\n\n observer.next({\n result: transformed.result,\n });\n },\n },\n );\n\n return () => {\n abort();\n\n if (type === 'subscription' && this.activeConnection.isOpen()) {\n this.send({\n id,\n method: 'subscription.stop',\n });\n }\n\n signal?.removeEventListener('abort', abort);\n };\n });\n }\n\n public get connection() {\n return backwardCompatibility(this.activeConnection);\n }\n\n /**\n * Manages the reconnection process for the WebSocket using retry logic.\n * Ensures that only one reconnection attempt is active at a time by tracking the current\n * reconnection state in the `reconnecting` promise.\n */\n private reconnecting: Promise<void> | null = null;\n private reconnect(closedError: TRPCWebSocketClosedError) {\n this.connectionState.next({\n type: 'state',\n state: 'connecting',\n error: TRPCClientError.from(closedError),\n });\n if (this.reconnecting) return;\n\n const tryReconnect = async (attemptIndex: number) => {\n try {\n await sleep(this.reconnectRetryDelay(attemptIndex));\n if (this.allowReconnect) {\n await this.activeConnection.close();\n await this.activeConnection.open();\n\n if (this.requestManager.hasPendingRequests()) {\n this.send(\n this.requestManager\n .getPendingRequests()\n .map(({ message }) => message),\n );\n }\n }\n this.reconnecting = null;\n } catch {\n await tryReconnect(attemptIndex + 1);\n }\n };\n\n this.reconnecting = tryReconnect(0);\n }\n\n private setupWebSocketListeners(ws: WebSocket) {\n const handleCloseOrError = (cause: unknown) => {\n const reqs = this.requestManager.getPendingRequests();\n for (const { message, callbacks } of reqs) {\n if (message.method === 'subscription') continue;\n\n callbacks.error(\n TRPCClientError.from(\n cause ??\n new TRPCWebSocketClosedError({\n message: 'WebSocket closed',\n cause,\n }),\n ),\n );\n this.requestManager.delete(message.id);\n }\n };\n\n ws.addEventListener('open', () => {\n run(async () => {\n if (this.lazyMode) {\n this.inactivityTimeout.start();\n }\n\n this.callbacks.onOpen?.();\n\n this.connectionState.next({\n type: 'state',\n state: 'pending',\n error: null,\n });\n }).catch((error) => {\n ws.close(3000);\n handleCloseOrError(error);\n });\n });\n\n ws.addEventListener('message', ({ data }) => {\n this.inactivityTimeout.reset();\n\n // Handle PING/PONG as text regardless of encoder\n if (['PING', 'PONG'].includes(data)) return;\n\n const incomingMessage = this.encoder.decode(\n data,\n ) as TRPCClientIncomingMessage;\n if ('method' in incomingMessage) {\n this.handleIncomingRequest(incomingMessage);\n return;\n }\n\n this.handleResponseMessage(incomingMessage);\n });\n\n ws.addEventListener('close', (event) => {\n handleCloseOrError(event);\n this.callbacks.onClose?.(event);\n\n if (!this.lazyMode || this.requestManager.hasPendingSubscriptions()) {\n this.reconnect(\n new TRPCWebSocketClosedError({\n message: 'WebSocket closed',\n cause: event,\n }),\n );\n }\n });\n\n ws.addEventListener('error', (event) => {\n handleCloseOrError(event);\n this.callbacks.onError?.(event);\n\n this.reconnect(\n new TRPCWebSocketClosedError({\n message: 'WebSocket closed',\n cause: event,\n }),\n );\n });\n }\n\n private handleResponseMessage(message: TRPCResponseMessage) {\n const request = this.requestManager.getPendingRequest(message.id);\n if (!request) return;\n\n request.callbacks.next(message);\n\n let completed = true;\n if ('result' in message && request.message.method === 'subscription') {\n if (message.result.type === 'data') {\n request.message.params.lastEventId = message.result.id;\n }\n\n if (message.result.type !== 'stopped') {\n completed = false;\n }\n }\n\n if (completed) {\n request.callbacks.complete();\n this.requestManager.delete(message.id);\n }\n }\n\n private handleIncomingRequest(message: TRPCClientIncomingRequest) {\n if (message.method === 'reconnect') {\n this.reconnect(\n new TRPCWebSocketClosedError({\n message: 'Server requested reconnect',\n }),\n );\n }\n }\n\n /**\n * Sends a message or batch of messages directly to the server.\n */\n private send(\n messageOrMessages: TRPCClientOutgoingMessage | TRPCClientOutgoingMessage[],\n ) {\n if (!this.activeConnection.isOpen()) {\n throw new Error('Active connection is not open');\n }\n\n const messages =\n messageOrMessages instanceof Array\n ? messageOrMessages\n : [messageOrMessages];\n this.activeConnection.ws.send(\n this.encoder.encode(messages.length === 1 ? messages[0] : messages),\n );\n }\n\n /**\n * Groups requests for batch sending.\n *\n * @returns A function to abort the batched request.\n */\n private batchSend(message: TRPCClientOutgoingMessage, callbacks: TCallbacks) {\n this.inactivityTimeout.reset();\n\n run(async () => {\n if (!this.activeConnection.isOpen()) {\n await this.open();\n }\n await sleep(0);\n\n if (!this.requestManager.hasOutgoingRequests()) return;\n\n this.send(this.requestManager.flush().map(({ message }) => message));\n }).catch((err) => {\n this.requestManager.delete(message.id);\n callbacks.error(TRPCClientError.from(err));\n });\n\n return this.requestManager.register(message, callbacks);\n }\n}\n","import type { Encoder } from './wsClient/encoder';\nimport { jsonEncoder } from './wsClient/encoder';\nimport type { WebSocketClientOptions } from './wsClient/options';\nimport { WsClient } from './wsClient/wsClient';\n\nexport function createWSClient(opts: WebSocketClientOptions) {\n return new WsClient(opts);\n}\n\nexport type TRPCWebSocketClient = ReturnType<typeof createWSClient>;\n\nexport { jsonEncoder, type Encoder, type WebSocketClientOptions };\n","import { observable } from '@trpc/server/observable';\nimport type {\n AnyRouter,\n inferClientTypes,\n} from '@trpc/server/unstable-core-do-not-import';\nimport type { TransformerOptions } from '../../unstable-internals';\nimport { getTransformer } from '../../unstable-internals';\nimport type { TRPCLink } from '../types';\nimport type {\n Encoder,\n TRPCWebSocketClient,\n WebSocketClientOptions,\n} from './createWsClient';\nimport { createWSClient, jsonEncoder } from './createWsClient';\n\nexport type WebSocketLinkOptions<TRouter extends AnyRouter> = {\n client: TRPCWebSocketClient;\n} & TransformerOptions<inferClientTypes<TRouter>>;\n\nexport function wsLink<TRouter extends AnyRouter>(\n opts: WebSocketLinkOptions<TRouter>,\n): TRPCLink<TRouter> {\n const { client } = opts;\n const transformer = getTransformer(opts.transformer);\n return () => {\n return ({ op }) => {\n return observable((observer) => {\n const connStateSubscription =\n op.type === 'subscription'\n ? client.connectionState.subscribe({\n next(result) {\n observer.next({\n result,\n context: op.context,\n });\n },\n })\n : null;\n\n const requestSubscription = client\n .request({\n op,\n transformer,\n })\n .subscribe(observer);\n\n return () => {\n requestSubscription.unsubscribe();\n connStateSubscription?.unsubscribe();\n };\n });\n };\n };\n}\n\nexport {\n createWSClient,\n jsonEncoder,\n type Encoder,\n type TRPCWebSocketClient,\n type WebSocketClientOptions,\n};\n","import type {\n inferObservableValue,\n Unsubscribable,\n} from '@trpc/server/observable';\nimport { observableToPromise, share } from '@trpc/server/observable';\nimport type {\n AnyRouter,\n inferAsyncIterableYield,\n InferrableClientTypes,\n Maybe,\n TypeError,\n} from '@trpc/server/unstable-core-do-not-import';\nimport { createChain } from '../links/internals/createChain';\nimport type { TRPCConnectionState } from '../links/internals/subscriptions';\nimport type {\n OperationContext,\n OperationLink,\n TRPCClientRuntime,\n TRPCLink,\n} from '../links/types';\nimport { TRPCClientError } from '../TRPCClientError';\n\ntype TRPCType = 'mutation' | 'query' | 'subscription';\nexport interface TRPCRequestOptions {\n /**\n * Pass additional context to links\n */\n context?: OperationContext;\n signal?: AbortSignal;\n}\n\nexport interface TRPCSubscriptionObserver<TValue, TError> {\n onStarted: (opts: { context: OperationContext | undefined }) => void;\n onData: (value: inferAsyncIterableYield<TValue>) => void;\n onError: (err: TError) => void;\n onStopped: () => void;\n onComplete: () => void;\n onConnectionStateChange: (state: TRPCConnectionState<TError>) => void;\n}\n\n/** @internal */\nexport type CreateTRPCClientOptions<TRouter extends InferrableClientTypes> = {\n links: TRPCLink<TRouter>[];\n transformer?: TypeError<'The transformer property has moved to httpLink/httpBatchLink/wsLink'>;\n};\n\nexport class TRPCUntypedClient<TInferrable extends InferrableClientTypes> {\n private readonly links: OperationLink<TInferrable>[];\n public readonly runtime: TRPCClientRuntime;\n private requestId: number;\n\n constructor(opts: CreateTRPCClientOptions<TInferrable>) {\n this.requestId = 0;\n\n this.runtime = {};\n\n // Initialize the links\n this.links = opts.links.map((link) => link(this.runtime));\n }\n\n private $request<TInput = unknown, TOutput = unknown>(opts: {\n type: TRPCType;\n input: TInput;\n path: string;\n context?: OperationContext;\n signal: Maybe<AbortSignal>;\n }) {\n const chain$ = createChain<AnyRouter, TInput, TOutput>({\n links: this.links as OperationLink<any, any, any>[],\n op: {\n ...opts,\n context: opts.context ?? {},\n id: ++this.requestId,\n },\n });\n return chain$.pipe(share());\n }\n\n private async requestAsPromise<TInput = unknown, TOutput = unknown>(opts: {\n type: TRPCType;\n input: TInput;\n path: string;\n context?: OperationContext;\n signal: Maybe<AbortSignal>;\n }): Promise<TOutput> {\n try {\n const req$ = this.$request<TInput, TOutput>(opts);\n type TValue = inferObservableValue<typeof req$>;\n\n const envelope = await observableToPromise<TValue>(req$);\n const data = (envelope.result as any).data;\n return data;\n } catch (err) {\n throw TRPCClientError.from(err as Error);\n }\n }\n public query(path: string, input?: unknown, opts?: TRPCRequestOptions) {\n return this.requestAsPromise<unknown, unknown>({\n type: 'query',\n path,\n input,\n context: opts?.context,\n signal: opts?.signal,\n });\n }\n public mutation(path: string, input?: unknown, opts?: TRPCRequestOptions) {\n return this.requestAsPromise<unknown, unknown>({\n type: 'mutation',\n path,\n input,\n context: opts?.context,\n signal: opts?.signal,\n });\n }\n public subscription(\n path: string,\n input: unknown,\n opts: Partial<\n TRPCSubscriptionObserver<unknown, TRPCClientError<AnyRouter>>\n > &\n TRPCRequestOptions,\n ): Unsubscribable {\n const observable$ = this.$request({\n type: 'subscription',\n path,\n input,\n context: opts.context,\n signal: opts.signal,\n });\n return observable$.subscribe({\n next(envelope) {\n switch (envelope.result.type) {\n case 'state': {\n opts.onConnectionStateChange?.(envelope.result);\n break;\n }\n case 'started': {\n opts.onStarted?.({\n context: envelope.context,\n });\n break;\n }\n case 'stopped': {\n opts.onStopped?.();\n break;\n }\n case 'data':\n case undefined: {\n opts.onData?.(envelope.result.data);\n break;\n }\n }\n },\n error(err) {\n opts.onError?.(err);\n },\n complete() {\n opts.onComplete?.();\n },\n });\n }\n}\n","import type { AnyRouter } from '@trpc/server/unstable-core-do-not-import';\nimport type { CreateTRPCClientOptions } from './internals/TRPCUntypedClient';\nimport { TRPCUntypedClient } from './internals/TRPCUntypedClient';\n\nexport function createTRPCUntypedClient<TRouter extends AnyRouter>(\n opts: CreateTRPCClientOptions<TRouter>,\n): TRPCUntypedClient<TRouter> {\n return new TRPCUntypedClient(opts);\n}\n\nexport type {\n CreateTRPCClientOptions,\n TRPCRequestOptions,\n} from './internals/TRPCUntypedClient';\nexport { TRPCUntypedClient } from './internals/TRPCUntypedClient';\n","/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport type { Unsubscribable } from '@trpc/server/observable';\nimport type {\n AnyProcedure,\n AnyRouter,\n inferClientTypes,\n inferProcedureInput,\n InferrableClientTypes,\n inferTransformedProcedureOutput,\n ProcedureType,\n RouterRecord,\n} from '@trpc/server/unstable-core-do-not-import';\nimport {\n createFlatProxy,\n createRecursiveProxy,\n} from '@trpc/server/unstable-core-do-not-import';\nimport type { CreateTRPCClientOptions } from './createTRPCUntypedClient';\nimport type { TRPCSubscriptionObserver } from './internals/TRPCUntypedClient';\nimport { TRPCUntypedClient } from './internals/TRPCUntypedClient';\nimport type { TRPCProcedureOptions } from './internals/types';\nimport type { TRPCClientError } from './TRPCClientError';\n\n/**\n * @public\n * @deprecated use {@link TRPCClient} instead, will be removed in v12\n **/\nexport type inferRouterClient<TRouter extends AnyRouter> = TRPCClient<TRouter>;\n\n/**\n * @public\n * @deprecated use {@link TRPCClient} instead, will be removed in v12\n **/\nexport type CreateTRPCClient<TRouter extends AnyRouter> = TRPCClient<TRouter>;\n\nconst untypedClientSymbol = Symbol.for('trpc_untypedClient');\n\n/**\n * @public\n **/\nexport type TRPCClient<TRouter extends AnyRouter> = DecoratedProcedureRecord<\n {\n transformer: TRouter['_def']['_config']['$types']['transformer'];\n errorShape: TRouter['_def']['_config']['$types']['errorShape'];\n },\n TRouter['_def']['record']\n> & {\n [untypedClientSymbol]: TRPCUntypedClient<TRouter>;\n};\n\n/** @internal */\nexport type TRPCResolverDef = {\n input: any;\n output: any;\n transformer: boolean;\n errorShape: any;\n};\n\ntype coerceAsyncGeneratorToIterable<T> =\n T extends AsyncGenerator<infer $T, infer $Return, infer $Next>\n ? AsyncIterable<$T, $Return, $Next>\n : T;\n\n/** @internal */\nexport type Resolver<TDef extends TRPCResolverDef> = (\n input: TDef['input'],\n opts?: TRPCProcedureOptions,\n) => Promise<coerceAsyncGeneratorToIterable<TDef['output']>>;\n\n/** @internal */\nexport type SubscriptionResolver<TDef extends TRPCResolverDef> = (\n input: TDef['input'],\n opts: Partial<\n TRPCSubscriptionObserver<TDef['output'], TRPCClientError<TDef>>\n > &\n TRPCProcedureOptions,\n) => Unsubscribable;\n\ntype DecorateProcedure<\n TType extends ProcedureType,\n TDef extends TRPCResolverDef,\n> = TType extends 'query'\n ? {\n query: Resolver<TDef>;\n }\n : TType extends 'mutation'\n ? {\n mutate: Resolver<TDef>;\n }\n : TType extends 'subscription'\n ? {\n subscribe: SubscriptionResolver<TDef>;\n }\n : never;\n\n/**\n * @internal\n */\ntype DecoratedProcedureRecord<\n TRoot extends InferrableClientTypes,\n TRecord extends RouterRecord,\n> = {\n [TKey in keyof TRecord]: TRecord[TKey] extends infer $Value\n ? $Value extends AnyProcedure\n ? DecorateProcedure<\n $Value['_def']['type'],\n {\n input: inferProcedureInput<$Value>;\n output: inferTransformedProcedureOutput<\n inferClientTypes<TRoot>,\n $Value\n >;\n errorShape: inferClientTypes<TRoot>['errorShape'];\n transformer: inferClientTypes<TRoot>['transformer'];\n }\n >\n : $Value extends RouterRecord\n ? DecoratedProcedureRecord<TRoot, $Value>\n : never\n : never;\n};\n\nconst clientCallTypeMap: Record<\n keyof DecorateProcedure<any, any>,\n ProcedureType\n> = {\n query: 'query',\n mutate: 'mutation',\n subscribe: 'subscription',\n};\n\n/** @internal */\nexport const clientCallTypeToProcedureType = (\n clientCallType: string,\n): ProcedureType => {\n return clientCallTypeMap[clientCallType as keyof typeof clientCallTypeMap];\n};\n\n/**\n * @internal\n */\nexport function createTRPCClientProxy<TRouter extends AnyRouter>(\n client: TRPCUntypedClient<TRouter>,\n): TRPCClient<TRouter> {\n const proxy = createRecursiveProxy<TRPCClient<TRouter>>(({ path, args }) => {\n const pathCopy = [...path];\n const procedureType = clientCallTypeToProcedureType(pathCopy.pop()!);\n\n const fullPath = pathCopy.join('.');\n\n return (client[procedureType] as any)(fullPath, ...(args as any));\n });\n return createFlatProxy<TRPCClient<TRouter>>((key) => {\n if (key === untypedClientSymbol) {\n return client;\n }\n return proxy[key];\n });\n}\n\nexport function createTRPCClient<TRouter extends AnyRouter>(\n opts: CreateTRPCClientOptions<TRouter>,\n): TRPCClient<TRouter> {\n const client = new TRPCUntypedClient(opts);\n const proxy = createTRPCClientProxy<TRouter>(client);\n return proxy;\n}\n\n/**\n * Get an untyped client from a proxy client\n * @internal\n */\nexport function getUntypedClient<TRouter extends AnyRouter>(\n client: TRPCClient<TRouter>,\n): TRPCUntypedClient<TRouter> {\n return client[untypedClientSymbol];\n}\n","import type { AnyRouter, ProcedureType } from '@trpc/server';\nimport { observable } from '@trpc/server/observable';\nimport type { TRPCErrorShape, TRPCResponse } from '@trpc/server/rpc';\nimport type { AnyClientTypes } from '@trpc/server/unstable-core-do-not-import';\nimport { jsonlStreamConsumer } from '@trpc/server/unstable-core-do-not-import';\nimport type { BatchLoader } from '../internals/dataLoader';\nimport { dataLoader } from '../internals/dataLoader';\nimport { allAbortSignals, raceAbortSignals } from '../internals/signals';\nimport type { NonEmptyArray } from '../internals/types';\nimport { TRPCClientError } from '../TRPCClientError';\nimport type { HTTPBatchLinkOptions } from './HTTPBatchLinkOptions';\nimport type { HTTPResult } from './internals/httpUtils';\nimport {\n fetchHTTPResponse,\n getBody,\n getUrl,\n resolveHTTPLinkOptions,\n} from './internals/httpUtils';\nimport type { Operation, TRPCLink } from './types';\n\nexport type HTTPBatchStreamLinkOptions<TRoot extends AnyClientTypes> =\n HTTPBatchLinkOptions<TRoot> & {\n /**\n * Which header to use to signal the server that the client wants a streaming response.\n * - `'trpc-accept'` (default): sends `trpc-accept: application/jsonl` header\n * - `'accept'`: sends `Accept: application/jsonl` header, which can avoid CORS preflight for cross-origin streaming queries. Be aware that `application/jsonl` is not an official MIME type and so this is not completely spec-compliant - you should test that your infrastructure supports this value.\n * @default 'trpc-accept'\n */\n streamHeader?: 'trpc-accept' | 'accept';\n };\n\n/**\n * @see https://trpc.io/docs/client/links/httpBatchStreamLink\n */\nexport function httpBatchStreamLink<TRouter extends AnyRouter>(\n opts: HTTPBatchStreamLinkOptions<TRouter['_def']['_config']['$types']>,\n): TRPCLink<TRouter> {\n const resolvedOpts = resolveHTTPLinkOptions(opts);\n const maxURLLength = opts.maxURLLength ?? Infinity;\n const maxItems = opts.maxItems ?? Infinity;\n\n return () => {\n const batchLoader = (\n type: ProcedureType,\n ): BatchLoader<Operation, HTTPResult> => {\n return {\n validate(batchOps) {\n if (maxURLLength === Infinity && maxItems === Infinity) {\n // escape hatch for quick calcs\n return true;\n }\n if (batchOps.length > maxItems) {\n return false;\n }\n const path = batchOps.map((op) => op.path).join(',');\n const inputs = batchOps.map((op) => op.input);\n\n const url = getUrl({\n ...resolvedOpts,\n type,\n path,\n inputs,\n signal: null,\n });\n\n return url.length <= maxURLLength;\n },\n async fetch(batchOps) {\n const path = batchOps.map((op) => op.path).join(',');\n const inputs = batchOps.map((op) => op.input);\n\n const batchSignals = allAbortSignals(\n ...batchOps.map((op) => op.signal),\n );\n const abortController = new AbortController();\n\n const responsePromise = fetchHTTPResponse({\n ...resolvedOpts,\n signal: raceAbortSignals(batchSignals, abortController.signal),\n type,\n contentTypeHeader: 'application/json',\n trpcAcceptHeader: 'application/jsonl',\n trpcAcceptHeaderKey: opts.streamHeader ?? 'trpc-accept',\n getUrl,\n getBody,\n inputs,\n path,\n headers() {\n if (!opts.headers) {\n return {};\n }\n if (typeof opts.headers === 'function') {\n return opts.headers({\n opList: batchOps as NonEmptyArray<Operation>,\n });\n }\n return opts.headers;\n },\n });\n\n const res = await responsePromise;\n const [head] = await jsonlStreamConsumer<\n Record<string, Promise<any>>\n >({\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n from: res.body!,\n deserialize: (data) =>\n resolvedOpts.transformer.output.deserialize(data),\n // onError: console.error,\n formatError(opts) {\n const error = opts.error as TRPCErrorShape;\n return TRPCClientError.from({\n error,\n });\n },\n abortController,\n });\n const promises = Object.keys(batchOps).map(\n async (key): Promise<HTTPResult> => {\n let json: TRPCResponse = await Promise.resolve(head[key]);\n\n if ('result' in json) {\n /**\n * Not very pretty, but we need to unwrap nested data as promises\n * Our stream producer will only resolve top-level async values or async values that are directly nested in another async value\n */\n const result = await Promise.resolve(json.result);\n json = {\n result: {\n data: await Promise.resolve(result.data),\n },\n };\n }\n\n return {\n json,\n meta: {\n response: res,\n },\n };\n },\n );\n return promises;\n },\n };\n };\n\n const query = dataLoader(batchLoader('query'));\n const mutation = dataLoader(batchLoader('mutation'));\n\n const loaders = { query, mutation };\n return ({ op }) => {\n return observable((observer) => {\n /* istanbul ignore if -- @preserve */\n if (op.type === 'subscription') {\n throw new Error(\n 'Subscriptions are unsupported by `httpBatchStreamLink` - use `httpSubscriptionLink` or `wsLink`',\n );\n }\n const loader = loaders[op.type];\n const promise = loader.load(op);\n\n let _res = undefined as HTTPResult | undefined;\n promise\n .then((res) => {\n _res = res;\n if ('error' in res.json) {\n observer.error(\n TRPCClientError.from(res.json, {\n meta: res.meta,\n }),\n );\n return;\n } else if ('result' in res.json) {\n observer.next({\n context: res.meta,\n result: res.json.result,\n });\n observer.complete();\n return;\n }\n\n observer.complete();\n })\n .catch((err) => {\n observer.error(\n TRPCClientError.from(err, {\n meta: _res?.meta,\n }),\n );\n });\n\n return () => {\n // noop\n };\n });\n };\n };\n}\n\n/**\n * @deprecated use {@link httpBatchStreamLink} instead\n */\nexport const unstable_httpBatchStreamLink = httpBatchStreamLink;\n","export function inputWithTrackedEventId(\n input: unknown,\n lastEventId: string | undefined,\n) {\n if (!lastEventId) {\n return input;\n }\n if (input != null && typeof input !== 'object') {\n return input;\n }\n return {\n ...(input ?? {}),\n lastEventId,\n };\n}\n","function _asyncIterator(r) {\n var n,\n t,\n o,\n e = 2;\n for (\"undefined\" != typeof Symbol && (t = Symbol.asyncIterator, o = Symbol.iterator); e--;) {\n if (t && null != (n = r[t])) return n.call(r);\n if (o && null != (n = r[o])) return new AsyncFromSyncIterator(n.call(r));\n t = \"@@asyncIterator\", o = \"@@iterator\";\n }\n throw new TypeError(\"Object is not async iterable\");\n}\nfunction AsyncFromSyncIterator(r) {\n function AsyncFromSyncIteratorContinuation(r) {\n if (Object(r) !== r) return Promise.reject(new TypeError(r + \" is not an object.\"));\n var n = r.done;\n return Promise.resolve(r.value).then(function (r) {\n return {\n value: r,\n done: n\n };\n });\n }\n return AsyncFromSyncIterator = function AsyncFromSyncIterator(r) {\n this.s = r, this.n = r.next;\n }, AsyncFromSyncIterator.prototype = {\n s: null,\n n: null,\n next: function next() {\n return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments));\n },\n \"return\": function _return(r) {\n var n = this.s[\"return\"];\n return void 0 === n ? Promise.resolve({\n value: r,\n done: !0\n }) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments));\n },\n \"throw\": function _throw(r) {\n var n = this.s[\"return\"];\n return void 0 === n ? Promise.reject(r) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments));\n }\n }, new AsyncFromSyncIterator(r);\n}\nmodule.exports = _asyncIterator, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","import { behaviorSubject, observable } from '@trpc/server/observable';\nimport type { TRPCErrorShape, TRPCResult } from '@trpc/server/rpc';\nimport type {\n AnyClientTypes,\n EventSourceLike,\n inferClientTypes,\n InferrableClientTypes,\n} from '@trpc/server/unstable-core-do-not-import';\nimport {\n retryableRpcCodes,\n run,\n sseStreamConsumer,\n} from '@trpc/server/unstable-core-do-not-import';\nimport { inputWithTrackedEventId } from '../internals/inputWithTrackedEventId';\nimport { raceAbortSignals } from '../internals/signals';\nimport { TRPCClientError } from '../TRPCClientError';\nimport type { TRPCConnectionState } from '../unstable-internals';\nimport { getTransformer, type TransformerOptions } from '../unstable-internals';\nimport { getUrl } from './internals/httpUtils';\nimport {\n resultOf,\n type UrlOptionsWithConnectionParams,\n} from './internals/urlWithConnectionParams';\nimport type { Operation, TRPCLink } from './types';\n\nasync function urlWithConnectionParams(\n opts: UrlOptionsWithConnectionParams,\n): Promise<string> {\n let url = await resultOf(opts.url);\n if (opts.connectionParams) {\n const params = await resultOf(opts.connectionParams);\n\n const prefix = url.includes('?') ? '&' : '?';\n url +=\n prefix + 'connectionParams=' + encodeURIComponent(JSON.stringify(params));\n }\n\n return url;\n}\n\ntype HTTPSubscriptionLinkOptions<\n TRoot extends AnyClientTypes,\n TEventSource extends EventSourceLike.AnyConstructor = typeof EventSource,\n> = {\n /**\n * EventSource ponyfill\n */\n EventSource?: TEventSource;\n /**\n * EventSource options or a callback that returns them\n */\n eventSourceOptions?:\n | EventSourceLike.InitDictOf<TEventSource>\n | ((opts: {\n op: Operation;\n }) =>\n | EventSourceLike.InitDictOf<TEventSource>\n | Promise<EventSourceLike.InitDictOf<TEventSource>>);\n} & TransformerOptions<TRoot> &\n UrlOptionsWithConnectionParams;\n\n/**\n * @see https://trpc.io/docs/client/links/httpSubscriptionLink\n */\nexport function httpSubscriptionLink<\n TInferrable extends InferrableClientTypes,\n TEventSource extends EventSourceLike.AnyConstructor,\n>(\n opts: HTTPSubscriptionLinkOptions<\n inferClientTypes<TInferrable>,\n TEventSource\n >,\n): TRPCLink<TInferrable> {\n const transformer = getTransformer(opts.transformer);\n\n return () => {\n return ({ op }) => {\n return observable((observer) => {\n const { type, path, input } = op;\n\n /* istanbul ignore if -- @preserve */\n if (type !== 'subscription') {\n throw new Error('httpSubscriptionLink only supports subscriptions');\n }\n\n let lastEventId: string | undefined = undefined;\n const ac = new AbortController();\n const signal = raceAbortSignals(op.signal, ac.signal);\n const eventSourceStream = sseStreamConsumer<{\n EventSource: TEventSource;\n data: Partial<{\n id?: string;\n data: unknown;\n }>;\n error: TRPCErrorShape;\n }>({\n url: async () =>\n getUrl({\n transformer,\n url: await urlWithConnectionParams(opts),\n input: inputWithTrackedEventId(input, lastEventId),\n path,\n type,\n signal: null,\n }),\n init: () => resultOf(opts.eventSourceOptions, { op }),\n signal,\n deserialize: (data) => transformer.output.deserialize(data),\n EventSource:\n opts.EventSource ??\n (globalThis.EventSource as never as TEventSource),\n });\n\n const connectionState = behaviorSubject<\n TRPCConnectionState<TRPCClientError<any>>\n >({\n type: 'state',\n state: 'connecting',\n error: null,\n });\n\n const connectionSub = connectionState.subscribe({\n next(state) {\n observer.next({\n result: state,\n });\n },\n });\n run(async () => {\n for await (const chunk of eventSourceStream) {\n switch (chunk.type) {\n case 'ping':\n // do nothing\n break;\n case 'data':\n const chunkData = chunk.data;\n\n let result: TRPCResult<unknown>;\n if (chunkData.id) {\n // if the `tracked()`-helper is used, we always have an `id` field\n lastEventId = chunkData.id;\n result = {\n id: chunkData.id,\n data: chunkData,\n };\n } else {\n result = {\n data: chunkData.data,\n };\n }\n\n observer.next({\n result,\n context: {\n eventSource: chunk.eventSource,\n },\n });\n break;\n case 'connected': {\n observer.next({\n result: {\n type: 'started',\n },\n context: {\n eventSource: chunk.eventSource,\n },\n });\n connectionState.next({\n type: 'state',\n state: 'pending',\n error: null,\n });\n break;\n }\n case 'serialized-error': {\n const error = TRPCClientError.from({ error: chunk.error });\n\n if (retryableRpcCodes.includes(chunk.error.code)) {\n //\n connectionState.next({\n type: 'state',\n state: 'connecting',\n error,\n });\n break;\n }\n //\n // non-retryable error, cancel the subscription\n throw error;\n }\n case 'connecting': {\n const lastState = connectionState.get();\n\n const error = chunk.event && TRPCClientError.from(chunk.event);\n if (!error && lastState.state === 'connecting') {\n break;\n }\n\n connectionState.next({\n type: 'state',\n state: 'connecting',\n error,\n });\n break;\n }\n case 'timeout': {\n connectionState.next({\n type: 'state',\n state: 'connecting',\n error: new TRPCClientError(\n `Timeout of ${chunk.ms}ms reached while waiting for a response`,\n ),\n });\n }\n }\n }\n observer.next({\n result: {\n type: 'stopped',\n },\n });\n connectionState.next({\n type: 'state',\n state: 'idle',\n error: null,\n });\n observer.complete();\n }).catch((error) => {\n observer.error(TRPCClientError.from(error));\n });\n\n return () => {\n observer.complete();\n ac.abort();\n connectionSub.unsubscribe();\n };\n });\n };\n };\n}\n\n/**\n * @deprecated use {@link httpSubscriptionLink} instead\n */\nexport const unstable_httpSubscriptionLink = httpSubscriptionLink;\n","/* istanbul ignore file -- @preserve */\n// We're not actually exporting this link\nimport type { Unsubscribable } from '@trpc/server/observable';\nimport { observable } from '@trpc/server/observable';\nimport type { InferrableClientTypes } from '@trpc/server/unstable-core-do-not-import';\nimport { inputWithTrackedEventId } from '../internals/inputWithTrackedEventId';\nimport type { TRPCClientError } from '../TRPCClientError';\nimport type { Operation, TRPCLink } from './types';\n\ninterface RetryLinkOptions<TInferrable extends InferrableClientTypes> {\n /**\n * The retry function\n */\n retry: (opts: RetryFnOptions<TInferrable>) => boolean;\n /**\n * The delay between retries in ms (defaults to 0)\n */\n retryDelayMs?: (attempt: number) => number;\n}\n\ninterface RetryFnOptions<TInferrable extends InferrableClientTypes> {\n /**\n * The operation that failed\n */\n op: Operation;\n /**\n * The error that occurred\n */\n error: TRPCClientError<TInferrable>;\n /**\n * The number of attempts that have been made (including the first call)\n */\n attempts: number;\n}\n\n/**\n * @see https://trpc.io/docs/v11/client/links/retryLink\n */\nexport function retryLink<TInferrable extends InferrableClientTypes>(\n opts: RetryLinkOptions<TInferrable>,\n): TRPCLink<TInferrable> {\n // initialized config\n return () => {\n // initialized in app\n return (callOpts) => {\n // initialized for request\n return observable((observer) => {\n let next$: Unsubscribable;\n let callNextTimeout: ReturnType<typeof setTimeout> | undefined =\n undefined;\n\n let lastEventId: string | undefined = undefined;\n\n attempt(1);\n\n function opWithLastEventId() {\n const op = callOpts.op;\n if (!lastEventId) {\n return op;\n }\n\n return {\n ...op,\n input: inputWithTrackedEventId(op.input, lastEventId),\n };\n }\n\n function attempt(attempts: number) {\n const op = opWithLastEventId();\n\n next$ = callOpts.next(op).subscribe({\n error(error) {\n const shouldRetry = opts.retry({\n op,\n attempts,\n error,\n });\n if (!shouldRetry) {\n observer.error(error);\n return;\n }\n const delayMs = opts.retryDelayMs?.(attempts) ?? 0;\n\n if (delayMs <= 0) {\n attempt(attempts + 1);\n return;\n }\n callNextTimeout = setTimeout(\n () => attempt(attempts + 1),\n delayMs,\n );\n },\n next(envelope) {\n //\n if (\n (!envelope.result.type || envelope.result.type === 'data') &&\n envelope.result.id\n ) {\n //\n lastEventId = envelope.result.id;\n }\n\n observer.next(envelope);\n },\n complete() {\n observer.complete();\n },\n });\n }\n return () => {\n next$.unsubscribe();\n clearTimeout(callNextTimeout);\n };\n });\n };\n };\n}\n","function _usingCtx() {\n var r = \"function\" == typeof SuppressedError ? SuppressedError : function (r, e) {\n var n = Error();\n return n.name = \"SuppressedError\", n.error = r, n.suppressed = e, n;\n },\n e = {},\n n = [];\n function using(r, e) {\n if (null != e) {\n if (Object(e) !== e) throw new TypeError(\"using declarations can only be used with objects, functions, null, or undefined.\");\n if (r) var o = e[Symbol.asyncDispose || Symbol[\"for\"](\"Symbol.asyncDispose\")];\n if (void 0 === o && (o = e[Symbol.dispose || Symbol[\"for\"](\"Symbol.dispose\")], r)) var t = o;\n if (\"function\" != typeof o) throw new TypeError(\"Object is not disposable.\");\n t && (o = function o() {\n try {\n t.call(e);\n } catch (r) {\n return Promise.reject(r);\n }\n }), n.push({\n v: e,\n d: o,\n a: r\n });\n } else r && n.push({\n d: e,\n a: r\n });\n return e;\n }\n return {\n e: e,\n u: using.bind(null, !1),\n a: using.bind(null, !0),\n d: function d() {\n var o,\n t = this.e,\n s = 0;\n function next() {\n for (; o = n.pop();) try {\n if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next);\n if (o.d) {\n var r = o.d.call(o.v);\n if (o.a) return s |= 2, Promise.resolve(r).then(next, err);\n } else s |= 1;\n } catch (r) {\n return err(r);\n }\n if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve();\n if (t !== e) throw t;\n }\n function err(n) {\n return t = t !== e ? new r(n, t) : n, next();\n }\n return next();\n }\n };\n}\nmodule.exports = _usingCtx, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","function _OverloadYield(e, d) {\n this.v = e, this.k = d;\n}\nmodule.exports = _OverloadYield, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var OverloadYield = require(\"./OverloadYield.js\");\nfunction _awaitAsyncGenerator(e) {\n return new OverloadYield(e, 0);\n}\nmodule.exports = _awaitAsyncGenerator, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var OverloadYield = require(\"./OverloadYield.js\");\nfunction _wrapAsyncGenerator(e) {\n return function () {\n return new AsyncGenerator(e.apply(this, arguments));\n };\n}\nfunction AsyncGenerator(e) {\n var r, t;\n function resume(r, t) {\n try {\n var n = e[r](t),\n o = n.value,\n u = o instanceof OverloadYield;\n Promise.resolve(u ? o.v : o).then(function (t) {\n if (u) {\n var i = \"return\" === r ? \"return\" : \"next\";\n if (!o.k || t.done) return resume(i, t);\n t = e[i](t).value;\n }\n settle(n.done ? \"return\" : \"normal\", t);\n }, function (e) {\n resume(\"throw\", e);\n });\n } catch (e) {\n settle(\"throw\", e);\n }\n }\n function settle(e, n) {\n switch (e) {\n case \"return\":\n r.resolve({\n value: n,\n done: !0\n });\n break;\n case \"throw\":\n r.reject(n);\n break;\n default:\n r.resolve({\n value: n,\n done: !1\n });\n }\n (r = r.next) ? resume(r.key, r.arg) : t = null;\n }\n this._invoke = function (e, n) {\n return new Promise(function (o, u) {\n var i = {\n key: e,\n arg: n,\n resolve: o,\n reject: u,\n next: null\n };\n t ? t = t.next = i : (r = t = i, resume(e, n));\n });\n }, \"function\" != typeof e[\"return\"] && (this[\"return\"] = void 0);\n}\nAsyncGenerator.prototype[\"function\" == typeof Symbol && Symbol.asyncIterator || \"@@asyncIterator\"] = function () {\n return this;\n}, AsyncGenerator.prototype.next = function (e) {\n return this._invoke(\"next\", e);\n}, AsyncGenerator.prototype[\"throw\"] = function (e) {\n return this._invoke(\"throw\", e);\n}, AsyncGenerator.prototype[\"return\"] = function (e) {\n return this._invoke(\"return\", e);\n};\nmodule.exports = _wrapAsyncGenerator, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","import {\n getTRPCErrorFromUnknown,\n getTRPCErrorShape,\n isTrackedEnvelope,\n} from '@trpc/server';\nimport { behaviorSubject, observable } from '@trpc/server/observable';\nimport { TRPC_ERROR_CODES_BY_KEY, type TRPCResult } from '@trpc/server/rpc';\nimport {\n callProcedure,\n isAbortError,\n isAsyncIterable,\n iteratorResource,\n makeResource,\n retryableRpcCodes,\n run,\n type AnyRouter,\n type ErrorHandlerOptions,\n type inferClientTypes,\n type inferRouterContext,\n} from '@trpc/server/unstable-core-do-not-import';\nimport { inputWithTrackedEventId } from '../internals/inputWithTrackedEventId';\nimport { abortSignalToPromise, raceAbortSignals } from '../internals/signals';\nimport { getTransformer } from '../internals/transformer';\nimport type { TransformerOptions } from '../internals/transformer';\nimport { isTRPCClientError, TRPCClientError } from '../TRPCClientError';\nimport type { TRPCConnectionState } from './internals/subscriptions';\nimport type { TRPCLink } from './types';\n\nexport type LocalLinkOptions<TRouter extends AnyRouter> = {\n router: TRouter;\n createContext: () => Promise<inferRouterContext<TRouter>>;\n onError?: (opts: ErrorHandlerOptions<inferRouterContext<TRouter>>) => void;\n} & TransformerOptions<inferClientTypes<TRouter>>;\n\n/**\n * localLink is a terminating link that allows you to make tRPC procedure calls directly in your application without going through HTTP.\n *\n * @see https://trpc.io/docs/links/localLink\n */\nexport function unstable_localLink<TRouter extends AnyRouter>(\n opts: LocalLinkOptions<TRouter>,\n): TRPCLink<TRouter> {\n const transformer = getTransformer(opts.transformer);\n\n const transformChunk = (chunk: unknown) => {\n if (opts.transformer) {\n // assume transformer will do the right thing\n return chunk;\n }\n // Special case for undefined, because `JSON.stringify(undefined)` throws\n if (chunk === undefined) {\n return chunk;\n }\n const serialized = JSON.stringify(transformer.input.serialize(chunk));\n const deserialized = JSON.parse(transformer.output.deserialize(serialized));\n return deserialized;\n };\n\n return () =>\n ({ op }) =>\n observable((observer) => {\n let ctx: inferRouterContext<TRouter> | undefined = undefined;\n const ac = new AbortController();\n\n const signal = raceAbortSignals(op.signal, ac.signal);\n const signalPromise = abortSignalToPromise(signal);\n\n signalPromise.catch(() => {\n // prevent unhandled rejection\n });\n\n let input = op.input;\n async function runProcedure(newInput: unknown): Promise<unknown> {\n input = newInput;\n\n ctx = await opts.createContext();\n\n return callProcedure({\n router: opts.router,\n path: op.path,\n getRawInput: async () => newInput,\n ctx,\n type: op.type,\n signal,\n batchIndex: 0,\n });\n }\n\n function onErrorCallback(cause: unknown) {\n if (isAbortError(cause)) {\n return;\n }\n opts.onError?.({\n error: getTRPCErrorFromUnknown(cause),\n type: op.type,\n path: op.path,\n input,\n ctx,\n });\n }\n\n function coerceToTRPCClientError(cause: unknown) {\n if (isTRPCClientError<TRouter>(cause)) {\n return cause;\n }\n const error = getTRPCErrorFromUnknown(cause);\n\n const shape = getTRPCErrorShape({\n config: opts.router._def._config,\n ctx,\n error,\n input,\n path: op.path,\n type: op.type,\n });\n return TRPCClientError.from(\n { error: transformChunk(shape) },\n { cause: cause instanceof Error ? cause : undefined },\n );\n }\n\n run(async () => {\n switch (op.type) {\n case 'query':\n case 'mutation': {\n const result = await runProcedure(op.input);\n if (!isAsyncIterable(result)) {\n observer.next({\n result: { data: transformChunk(result) },\n });\n observer.complete();\n break;\n }\n\n observer.next({\n result: {\n data: (async function* () {\n await using iterator = iteratorResource(result);\n using _finally = makeResource({}, () => {\n observer.complete();\n });\n try {\n while (true) {\n const res = await Promise.race([\n iterator.next(),\n signalPromise,\n ]);\n if (res.done) {\n return transformChunk(res.value);\n }\n yield transformChunk(res.value);\n }\n } catch (cause) {\n onErrorCallback(cause);\n throw coerceToTRPCClientError(cause);\n }\n })(),\n },\n });\n break;\n }\n case 'subscription': {\n const connectionState = behaviorSubject<\n TRPCConnectionState<TRPCClientError<any>>\n >({\n type: 'state',\n state: 'connecting',\n error: null,\n });\n\n const connectionSub = connectionState.subscribe({\n next(state) {\n observer.next({\n result: state,\n });\n },\n });\n let lastEventId: string | undefined = undefined;\n\n using _finally = makeResource({}, async () => {\n observer.complete();\n\n connectionState.next({\n type: 'state',\n state: 'idle',\n error: null,\n });\n connectionSub.unsubscribe();\n });\n while (true) {\n const result = await runProcedure(\n inputWithTrackedEventId(op.input, lastEventId),\n );\n if (!isAsyncIterable(result)) {\n throw new Error('Expected an async iterable');\n }\n await using iterator = iteratorResource(result);\n\n observer.next({\n result: {\n type: 'started',\n },\n });\n connectionState.next({\n type: 'state',\n state: 'pending',\n error: null,\n });\n\n // Use a while loop to handle errors and reconnects\n while (true) {\n let res;\n try {\n res = await Promise.race([iterator.next(), signalPromise]);\n } catch (cause) {\n if (isAbortError(cause)) {\n return;\n }\n const error = getTRPCErrorFromUnknown(cause);\n\n if (\n !retryableRpcCodes.includes(\n TRPC_ERROR_CODES_BY_KEY[error.code],\n )\n ) {\n throw coerceToTRPCClientError(error);\n }\n\n onErrorCallback(error);\n connectionState.next({\n type: 'state',\n state: 'connecting',\n error: coerceToTRPCClientError(error),\n });\n\n break;\n }\n\n if (res.done) {\n return;\n }\n let chunk: TRPCResult<unknown>;\n if (isTrackedEnvelope(res.value)) {\n lastEventId = res.value[0];\n\n chunk = {\n id: res.value[0],\n data: {\n id: res.value[0],\n data: res.value[1],\n },\n };\n } else {\n chunk = {\n data: res.value,\n };\n }\n\n observer.next({\n result: {\n ...chunk,\n data: transformChunk(chunk.data),\n },\n });\n }\n }\n break;\n }\n }\n }).catch((cause) => {\n onErrorCallback(cause);\n observer.error(coerceToTRPCClientError(cause));\n });\n\n return () => {\n ac.abort();\n };\n });\n}\n/**\n * @deprecated Renamed to `unstable_localLink`. This alias will be removed in a future major release.\n */\nexport const experimental_localLink: typeof unstable_localLink =\n unstable_localLink;\n","export {\n ensureBinary,\n downloadBinary,\n findInPath,\n getPlatformInfo,\n buildBinaryPath,\n} from './deps/binary-downloader.js'\nexport { ensureFfmpeg, getFfmpegDownloadUrl } from './deps/ffmpeg-downloader.js'\nexport {\n ensurePython,\n installPythonPackages,\n getPythonDownloadUrl,\n PYTHON_VERSION,\n} from './deps/python-downloader.js'\nexport { EventBus } from './events/event-bus.js'\nexport { downloadModel, downloadFile, fetchJson } from './download/model-downloader.js'\nexport { ModelDownloadService } from './download/model-download-service.js'\nexport { PythonEnvManager } from './python/python-env-manager.js'\nexport type { ValidationIssue, ValidationResult } from './pipeline/pipeline-validator.js'\nexport { PipelineValidator } from './pipeline/pipeline-validator.js'\nexport { PipelineRunner } from './pipeline/pipeline-runner.js'\n\n// Process management\nexport { ProcessManager } from './process/process-manager.js'\nexport { ManagedProcess } from './process/managed-process.js'\nexport type {\n ProcessConfig,\n ProcessStats,\n ManagedProcessStatus,\n ProcessState,\n ProcessEventEmitter,\n ProcessLoggerFactory,\n} from './process/interfaces.js'\n\n// Network quality tracking\nexport { NetworkQualityTracker } from './network/network-quality.js'\nexport type {\n StreamNetworkStats,\n ClientNetworkStats,\n DeviceNetworkStats,\n INetworkQualityTracker,\n} from './network/network-quality.js'\n\n// REPL engine\nexport { ReplEngine } from './repl/repl-engine.js'\nexport type {\n ReplScope,\n ReplSessionContext,\n ReplResult,\n IReplEngine,\n IReplContextProvider,\n} from './repl/interfaces.js'\n\n// Agent registry and task dispatcher\nexport { AgentRegistry } from './agent/agent-registry.js'\nexport { TaskDispatcher } from './agent/task-dispatcher.js'\nexport { AgentClient } from './agent/agent-client.js'\nexport type { AgentClientConfig, MessageHandler, BinaryHandler, ConnectionHandler } from './agent/agent-client.js'\nexport { AgentTaskRunner } from './agent/agent-task-runner.js'\nexport { DecodeTaskHandler, DetectTaskHandler, RecordTaskHandler } from './agent/pipeline-task-handlers.js'\nexport type {\n AgentInfo,\n AgentResources,\n AgentStatus,\n AgentTask,\n AgentTaskResult,\n TaskDispatchOptions,\n AgentEntry,\n AgentEventEmitter,\n} from './agent/interfaces.js'\n\n// Builtin providers — default implementations that register through CapabilityRegistry\n// and CAN be replaced by external addons.\nexport { SqliteStorageAddon } from './builtins/sqlite-storage/index.js'\nexport { SettingsStore } from './builtins/sqlite-storage/index.js'\nexport { CORE_TABLE_DDL, addonTableToDdl } from './builtins/sqlite-storage/index.js'\nexport type { AddonTableSchema } from './builtins/sqlite-storage/index.js'\nexport { SqliteStorageProvider, FileSystemStorage } from './builtins/sqlite-storage/index.js'\nexport { WinstonLoggingAddon } from './builtins/winston-logging/index.js'\nexport { WinstonDestination } from './builtins/winston-logging/index.js'\nexport { LocalBackupAddon } from './builtins/local-backup/index.js'\nexport { LocalBackupService } from './builtins/local-backup/index.js'\nexport type { BackupManifest, BackupConfig } from './builtins/local-backup/index.js'\n// Lifecycle\nexport { LifecycleStateMachine } from './lifecycle/lifecycle-state-machine.js'\nexport type {\n ElementState,\n ElementStatus,\n} from './lifecycle/lifecycle-state-machine.js'\n\n// Feature\nexport { FeatureManager } from './feature/feature-manager.js'\nexport type {\n FeatureManifest,\n FeatureFlag,\n FeatureConfigReader,\n} from './feature/feature-manager.js'\n\n// Events (system-level event bus with ring buffer)\nexport { SystemEventBus } from './events/system-event-bus.js'\nexport type {\n SystemEvent,\n EventSource,\n EventFilter,\n} from './events/system-event-bus.js'\n\n// Logging\nexport { LogManager } from './logging/log-manager.js'\nexport type { ILogDestination } from './logging/log-manager.js'\nexport { LogRingBuffer } from './logging/log-ring-buffer.js'\nexport type { LogEntry, LogFilter, LogLevel } from './logging/log-ring-buffer.js'\nexport { ScopedLogger } from './logging/scoped-logger.js'\nexport type { IScopedLogger } from './logging/scoped-logger.js'\n\n// Storage\nexport { StorageManager } from './storage/storage-manager.js'\nexport type {\n IStorageProvider as ICoreStorageProvider,\n IStorageLocation,\n IStructuredStorage,\n IFileStorage,\n QueryFilter,\n StorageRecord,\n} from './storage/storage-manager.js'\nexport { StorageLocationManager } from './storage/storage-location-manager.js'\nexport type { StorageLocationName } from './storage/storage-location-manager.js'\nexport { FsStorageBackend } from './storage/fs-storage-backend.js'\nexport type { IStorageBackend } from './storage/fs-storage-backend.js'\n\n// Auth\nexport { AuthManager } from './auth/auth-manager.js'\nexport type { UserRole, TokenPayload, AuthConfigReader } from './auth/auth-manager.js'\nexport { ApiKeyManager } from './auth/api-key-manager.js'\nexport type { ApiKeyRecord, ApiKeyStorageAccess } from './auth/api-key-manager.js'\nexport { UserManager } from './auth/user-manager.js'\nexport type { UserRecord, UserStorageAccess, UserConfigReader } from './auth/user-manager.js'\nexport { ScopedTokenManager } from './auth/scoped-token-manager.js'\n\n// Notification\nexport { NotificationService } from './notification/notification-service.js'\nexport { ToastService } from './notification/toast-service.js'\nexport type { Unsubscribe } from './notification/toast-service.js'\n\n// Addon routes\nexport { AddonRouteRegistry } from './addon-routes/addon-route-registry.js'\n\n// Device\nexport { DeviceRegistry } from './device/device-registry.js'\nexport type {\n IRegisteredDevice,\n} from './device/device-registry.js'\nexport { CapabilityResolver } from './device/capability-resolver.js'\nexport type {\n IDeviceCapability,\n CapabilityBinding,\n IResolvableDevice,\n IAddonRegistryAccess,\n} from './device/capability-resolver.js'\n\n// TLS\nexport * from './tls/index.js'\n\n// Addon API Factory\nexport { AddonApiFactory } from './addon/addon-api-factory.js'\nexport type { DirectCallerOptions, WssClientOptions } from './addon/addon-api-factory.js'\n\n// Platform\nexport { PlatformScorer } from './platform/platform-scorer.js'\nexport { InferenceConfigResolver } from './platform/inference-config-resolver.js'\n\n// Integration & Device Registry\nexport { IntegrationRegistry } from './builtins/sqlite-storage/integration-registry.js'\n\n// Provider\nexport { ProviderManager } from './provider/provider-manager.js'\nexport type {\n ProviderDeviceRegistry,\n IManagedProvider,\n ProviderListItem,\n} from './provider/provider-manager.js'\n","import { existsSync, mkdirSync, chmodSync, createWriteStream, unlinkSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { pipeline } from 'node:stream/promises'\nimport { Readable } from 'node:stream'\nimport { execFileSync } from 'node:child_process'\nimport type { IScopedLogger } from '@camstack/types'\n\nexport interface PlatformInfo {\n readonly platform: NodeJS.Platform\n readonly arch: NodeJS.Architecture\n}\n\nexport function getPlatformInfo(): PlatformInfo {\n return {\n platform: process.platform,\n arch: process.arch,\n }\n}\n\nexport function buildBinaryPath(dataDir: string, name: string, platform?: string): string {\n const ext = (platform ?? process.platform) === 'win32' ? '.exe' : ''\n return join(dataDir, 'deps', `${name}${ext}`)\n}\n\n/** Check if a binary exists in PATH */\nexport function findInPath(name: string): string | null {\n try {\n execFileSync(name, ['--version'], { stdio: 'pipe', timeout: 5000 })\n return name\n } catch {\n return null\n }\n}\n\nexport interface DownloadOptions {\n readonly name: string\n readonly url: string\n readonly targetDir: string\n readonly targetName: string\n readonly logger: IScopedLogger\n readonly isArchive?: boolean\n readonly archiveFormat?: 'zip' | 'tar.gz' | 'tar.xz'\n /** Relative path within archive to the binary (e.g., 'ffmpeg-6.1/bin/ffmpeg') */\n readonly archiveInnerPath?: string\n}\n\n/**\n * Download a binary to the target directory.\n * Handles archives (zip, tar.gz, tar.xz) and raw binaries.\n */\nexport async function downloadBinary(opts: DownloadOptions): Promise<string> {\n const { name, url, targetDir, targetName, logger, isArchive, archiveFormat, archiveInnerPath } = opts\n const targetPath = join(targetDir, targetName)\n\n if (existsSync(targetPath)) {\n logger.debug(`${name} binary already exists at ${targetPath}`)\n return targetPath\n }\n\n mkdirSync(targetDir, { recursive: true })\n\n logger.info(`Downloading ${name} from ${url}`)\n const response = await fetch(url, { redirect: 'follow' })\n if (!response.ok || !response.body) {\n throw new Error(`Failed to download ${name}: ${response.status} ${response.statusText}`)\n }\n\n if (isArchive) {\n const ext = archiveFormat ?? 'tar.gz'\n const tmpArchive = join(targetDir, `${name}-download.${ext}`)\n const nodeStream = Readable.fromWeb(response.body as any)\n await pipeline(nodeStream, createWriteStream(tmpArchive))\n\n // Extract\n const tmpExtractDir = join(targetDir, `${name}-extract`)\n mkdirSync(tmpExtractDir, { recursive: true })\n\n if (ext === 'zip') {\n try {\n execFileSync('unzip', ['-o', '-q', tmpArchive, '-d', tmpExtractDir], { stdio: 'pipe' })\n } catch {\n execFileSync('tar', ['-xf', tmpArchive, '-C', tmpExtractDir], { stdio: 'pipe' })\n }\n } else if (ext === 'tar.xz') {\n execFileSync('tar', ['-xJf', tmpArchive, '-C', tmpExtractDir], { stdio: 'pipe' })\n } else {\n execFileSync('tar', ['-xzf', tmpArchive, '-C', tmpExtractDir], { stdio: 'pipe' })\n }\n\n // Copy binary from archive\n if (archiveInnerPath) {\n const { copyFileSync } = await import('node:fs')\n const sourcePath = join(tmpExtractDir, archiveInnerPath)\n if (!existsSync(sourcePath)) {\n throw new Error(`Binary not found in archive at ${archiveInnerPath}`)\n }\n copyFileSync(sourcePath, targetPath)\n }\n\n // Cleanup\n unlinkSync(tmpArchive)\n const { rmSync } = await import('node:fs')\n rmSync(tmpExtractDir, { recursive: true, force: true })\n } else {\n // Direct binary download\n const nodeStream = Readable.fromWeb(response.body as any)\n await pipeline(nodeStream, createWriteStream(targetPath))\n }\n\n chmodSync(targetPath, 0o755)\n logger.info(`${name} downloaded to ${targetPath}`)\n return targetPath\n}\n\n/**\n * Ensure a binary is available. Checks:\n * 1. Target path (already downloaded)\n * 2. System PATH\n * 3. Download from URL\n */\nexport async function ensureBinary(opts: {\n readonly name: string\n readonly targetDir: string\n readonly downloadUrl: string\n readonly logger: IScopedLogger\n readonly isArchive?: boolean\n readonly archiveFormat?: 'zip' | 'tar.gz' | 'tar.xz'\n readonly archiveInnerPath?: string\n}): Promise<string> {\n const ext = process.platform === 'win32' ? '.exe' : ''\n const targetName = `${opts.name}${ext}`\n const targetPath = join(opts.targetDir, targetName)\n\n // 1. Already downloaded\n if (existsSync(targetPath)) {\n opts.logger.debug(`${opts.name} found at ${targetPath}`)\n return targetPath\n }\n\n // 2. System PATH\n const inPath = findInPath(opts.name)\n if (inPath) {\n opts.logger.info(`${opts.name} found in system PATH`)\n return inPath\n }\n\n // 3. Download\n return downloadBinary({\n name: opts.name,\n url: opts.downloadUrl,\n targetDir: opts.targetDir,\n targetName,\n logger: opts.logger,\n isArchive: opts.isArchive,\n archiveFormat: opts.archiveFormat,\n archiveInnerPath: opts.archiveInnerPath,\n })\n}\n","/**\n * Download ffmpeg static build for the current platform.\n *\n * Sources:\n * - Linux: https://johnvansickle.com/ffmpeg/ (static builds)\n * - macOS: https://evermeet.cx/ffmpeg/ or homebrew\n *\n * Using BtbN's GitHub releases as they cover both platforms:\n * https://github.com/BtbN/FFmpeg-Builds/releases\n */\nimport { join } from 'node:path'\nimport type { IScopedLogger } from '@camstack/types'\nimport { ensureBinary } from './binary-downloader.js'\n\nconst FFMPEG_VERSION = '7.1'\n\nexport function getFfmpegDownloadUrl(platform: string, arch: string): string {\n switch (platform) {\n case 'linux': {\n const archMap: Record<string, string> = { x64: 'amd64', arm64: 'arm64' }\n const a = archMap[arch]\n if (!a) throw new Error(`Unsupported Linux architecture: ${arch}`)\n // John Van Sickle static builds — well-tested, widely used\n return `https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-${a}-static.tar.xz`\n }\n case 'darwin': {\n const archMap: Record<string, string> = { arm64: 'arm64', x64: 'amd64' }\n const a = archMap[arch]\n if (!a) throw new Error(`Unsupported macOS architecture: ${arch}`)\n // macOS static builds from osxexperts (maintained, universal builds)\n return `https://www.osxexperts.net/ffmpeg${FFMPEG_VERSION.replace('.', '')}arm.zip`\n }\n default:\n throw new Error(`Unsupported platform: ${platform}`)\n }\n}\n\nexport function getFfmpegArchiveInfo(platform: string): {\n isArchive: boolean\n archiveFormat: 'zip' | 'tar.gz' | 'tar.xz'\n archiveInnerPath: string\n} {\n switch (platform) {\n case 'linux':\n return {\n isArchive: true,\n archiveFormat: 'tar.xz',\n archiveInnerPath: `ffmpeg-${FFMPEG_VERSION}-amd64-static/ffmpeg`,\n }\n case 'darwin':\n return {\n isArchive: true,\n archiveFormat: 'zip',\n archiveInnerPath: 'ffmpeg',\n }\n default:\n throw new Error(`Unsupported platform: ${platform}`)\n }\n}\n\n/**\n * Ensure ffmpeg binary is available.\n * Checks: deps dir → system PATH → download.\n */\nexport async function ensureFfmpeg(dataDir: string, logger: IScopedLogger): Promise<string> {\n const depsDir = join(dataDir, 'deps')\n const platform = process.platform\n const arch = process.arch\n\n const archiveInfo = getFfmpegArchiveInfo(platform)\n\n return ensureBinary({\n name: 'ffmpeg',\n targetDir: depsDir,\n downloadUrl: getFfmpegDownloadUrl(platform, arch),\n logger,\n ...archiveInfo,\n })\n}\n","/**\n * Download portable Python (headless) from bjia56/portable-python.\n *\n * Source: https://github.com/bjia56/portable-python\n *\n * Advantages over python-build-standalone:\n * - macOS universal2 binary (arm64+x86_64 in one)\n * - Lighter (~24-28MB headless zip)\n * - glibc 2.17 minimum (better compat)\n * - Headless variant excludes tkinter/UI (ideal for ML inference)\n *\n * After extraction, the binary is at: python/bin/python3\n */\nimport { join } from 'node:path'\nimport { existsSync, mkdirSync, chmodSync } from 'node:fs'\nimport { execFileSync } from 'node:child_process'\nimport { pipeline } from 'node:stream/promises'\nimport { Readable } from 'node:stream'\nimport { createWriteStream } from 'node:fs'\nimport type { IScopedLogger } from '@camstack/types'\nimport { findInPath } from './binary-downloader.js'\n\nexport const PYTHON_VERSION = '3.12.12'\nconst PP_BASE = `https://github.com/bjia56/portable-python/releases/download/cpython-v${PYTHON_VERSION}-build.0`\n\nexport function getPythonDownloadUrl(platform: string, arch: string): string {\n switch (platform) {\n case 'linux': {\n const archMap: Record<string, string> = { x64: 'x86_64', arm64: 'aarch64' }\n const a = archMap[arch]\n if (!a) throw new Error(`Unsupported Linux architecture for Python: ${arch}`)\n return `${PP_BASE}/python-headless-${PYTHON_VERSION}-linux-${a}.zip`\n }\n case 'darwin': {\n // universal2 covers both arm64 and x86_64\n return `${PP_BASE}/python-headless-${PYTHON_VERSION}-darwin-universal2.zip`\n }\n default:\n throw new Error(`Unsupported platform for portable Python: ${platform}`)\n }\n}\n\n/**\n * Ensure a portable Python is available.\n * Checks: embedded python → system PATH → download portable.\n *\n * Returns the path to the python3 binary.\n */\nexport async function ensurePython(dataDir: string, logger: IScopedLogger): Promise<string | null> {\n const pythonDir = join(dataDir, 'deps', 'python')\n const pythonBin = join(pythonDir, 'bin', 'python3')\n\n // 1. Already downloaded\n if (existsSync(pythonBin)) {\n logger.debug(`Portable Python found at ${pythonBin}`)\n return pythonBin\n }\n\n // 2. System PATH\n for (const name of ['python3', 'python']) {\n const inPath = findInPath(name)\n if (inPath) {\n logger.info(`Python found in system PATH: ${name}`)\n return inPath\n }\n }\n\n // 3. Download portable python\n logger.info(`Downloading portable Python ${PYTHON_VERSION} (headless)...`)\n\n const depsDir = join(dataDir, 'deps')\n mkdirSync(depsDir, { recursive: true })\n\n const url = getPythonDownloadUrl(process.platform, process.arch)\n const tmpArchive = join(depsDir, 'python-download.zip')\n\n logger.info(` Source: ${url}`)\n\n const response = await fetch(url, { redirect: 'follow' })\n if (!response.ok || !response.body) {\n logger.warn(`Failed to download Python: ${response.status} — ML detection will not be available`)\n return null\n }\n\n const nodeStream = Readable.fromWeb(response.body as any)\n await pipeline(nodeStream, createWriteStream(tmpArchive))\n\n // Extract — zip contains a 'python/' directory\n try {\n execFileSync('unzip', ['-o', '-q', tmpArchive, '-d', depsDir], { stdio: 'pipe' })\n } catch {\n // Fallback: some minimal Linux installs don't have unzip\n execFileSync('python3', ['-m', 'zipfile', '-e', tmpArchive, depsDir], { stdio: 'pipe' })\n }\n\n // Cleanup\n const { unlinkSync } = await import('node:fs')\n unlinkSync(tmpArchive)\n\n if (!existsSync(pythonBin)) {\n logger.warn('Python extraction succeeded but binary not found at expected path')\n return null\n }\n\n chmodSync(pythonBin, 0o755)\n logger.info(`Portable Python ${PYTHON_VERSION} installed at ${pythonBin}`)\n return pythonBin\n}\n\n/**\n * Install Python packages into the portable Python environment.\n */\nexport async function installPythonPackages(\n pythonPath: string,\n packages: readonly string[],\n logger: IScopedLogger,\n): Promise<void> {\n if (packages.length === 0) return\n\n logger.info(`Installing Python packages: ${packages.join(', ')}`)\n try {\n execFileSync(pythonPath, ['-m', 'pip', 'install', '--quiet', ...packages], {\n stdio: 'pipe',\n timeout: 300_000, // 5 minutes for large packages like torch\n })\n logger.info('Python packages installed successfully')\n } catch (err) {\n logger.error(`Failed to install Python packages: ${err instanceof Error ? err.message : err}`)\n throw err\n }\n}\n","type EventCallback<T = unknown> = (data: T) => void\n\nexport class EventBus {\n private listeners = new Map<string, Set<EventCallback>>()\n\n on<T = unknown>(event: string, callback: EventCallback<T>): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set())\n const set = this.listeners.get(event)!\n set.add(callback as EventCallback)\n return () => set.delete(callback as EventCallback)\n }\n\n emit<T = unknown>(event: string, data: T): void {\n const set = this.listeners.get(event)\n if (!set) return\n for (const cb of set) {\n try { cb(data) } catch { /* don't let one listener break others */ }\n }\n }\n\n once<T = unknown>(event: string, callback: EventCallback<T>): () => void {\n const unsub = this.on<T>(event, (data) => {\n unsub()\n callback(data)\n })\n return unsub\n }\n\n removeAllListeners(event?: string): void {\n if (event) this.listeners.delete(event)\n else this.listeners.clear()\n }\n\n listenerCount(event: string): number {\n return this.listeners.get(event)?.size ?? 0\n }\n}\n","import type { ModelDownloadOptions, ModelDownloadResult } from '@camstack/types'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { createHash } from 'node:crypto'\n\n/** Build fetch headers, including HF auth token for huggingface.co URLs */\nfunction buildHeaders(url: string): Record<string, string> {\n const headers: Record<string, string> = { 'User-Agent': 'CamStack/1.0' }\n const hfToken = process.env['HF_TOKEN'] ?? process.env['HUGGING_FACE_HUB_TOKEN']\n if (hfToken && url.includes('huggingface.co')) {\n headers['Authorization'] = `Bearer ${hfToken}`\n }\n return headers\n}\n\n/**\n * Download a single file from a URL to a destination path.\n * Uses native fetch() (Node 22+) which handles redirects natively.\n * Streams to disk with optional progress callback.\n * Returns the destination path. Skips download if file already exists.\n */\nexport async function downloadFile(\n url: string,\n destPath: string,\n onProgress?: (downloaded: number, total: number) => void,\n): Promise<string> {\n if (fs.existsSync(destPath)) return destPath\n\n fs.mkdirSync(path.dirname(destPath), { recursive: true })\n\n // Atomic download: write to .downloading tmp, rename on success\n const tmpPath = destPath + '.downloading'\n\n try {\n const response = await fetch(url, {\n redirect: 'follow',\n headers: buildHeaders(url),\n })\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} downloading ${url}`)\n }\n if (!response.body) {\n throw new Error(`No response body from ${url}`)\n }\n\n const total = parseInt(response.headers.get('content-length') ?? '0', 10)\n let downloaded = 0\n\n const fileStream = fs.createWriteStream(tmpPath)\n const reader = response.body.getReader()\n\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n fileStream.write(value)\n downloaded += value.length\n onProgress?.(downloaded, total)\n }\n } finally {\n fileStream.end()\n await new Promise<void>((resolve, reject) => {\n fileStream.on('finish', resolve)\n fileStream.on('error', reject)\n })\n }\n\n fs.renameSync(tmpPath, destPath)\n return destPath\n } catch (err) {\n // Clean up partial download\n try { fs.unlinkSync(tmpPath) } catch { /* ignore */ }\n throw err\n }\n}\n\n/**\n * Fetch JSON from a URL using native fetch().\n */\nexport async function fetchJson(url: string): Promise<unknown> {\n const response = await fetch(url, {\n redirect: 'follow',\n headers: buildHeaders(url),\n })\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} fetching ${url}`)\n }\n return response.json()\n}\n\n/**\n * Download a model with fallback URLs and optional SHA256 verification.\n * Legacy API preserved for backward compatibility -- delegates to downloadFile().\n */\nexport async function downloadModel(options: ModelDownloadOptions): Promise<ModelDownloadResult> {\n const { url, fallbackUrls = [], destDir, filename, expectedSha256, onProgress } = options\n\n const fname = filename ?? url.split('/').pop() ?? 'model.bin'\n const destPath = path.join(destDir, fname)\n\n // Check cache\n if (fs.existsSync(destPath)) {\n return { filePath: destPath, downloadedBytes: 0, fromCache: true }\n }\n\n fs.mkdirSync(destDir, { recursive: true })\n\n const urls = [url, ...fallbackUrls]\n let lastError: Error | null = null\n\n for (const tryUrl of urls) {\n try {\n await downloadFile(tryUrl, destPath, onProgress)\n\n // Verify SHA256 if provided\n if (expectedSha256) {\n const hash = await computeSha256(destPath)\n if (hash !== expectedSha256) {\n fs.unlinkSync(destPath)\n throw new Error(`SHA256 mismatch: expected ${expectedSha256}, got ${hash}`)\n }\n }\n\n const stat = fs.statSync(destPath)\n return { filePath: destPath, downloadedBytes: stat.size, fromCache: false }\n } catch (e) {\n lastError = e as Error\n if (fs.existsSync(destPath)) fs.unlinkSync(destPath)\n }\n }\n\n throw lastError ?? new Error(`Failed to download model from ${url}`)\n}\n\nasync function computeSha256(filePath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const hash = createHash('sha256')\n const stream = fs.createReadStream(filePath)\n stream.on('data', (chunk) => hash.update(chunk))\n stream.on('end', () => resolve(hash.digest('hex')))\n stream.on('error', reject)\n })\n}\n","import type { ModelCatalogEntry, ModelFormat, IAddonModelManager, ModelExtraFile } from '@camstack/types'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { downloadFile, fetchJson } from './model-downloader.js'\n\n/**\n * Unified model download service.\n *\n * Handles downloading model files and extra files (labels, dicts) from a\n * catalog of ModelCatalogEntry items. Supports single-file models and\n * directory bundles (e.g., .mlpackage for CoreML).\n *\n * Addons use this via `context.models.ensure(modelId, format)`.\n */\nexport class ModelDownloadService implements IAddonModelManager {\n private readonly catalog: ReadonlyMap<string, ModelCatalogEntry>\n\n constructor(\n private readonly modelsDir: string,\n catalog: readonly ModelCatalogEntry[],\n private readonly onProgress?: (modelId: string, downloaded: number, total: number) => void,\n ) {\n const map = new Map<string, ModelCatalogEntry>()\n for (const entry of catalog) {\n map.set(entry.id, entry)\n }\n this.catalog = map\n }\n\n /**\n * Ensure a model (and its extra files) is downloaded.\n * Returns the local filesystem path to the model file/directory.\n */\n async ensure(modelId: string, format?: ModelFormat): Promise<string> {\n const entry = this.catalog.get(modelId)\n if (!entry) {\n throw new Error(`ModelDownloadService: unknown model \"${modelId}\"`)\n }\n\n // Resolve format: use provided or pick first available\n const selectedFormat = format ?? this.pickDefaultFormat(entry)\n const formatEntry = entry.formats[selectedFormat]\n if (!formatEntry) {\n throw new Error(\n `ModelDownloadService: model \"${modelId}\" has no ${selectedFormat} format`,\n )\n }\n\n // Download extra files first (labels JSON, dict.txt, etc.)\n await this.ensureExtraFiles(modelId)\n\n // Derive local path from URL\n const modelPath = this.modelFilePath(entry, selectedFormat)\n\n if (fs.existsSync(modelPath)) {\n // Validate directory bundles have required Manifest.json\n if (formatEntry.isDirectory) {\n if (!fs.existsSync(path.join(modelPath, 'Manifest.json'))) {\n fs.rmSync(modelPath, { recursive: true, force: true })\n } else {\n return modelPath\n }\n } else {\n return modelPath\n }\n }\n\n fs.mkdirSync(this.modelsDir, { recursive: true })\n\n if (formatEntry.isDirectory) {\n await this.downloadDirectory(\n formatEntry.url,\n modelPath,\n formatEntry.files,\n modelId,\n )\n } else {\n await downloadFile(\n formatEntry.url,\n modelPath,\n this.onProgress\n ? (downloaded, total) => this.onProgress!(modelId, downloaded, total)\n : undefined,\n )\n }\n\n return modelPath\n }\n\n /**\n * Ensure extra files for a model are downloaded.\n * Returns the local paths of all extra files.\n */\n async ensureExtraFiles(modelId: string): Promise<readonly string[]> {\n const entry = this.catalog.get(modelId)\n if (!entry) {\n throw new Error(`ModelDownloadService: unknown model \"${modelId}\"`)\n }\n\n const extras = entry.extraFiles\n if (!extras || extras.length === 0) return []\n\n const paths: string[] = []\n for (const extra of extras) {\n const destPath = path.join(this.modelsDir, extra.filename)\n await downloadFile(extra.url, destPath)\n paths.push(destPath)\n }\n return paths\n }\n\n /** Absolute path to the shared models directory. */\n getModelsDir(): string {\n return this.modelsDir\n }\n\n /** Check if a model file is already present on disk. */\n isDownloaded(modelId: string, format?: ModelFormat): boolean {\n const entry = this.catalog.get(modelId)\n if (!entry) return false\n\n const selectedFormat = format ?? this.pickDefaultFormat(entry)\n const formatEntry = entry.formats[selectedFormat]\n if (!formatEntry) return false\n\n const modelPath = this.modelFilePath(entry, selectedFormat)\n if (!fs.existsSync(modelPath)) return false\n\n // Validate directory bundles\n if (formatEntry.isDirectory) {\n return fs.existsSync(path.join(modelPath, 'Manifest.json'))\n }\n\n return fs.statSync(modelPath).size > 0\n }\n\n /**\n * Legacy API: download a model by ID (delegates to ensure with default format).\n * Required by IAddonModelManager interface.\n */\n async downloadModel(id: string): Promise<string> {\n return this.ensure(id)\n }\n\n /** Get the catalog entry for a model by ID. */\n getEntry(modelId: string): ModelCatalogEntry | undefined {\n return this.catalog.get(modelId)\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private pickDefaultFormat(entry: ModelCatalogEntry): ModelFormat {\n // Prefer onnx, then others in order\n const priority: ModelFormat[] = ['onnx', 'coreml', 'openvino', 'tflite', 'pt']\n for (const fmt of priority) {\n if (entry.formats[fmt]) return fmt\n }\n // Fallback: first available format\n const first = Object.keys(entry.formats)[0] as ModelFormat | undefined\n if (first) return first\n throw new Error(`ModelDownloadService: model \"${entry.id}\" has no formats`)\n }\n\n private modelFilePath(entry: ModelCatalogEntry, format: ModelFormat): string {\n const formatEntry = entry.formats[format]\n if (!formatEntry) {\n throw new Error(`Model ${entry.id} has no ${format} format`)\n }\n const urlParts = formatEntry.url.split('/')\n const filename = urlParts[urlParts.length - 1] ?? `${entry.id}.${format}`\n return path.join(this.modelsDir, filename)\n }\n\n /**\n * Download a directory bundle (e.g., .mlpackage) from HuggingFace.\n * ATOMIC: downloads to temp dir, renames only on complete success.\n */\n private async downloadDirectory(\n url: string,\n destDir: string,\n knownFiles?: readonly string[],\n modelId?: string,\n ): Promise<void> {\n const match = url.match(/huggingface\\.co\\/([^/]+\\/[^/]+)\\/resolve\\/main\\/(.+)/)\n if (!match) throw new Error(`Cannot parse HuggingFace URL: ${url}`)\n\n const [, repo, dirPath] = match\n\n let filesToDownload: Array<{ relativePath: string; fileUrl: string }>\n\n if (knownFiles && knownFiles.length > 0) {\n filesToDownload = knownFiles.map(f => ({\n relativePath: f,\n fileUrl: `https://huggingface.co/${repo}/resolve/main/${dirPath}/${f}`,\n }))\n } else {\n const hfFiles = await this.listHfFiles(repo!, dirPath!)\n if (hfFiles.length === 0) {\n throw new Error(`No files found in HuggingFace directory: ${dirPath}`)\n }\n filesToDownload = hfFiles.map(f => ({\n relativePath: f.path.substring(dirPath!.length + 1),\n fileUrl: `https://huggingface.co/${repo}/resolve/main/${f.path}`,\n }))\n }\n\n const tmpDir = destDir + '.downloading'\n fs.rmSync(tmpDir, { recursive: true, force: true })\n fs.mkdirSync(tmpDir, { recursive: true })\n\n try {\n for (const file of filesToDownload) {\n const destPath = path.join(tmpDir, file.relativePath)\n fs.mkdirSync(path.dirname(destPath), { recursive: true })\n await downloadFile(file.fileUrl, destPath)\n }\n\n fs.rmSync(destDir, { recursive: true, force: true })\n fs.renameSync(tmpDir, destDir)\n } catch (err) {\n fs.rmSync(tmpDir, { recursive: true, force: true })\n throw err\n }\n }\n\n /** Recursively list all files in a HuggingFace directory via API. */\n private async listHfFiles(\n repo: string,\n dirPath: string,\n ): Promise<Array<{ path: string; size: number }>> {\n const apiUrl = `https://huggingface.co/api/models/${repo}/tree/main/${dirPath}`\n const entries = (await fetchJson(apiUrl)) as any[]\n const files: Array<{ path: string; size: number }> = []\n\n for (const entry of entries) {\n if (entry.type === 'file') {\n files.push({ path: entry.path, size: entry.size ?? entry.lfs?.size ?? 0 })\n } else if (entry.type === 'directory') {\n const subFiles = await this.listHfFiles(repo, entry.path)\n files.push(...subFiles)\n }\n }\n\n return files\n }\n}\n","import type { IPythonEnvironment, PythonProbeResult, PythonEnvReady } from '@camstack/types'\nimport { execFile, spawn } from 'node:child_process'\nimport type { ChildProcess } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\n\nconst execFileAsync = promisify(execFile)\n\nexport class PythonEnvManager implements IPythonEnvironment {\n private venvPath: string\n private cachedProbe: PythonProbeResult | null = null\n\n constructor(private readonly dataDir: string) {\n this.venvPath = path.join(dataDir, '.venv')\n }\n\n async probe(): Promise<PythonProbeResult> {\n if (this.cachedProbe) return this.cachedProbe\n\n // Try python3, then python\n for (const cmd of ['python3', 'python']) {\n try {\n const { stdout } = await execFileAsync(cmd, ['--version'])\n const version = stdout.trim().replace('Python ', '')\n const major = parseInt(version.split('.')[0] ?? '0', 10)\n const minor = parseInt(version.split('.')[1] ?? '0', 10)\n\n if (major < 3 || (major === 3 && minor < 10)) continue\n\n // Get path\n const { stdout: pathOut } = await execFileAsync(cmd, ['-c', 'import sys; print(sys.executable)'])\n\n this.cachedProbe = {\n available: true,\n version,\n path: pathOut.trim(),\n }\n return this.cachedProbe\n } catch { continue }\n }\n\n this.cachedProbe = { available: false }\n return this.cachedProbe\n }\n\n async ensure(options: { packages: readonly string[] }): Promise<PythonEnvReady> {\n const probe = await this.probe()\n if (!probe.available || !probe.path) {\n throw new Error('Python 3.10+ is required but not found on this system')\n }\n\n // Create venv if needed\n if (!fs.existsSync(path.join(this.venvPath, 'bin', 'python'))) {\n await execFileAsync(probe.path, ['-m', 'venv', this.venvPath])\n }\n\n const venvPython = path.join(this.venvPath, 'bin', 'python')\n\n // Install packages\n if (options.packages.length > 0) {\n await execFileAsync(venvPython, ['-m', 'pip', 'install', '-q', ...options.packages])\n }\n\n return {\n pythonPath: venvPython,\n venvPath: this.venvPath,\n spawn: (script: string, args: readonly string[]) => {\n return spawn(venvPython, [script, ...args])\n },\n }\n }\n\n spawn(script: string, args: readonly string[]): ChildProcess {\n const venvPython = path.join(this.venvPath, 'bin', 'python')\n if (!fs.existsSync(venvPython)) {\n throw new Error('Python venv not initialized. Call ensure() first.')\n }\n return spawn(venvPython, [script, ...args])\n }\n}\n","import type { PipelineConfig, PipelineNode, ValidationIssue, ValidationResult } from '@camstack/types'\nimport { AddonLoader } from '@camstack/kernel'\n\nexport type { ValidationIssue, ValidationResult }\n\nexport class PipelineValidator {\n constructor(private readonly loader: AddonLoader) {}\n\n validate(config: PipelineConfig): ValidationResult {\n const errors: ValidationIssue[] = []\n const warnings: ValidationIssue[] = []\n\n // Validate video pipeline\n for (const node of config.video) {\n this.validateNode(node, errors, warnings, [])\n }\n\n // Validate audio\n if (config.audio) {\n this.validateNode(config.audio, errors, warnings, [])\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n }\n }\n\n private validateNode(\n node: PipelineNode,\n errors: ValidationIssue[],\n warnings: ValidationIssue[],\n ancestors: PipelineNode[],\n ): void {\n // Check addon exists\n if (!this.loader.hasAddon(node.addon)) {\n errors.push({\n step: node.step,\n addon: node.addon,\n message: `Addon \"${node.addon}\" is not registered`,\n severity: 'error',\n })\n return\n }\n\n // Check requiredSteps (from addon manifest)\n const registered = this.loader.getAddon(node.addon)\n if (registered) {\n const manifest = registered.declaration\n // Warn if a node appears at root but its addon has inputClasses\n // (This is a simplified check — full implementation would read manifest.requiredSteps)\n void manifest // reserved for future manifest-driven checks\n }\n\n // Validate children recursively\n if (node.children) {\n for (const child of node.children) {\n this.validateNode(child, errors, warnings, [...ancestors, node])\n }\n }\n }\n}\n","import type {\n FrameInput,\n AudioChunkInput,\n CropInput,\n PipelineConfig,\n PipelineNode,\n PipelineResult,\n StepResult,\n DetectorOutput,\n CropperOutput,\n ClassifierOutput,\n SpatialDetection,\n PipelineSlot,\n ICamstackAddon,\n} from '@camstack/types'\nimport { AddonEngineManager } from '@camstack/kernel'\nimport { randomUUID } from 'node:crypto'\n\nexport class PipelineRunner {\n constructor(\n private readonly engineManager: AddonEngineManager,\n private readonly addonConfigs: Map<string, Record<string, unknown>>, // addonId → global config\n ) {}\n\n async run(frame: FrameInput, config: PipelineConfig): Promise<PipelineResult> {\n const startTime = performance.now()\n const results: StepResult[] = []\n const timings: Record<string, number> = {}\n\n // Execute video pipeline root nodes\n for (const rootNode of config.video) {\n await this.executeNode(rootNode, frame, null, results, timings)\n }\n\n // Execute audio node if present (independent)\n if (config.audio) {\n await this.executeNode(config.audio, frame, null, results, timings)\n }\n\n return {\n results,\n totalMs: performance.now() - startTime,\n timings,\n frameTimestamp: frame.timestamp,\n }\n }\n\n /**\n * Run only the audio classification node on an audio chunk.\n * Used by the audio path in DetectionWiringService (separate from video pipeline).\n */\n async runAudioNode(chunk: AudioChunkInput, audioNode: PipelineNode): Promise<PipelineResult> {\n const startTime = performance.now()\n const results: StepResult[] = []\n const timings: Record<string, number> = {}\n const resultId = randomUUID()\n const stepStart = performance.now()\n\n try {\n const globalConfig = this.addonConfigs.get(audioNode.addon) ?? {}\n const engine = await this.engineManager.getOrCreateEngine(\n audioNode.addon, globalConfig, audioNode.configOverride,\n )\n\n if (!('classifyAudio' in engine) || typeof (engine as unknown as Record<string, unknown>)['classifyAudio'] !== 'function') {\n throw new Error(`Addon \"${audioNode.addon}\" has no classifyAudio method`)\n }\n\n const output = await (engine as unknown as { classifyAudio: (input: AudioChunkInput) => Promise<ClassifierOutput> }).classifyAudio(chunk)\n const stepMs = performance.now() - stepStart\n\n const stepResult: StepResult = {\n addon: audioNode.addon,\n slot: 'classifier',\n output,\n resultId,\n inferenceMs: output.inferenceMs,\n preprocessMs: 0,\n totalMs: stepMs,\n }\n results.push(stepResult)\n timings[audioNode.step] = stepMs\n } catch (error: unknown) {\n const stepMs = performance.now() - stepStart\n const message = error instanceof Error ? error.message : String(error)\n results.push({\n addon: audioNode.addon,\n slot: 'classifier',\n output: { classifications: [], inferenceMs: 0, modelId: '' } as unknown as ClassifierOutput,\n resultId,\n inferenceMs: 0,\n preprocessMs: 0,\n totalMs: stepMs,\n error: {\n code: 'ADDON_ERROR',\n message,\n childrenSkipped: true,\n },\n })\n }\n\n return {\n results,\n totalMs: performance.now() - startTime,\n timings,\n frameTimestamp: chunk.timestamp,\n }\n }\n\n private async executeNode(\n node: PipelineNode,\n frame: FrameInput,\n parentDetection: { det: SpatialDetection; resultId: string } | null,\n results: StepResult[],\n timings: Record<string, number>,\n ): Promise<void> {\n const resultId = randomUUID()\n const stepStart = performance.now()\n\n try {\n // Get or create engine for this addon\n const globalConfig = this.addonConfigs.get(node.addon) ?? {}\n const engine = await this.engineManager.getOrCreateEngine(\n node.addon, globalConfig, node.configOverride,\n )\n\n // Determine slot type and execute\n let output: DetectorOutput | CropperOutput | ClassifierOutput\n\n if (parentDetection) {\n // This is a child node — needs crop input\n const cropInput: CropInput = {\n frame,\n roi: parentDetection.det.bbox,\n parentDetection: parentDetection.det,\n }\n\n // Try cropper first, then classifier, then detector\n if ('crop' in engine && typeof (engine as unknown as Record<string, unknown>)['crop'] === 'function') {\n output = await (engine as unknown as { crop: (input: CropInput) => Promise<CropperOutput> }).crop(cropInput)\n } else if ('classify' in engine && typeof (engine as unknown as Record<string, unknown>)['classify'] === 'function') {\n output = await (engine as unknown as { classify: (input: CropInput) => Promise<ClassifierOutput> }).classify(cropInput)\n } else if ('detect' in engine && typeof (engine as unknown as Record<string, unknown>)['detect'] === 'function') {\n // Detector child (e.g., object-detection triggered by motion)\n output = await (engine as unknown as { detect: (input: FrameInput) => Promise<DetectorOutput> }).detect(frame)\n } else {\n throw new Error(`Addon \"${node.addon}\" has no detect/crop/classify method`)\n }\n } else {\n // Root node — full frame\n if ('detect' in engine && typeof (engine as unknown as Record<string, unknown>)['detect'] === 'function') {\n output = await (engine as unknown as { detect: (input: FrameInput) => Promise<DetectorOutput> }).detect(frame)\n } else if ('classify' in engine && typeof (engine as unknown as Record<string, unknown>)['classify'] === 'function') {\n // Audio classifier at root\n const rootCropInput: CropInput = {\n frame,\n roi: { x: 0, y: 0, w: frame.width, h: frame.height },\n parentDetection: { class: '', originalClass: '', score: 1, bbox: { x: 0, y: 0, w: frame.width, h: frame.height } },\n }\n output = await (engine as unknown as { classify: (input: CropInput) => Promise<ClassifierOutput> }).classify(rootCropInput)\n } else {\n throw new Error(`Addon \"${node.addon}\" has no detect/classify method`)\n }\n }\n\n const stepMs = performance.now() - stepStart\n\n // Determine slot type from output shape\n const slot: PipelineSlot =\n 'detections' in output ? 'detector' :\n 'crops' in output ? 'cropper' :\n 'classifier'\n\n const stepResult: StepResult = {\n addon: node.addon,\n slot,\n output,\n parentResultId: parentDetection?.resultId,\n resultId,\n inferenceMs: output.inferenceMs,\n preprocessMs: 0,\n totalMs: stepMs,\n }\n results.push(stepResult)\n timings[node.step] = stepMs\n\n // Process children\n if (node.children?.length) {\n const detections: readonly SpatialDetection[] =\n 'detections' in output ? output.detections :\n 'crops' in output ? output.crops :\n []\n\n // For each detection, find children with matching inputClasses and execute\n await this.executeChildren(node.children, frame, detections, resultId, results, timings)\n }\n } catch (error: unknown) {\n const stepMs = performance.now() - stepStart\n const message = error instanceof Error ? error.message : String(error)\n results.push({\n addon: node.addon,\n slot: 'detector',\n output: { detections: [], inferenceMs: 0, modelId: '' },\n parentResultId: parentDetection?.resultId,\n resultId,\n inferenceMs: 0,\n preprocessMs: 0,\n totalMs: stepMs,\n error: {\n code: 'ADDON_ERROR',\n message,\n childrenSkipped: true,\n },\n })\n }\n }\n\n private async executeChildren(\n children: readonly PipelineNode[],\n frame: FrameInput,\n parentDetections: readonly SpatialDetection[],\n parentResultId: string,\n results: StepResult[],\n timings: Record<string, number>,\n ): Promise<void> {\n // For each parent detection, run all matching children in parallel\n const promises: Promise<void>[] = []\n\n for (const detection of parentDetections) {\n for (const child of children) {\n // TODO: Check inputClasses matching from addon manifest\n // For now, run all children on all detections (caller configures tree correctly)\n promises.push(\n this.executeNode(child, frame, { det: detection, resultId: parentResultId }, results, timings),\n )\n }\n }\n\n await Promise.allSettled(promises)\n }\n}\n","import { fork, spawn, type ChildProcess } from 'node:child_process'\nimport type { IScopedLogger } from '@camstack/types'\nimport type {\n ProcessConfig,\n ProcessStats,\n ManagedProcessStatus,\n ProcessState,\n ProcessEventEmitter,\n} from './interfaces.js'\n\nconst DEFAULT_MAX_RESTARTS = 10\nconst MAX_BACKOFF_MS = 60_000\nconst GRACEFUL_SHUTDOWN_MS = 5_000\n\nexport class ManagedProcess {\n private childProcess: ChildProcess | null = null\n private _state: ProcessState = 'stopped'\n private _startedAt?: number\n private restartTimer?: ReturnType<typeof setTimeout>\n private _restartCount = 0\n private _lastCrashAt?: number\n private _lastCrashError?: string\n\n constructor(\n private readonly config: ProcessConfig,\n private readonly events: ProcessEventEmitter,\n private readonly logger: IScopedLogger,\n ) {}\n\n get state(): ProcessState {\n return this._state\n }\n\n async start(): Promise<void> {\n this._state = 'starting'\n\n try {\n if (this.config.modulePath) {\n this.childProcess = fork(this.config.modulePath, this.config.args ?? [], {\n env: { ...process.env, ...this.config.env },\n stdio: ['pipe', 'pipe', 'pipe', 'ipc'],\n })\n } else if (this.config.command) {\n this.childProcess = spawn(this.config.command, this.config.args ?? [], {\n env: { ...process.env, ...this.config.env },\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n } else {\n throw new Error('No command or modulePath specified')\n }\n\n this.childProcess.stdout?.on('data', (data: Buffer) => {\n this.logger.debug(data.toString().trim())\n })\n\n this.childProcess.stderr?.on('data', (data: Buffer) => {\n this.logger.warn(data.toString().trim())\n })\n\n this.childProcess.on('exit', (code, signal) => {\n const msg = `Process exited: code=${code}, signal=${signal}`\n\n if (code === 0) {\n this.logger.info(msg)\n this._state = 'stopped'\n } else {\n this._lastCrashAt = Date.now()\n this._lastCrashError = msg\n this.logger.error(msg)\n this._state = 'error'\n\n this.events.emitProcessCrashed(\n this.config.id,\n code,\n signal,\n this._restartCount,\n )\n\n const maxRestarts = this.config.maxRestarts ?? DEFAULT_MAX_RESTARTS\n if (this.config.autoRestart && this._restartCount < maxRestarts) {\n this.scheduleRestart()\n }\n }\n\n this.childProcess = null\n })\n\n this.childProcess.on('error', (err: Error) => {\n this.logger.error(`Process error: ${err.message}`)\n this._lastCrashError = err.message\n this._state = 'error'\n })\n\n this._state = 'running'\n this._startedAt = Date.now()\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n this._state = 'error'\n this._lastCrashError = msg\n throw err\n }\n }\n\n async stop(): Promise<void> {\n if (this.restartTimer) {\n clearTimeout(this.restartTimer)\n this.restartTimer = undefined\n }\n\n if (this._state === 'stopped') {\n return\n }\n\n this._state = 'stopping'\n\n if (this.childProcess && !this.childProcess.killed) {\n this.childProcess.kill('SIGTERM')\n\n await new Promise<void>((resolve) => {\n const timeout = setTimeout(() => {\n if (this.childProcess && !this.childProcess.killed) {\n this.childProcess.kill('SIGKILL')\n }\n resolve()\n }, GRACEFUL_SHUTDOWN_MS)\n\n this.childProcess?.on('exit', () => {\n clearTimeout(timeout)\n resolve()\n })\n })\n }\n\n // The exit handler may have already set state to 'stopped' asynchronously\n const currentState = this._state as string\n if (currentState !== 'stopped') {\n this._state = 'stopped'\n }\n }\n\n getStatus(): ManagedProcessStatus {\n return {\n id: this.config.id,\n label: this.config.label,\n state: this._state,\n pid: this.childProcess?.pid,\n stats: this.childProcess?.pid ? this.getStats() : undefined,\n lastCrashAt: this._lastCrashAt,\n lastCrashError: this._lastCrashError,\n restartCount: this._restartCount,\n nextRestartAt: this.restartTimer ? this.getNextRestartTime() : undefined,\n }\n }\n\n private scheduleRestart(): void {\n this._restartCount++\n const delayMs = Math.min(1000 * Math.pow(2, this._restartCount - 1), MAX_BACKOFF_MS)\n\n this.logger.info(`Scheduling restart #${this._restartCount} in ${delayMs}ms`)\n\n this.events.emitProcessRestartScheduled(\n this.config.id,\n this._restartCount,\n delayMs,\n )\n\n this.restartTimer = setTimeout(async () => {\n this.restartTimer = undefined\n try {\n await this.start()\n this.events.emitProcessRestarted(this.config.id, this._restartCount)\n } catch (err) {\n this.logger.error(`Restart failed: ${err}`)\n }\n }, delayMs)\n }\n\n private getStats(): ProcessStats | undefined {\n if (!this.childProcess?.pid) return undefined\n const uptime = this._startedAt ? Date.now() - this._startedAt : 0\n return {\n pid: this.childProcess.pid,\n cpu: 0,\n memory: 0,\n uptime,\n restartCount: this._restartCount,\n }\n }\n\n private getNextRestartTime(): number | undefined {\n if (!this._lastCrashAt) return undefined\n const delayMs = Math.min(1000 * Math.pow(2, this._restartCount - 1), MAX_BACKOFF_MS)\n return this._lastCrashAt + delayMs\n }\n}\n","import { ManagedProcess } from './managed-process.js'\nimport type {\n ProcessConfig,\n ManagedProcessStatus,\n ProcessEventEmitter,\n ProcessLoggerFactory,\n} from './interfaces.js'\n\nexport class ProcessManager {\n private readonly processes: Map<string, ManagedProcess> = new Map()\n\n constructor(\n private readonly events: ProcessEventEmitter,\n private readonly loggerFactory: ProcessLoggerFactory,\n ) {}\n\n register(config: ProcessConfig): ManagedProcess {\n if (this.processes.has(config.id)) {\n throw new Error(`Process already registered: ${config.id}`)\n }\n\n const logger = this.loggerFactory.createLogger(`process:${config.id}`)\n const managed = new ManagedProcess(config, this.events, logger)\n this.processes.set(config.id, managed)\n return managed\n }\n\n async start(id: string): Promise<void> {\n const p = this.get(id)\n await p.start()\n }\n\n async stop(id: string): Promise<void> {\n const p = this.get(id)\n await p.stop()\n }\n\n async restart(id: string): Promise<void> {\n const p = this.get(id)\n await p.stop()\n await p.start()\n }\n\n get(id: string): ManagedProcess {\n const p = this.processes.get(id)\n if (!p) throw new Error(`Process not found: ${id}`)\n return p\n }\n\n listAll(): readonly ManagedProcessStatus[] {\n return [...this.processes.values()].map((p) => p.getStatus())\n }\n\n async shutdownAll(): Promise<void> {\n const running = [...this.processes.values()].filter(\n (p) => p.getStatus().state === 'running',\n )\n\n await Promise.all(running.map((p) => p.stop()))\n }\n}\n","import type {\n StreamNetworkStats,\n ClientNetworkStats,\n DeviceNetworkStats,\n INetworkQualityTracker,\n} from '@camstack/types'\n\nexport type {\n StreamNetworkStats,\n ClientNetworkStats,\n DeviceNetworkStats,\n INetworkQualityTracker,\n}\n\ninterface MutableStreamStats {\n nominalBitrateKbps: number\n samples: number[]\n peakBitrateKbps: number\n packetLossSamples: number[]\n lastUpdated: number\n}\n\nexport class NetworkQualityTracker implements INetworkQualityTracker {\n private readonly devices = new Map<string, {\n streams: Map<string, MutableStreamStats>\n client: (ClientNetworkStats & { lastUpdated: number }) | null\n }>()\n\n private static readonly MAX_SAMPLES = 30 // ~5 min at 10s reporting interval\n\n reportStreamStats(deviceId: string, streamId: string, bitrateKbps: number, packetLoss?: number): void {\n const device = this.getOrCreateDevice(deviceId)\n let stream = device.streams.get(streamId)\n if (!stream) {\n stream = { nominalBitrateKbps: bitrateKbps, samples: [], peakBitrateKbps: 0, packetLossSamples: [], lastUpdated: 0 }\n device.streams.set(streamId, stream)\n }\n\n stream.samples.push(bitrateKbps)\n if (stream.samples.length > NetworkQualityTracker.MAX_SAMPLES) stream.samples.shift()\n\n stream.peakBitrateKbps = Math.max(stream.peakBitrateKbps, bitrateKbps)\n\n if (packetLoss !== undefined) {\n stream.packetLossSamples.push(packetLoss)\n if (stream.packetLossSamples.length > NetworkQualityTracker.MAX_SAMPLES) stream.packetLossSamples.shift()\n }\n\n stream.lastUpdated = Date.now()\n }\n\n reportClientStats(deviceId: string, stats: Omit<ClientNetworkStats, 'lastUpdated'>): void {\n const device = this.getOrCreateDevice(deviceId)\n device.client = { ...stats, lastUpdated: Date.now() }\n }\n\n getDeviceStats(deviceId: string): DeviceNetworkStats | null {\n const device = this.devices.get(deviceId)\n if (!device) return null\n\n const streams: Record<string, StreamNetworkStats> = {}\n for (const [streamId, s] of device.streams) {\n const avg = (arr: number[]) => arr.length === 0 ? 0 : arr.reduce((a, b) => a + b, 0) / arr.length\n streams[streamId] = {\n nominalBitrateKbps: s.nominalBitrateKbps,\n observedBitrateKbps: Math.round(avg(s.samples)),\n peakBitrateKbps: s.peakBitrateKbps,\n packetLossPercent: Math.round(avg(s.packetLossSamples) * 10) / 10,\n lastUpdated: s.lastUpdated,\n }\n }\n\n return { deviceId, streams, client: device.client ?? undefined }\n }\n\n getAllStats(): readonly DeviceNetworkStats[] {\n const results: DeviceNetworkStats[] = []\n for (const deviceId of this.devices.keys()) {\n const stats = this.getDeviceStats(deviceId)\n if (stats) results.push(stats)\n }\n return results\n }\n\n private getOrCreateDevice(deviceId: string) {\n let device = this.devices.get(deviceId)\n if (!device) {\n device = { streams: new Map(), client: null }\n this.devices.set(deviceId, device)\n }\n return device\n }\n}\n","import * as vm from 'node:vm'\nimport * as util from 'node:util'\nimport type {\n IReplEngine,\n IReplContextProvider,\n ReplSessionContext,\n ReplResult,\n} from './interfaces.js'\n\nconst EXECUTION_TIMEOUT_MS = 5000\nconst COMPLETION_TIMEOUT_MS = 1000\n\nexport class ReplEngine implements IReplEngine {\n constructor(\n private readonly contextProvider: IReplContextProvider,\n ) {}\n\n async execute(code: string, context: ReplSessionContext): Promise<ReplResult> {\n const start = Date.now()\n const sandbox = this.buildSandbox(context)\n\n try {\n const vmContext = vm.createContext(sandbox)\n const script = new vm.Script(code)\n let result = script.runInContext(vmContext, { timeout: EXECUTION_TIMEOUT_MS })\n\n // If result is a Promise, await it with timeout\n if (result && typeof result.then === 'function') {\n result = await Promise.race([\n result,\n new Promise((_, reject) =>\n setTimeout(() => reject(new Error('Async timeout (5s)')), EXECUTION_TIMEOUT_MS),\n ),\n ])\n }\n\n const duration = Date.now() - start\n\n if (result === undefined) {\n return { output: 'undefined', type: 'void', duration }\n }\n\n return {\n output: util.inspect(result, {\n depth: 4,\n colors: false,\n maxArrayLength: 50,\n maxStringLength: 1000,\n }),\n type: 'value',\n duration,\n }\n } catch (err: unknown) {\n // Errors thrown inside vm contexts may not be instanceof Error\n // because they use a different Error constructor from the sandbox\n const message =\n err instanceof Error\n ? err.message\n : typeof err === 'object' && err !== null && 'message' in err\n ? String((err as { message: unknown }).message)\n : String(err)\n return {\n output: message,\n type: 'error',\n duration: Date.now() - start,\n }\n }\n }\n\n async getCompletions(partial: string, context: ReplSessionContext): Promise<string[]> {\n const sandbox = this.buildSandbox(context)\n const keys = Object.keys(sandbox)\n\n if (!partial) return keys\n\n const lastDot = partial.lastIndexOf('.')\n if (lastDot === -1) {\n return keys.filter(k => k.startsWith(partial))\n }\n\n // Object property completion: \"device.get\" -> look up device, return matching keys\n const objPath = partial.substring(0, lastDot)\n const propPrefix = partial.substring(lastDot + 1)\n\n try {\n const vmContext = vm.createContext(sandbox)\n const obj = vm.runInContext(objPath, vmContext, { timeout: COMPLETION_TIMEOUT_MS })\n if (obj && typeof obj === 'object') {\n const proto = Object.getPrototypeOf(obj)\n const objKeys = Object.getOwnPropertyNames(obj)\n .concat(Object.getOwnPropertyNames(proto ?? {}))\n .filter(k => k.startsWith(propPrefix))\n return [...new Set(objKeys)].map(k => `${objPath}.${k}`)\n }\n } catch {\n // Ignore errors during completion\n }\n\n return []\n }\n\n private buildSandbox(context: ReplSessionContext): Record<string, unknown> {\n const base: Record<string, unknown> = {\n console: {\n log: (...args: unknown[]) => util.inspect(args),\n warn: (...args: unknown[]) => util.inspect(args),\n },\n JSON,\n Math,\n Date,\n Array,\n Object,\n String,\n Number,\n Boolean,\n Map,\n Set,\n Promise,\n Buffer,\n // Blocked globals\n setTimeout: undefined,\n setInterval: undefined,\n fetch: undefined,\n require: undefined,\n process: undefined,\n // Merge user-provided variables\n ...context.variables,\n }\n\n switch (context.scope.type) {\n case 'system':\n return { ...base, ...this.contextProvider.getSystemSandbox() }\n\n case 'device':\n return { ...base, ...this.contextProvider.getDeviceSandbox(context.scope.deviceId!) }\n\n case 'provider':\n return { ...base, ...this.contextProvider.getProviderSandbox(context.scope.providerId!) }\n\n case 'addon':\n return { ...base, ...this.contextProvider.getAddonSandbox(context.scope.addonId!) }\n\n default:\n return base\n }\n }\n}\n","import type {\n AgentInfo,\n AgentStatus,\n AgentEntry,\n AgentEventEmitter,\n} from './interfaces.js'\n\nexport class AgentRegistry {\n private readonly agents: Map<string, AgentEntry> = new Map()\n private readonly heartbeatIntervals: Map<string, NodeJS.Timeout> = new Map()\n\n constructor(\n private readonly events: AgentEventEmitter,\n private readonly heartbeatTimeoutMs: number = 30000,\n private readonly heartbeatCheckIntervalMs: number = 10000,\n ) {}\n\n /** Register a new agent */\n registerAgent(info: AgentInfo): void {\n const entry: AgentEntry = {\n info,\n state: 'online',\n connectedSince: Date.now(),\n lastHeartbeat: Date.now(),\n activeTaskCount: 0,\n completedTaskCount: 0,\n failedTaskCount: 0,\n }\n\n this.agents.set(info.id, entry)\n this.startHeartbeatCheck(info.id)\n\n this.events.emitAgentRegistered(info.id, [...info.capabilities])\n }\n\n /** Remove agent */\n unregisterAgent(id: string): void {\n const interval = this.heartbeatIntervals.get(id)\n if (interval) {\n clearInterval(interval)\n this.heartbeatIntervals.delete(id)\n }\n\n this.agents.delete(id)\n this.events.emitAgentUnregistered(id)\n }\n\n /** Update heartbeat timestamp */\n heartbeat(id: string): void {\n const entry = this.agents.get(id)\n if (!entry) return\n\n entry.lastHeartbeat = Date.now()\n\n if (entry.state === 'offline') {\n entry.state = 'online'\n this.events.emitAgentOnline(id)\n }\n }\n\n /** Find agents with a specific capability */\n getAgentsWithCapability(capability: string): readonly AgentEntry[] {\n return [...this.agents.values()].filter(\n (a) => a.state === 'online' && a.info.capabilities.includes(capability),\n )\n }\n\n /** Get best agent for a task (least loaded) */\n selectAgent(capability: string, preferredId?: string): AgentEntry | null {\n const capable = this.getAgentsWithCapability(capability)\n if (capable.length === 0) return null\n\n if (preferredId) {\n const preferred = capable.find((a) => a.info.id === preferredId)\n if (preferred) return preferred\n }\n\n // Least loaded: sort by activeTaskCount ascending\n const sorted = [...capable].sort((a, b) => a.activeTaskCount - b.activeTaskCount)\n return sorted[0] ?? null\n }\n\n /** List all agents with status */\n listAgents(): readonly AgentStatus[] {\n return [...this.agents.values()].map((entry) => ({\n id: entry.info.id,\n name: entry.info.name,\n state: entry.state,\n capabilities: [...entry.info.capabilities],\n lastHeartbeat: entry.lastHeartbeat,\n connectedSince: entry.connectedSince,\n resources: entry.info.resources,\n activeTaskCount: entry.activeTaskCount,\n completedTaskCount: entry.completedTaskCount,\n failedTaskCount: entry.failedTaskCount,\n }))\n }\n\n /** Get single agent */\n getAgent(id: string): AgentEntry | null {\n return this.agents.get(id) ?? null\n }\n\n /** Destroy all heartbeat intervals */\n destroy(): void {\n for (const interval of this.heartbeatIntervals.values()) {\n clearInterval(interval)\n }\n this.heartbeatIntervals.clear()\n }\n\n private startHeartbeatCheck(id: string): void {\n const interval = setInterval(() => {\n const entry = this.agents.get(id)\n if (!entry) return\n\n const elapsed = Date.now() - entry.lastHeartbeat\n if (elapsed > this.heartbeatTimeoutMs && entry.state === 'online') {\n entry.state = 'offline'\n this.events.emitAgentOffline(id)\n }\n }, this.heartbeatCheckIntervalMs)\n\n this.heartbeatIntervals.set(id, interval)\n }\n}\n","import type { AgentRegistry } from './agent-registry.js'\nimport type {\n AgentTask,\n AgentTaskResult,\n AgentEntry,\n TaskDispatchOptions,\n AgentEventEmitter,\n} from './interfaces.js'\n\ninterface PendingTask {\n readonly resolve: (result: AgentTaskResult) => void\n readonly reject: (error: Error) => void\n readonly timeout: NodeJS.Timeout\n}\n\nexport class TaskDispatcher {\n private readonly pendingTasks: Map<string, PendingTask> = new Map()\n private readonly localExecutors: Map<\n string,\n (input: Record<string, unknown>) => Promise<Record<string, unknown>>\n > = new Map()\n\n constructor(\n private readonly agentRegistry: AgentRegistry,\n private readonly events: AgentEventEmitter,\n ) {}\n\n /** Dispatch a task to the best available agent */\n async dispatch(task: AgentTask, options?: TaskDispatchOptions): Promise<AgentTaskResult> {\n const capability = options?.capability ?? task.capability\n const agent = this.agentRegistry.selectAgent(capability, options?.preferredAgent)\n\n if (!agent && !options?.remoteOnly) {\n return this.executeLocally(task)\n }\n\n if (!agent) {\n return {\n taskId: task.id,\n agentId: 'none',\n status: 'error',\n error: 'No agent available',\n durationMs: 0,\n }\n }\n\n return this.sendToAgent(task, agent)\n }\n\n /** Register a local executor for a capability (in-process fallback) */\n registerLocalExecutor(\n capability: string,\n executor: (input: Record<string, unknown>) => Promise<Record<string, unknown>>,\n ): void {\n this.localExecutors.set(capability, executor)\n }\n\n /** Called when an agent returns a result */\n handleTaskResult(result: AgentTaskResult): void {\n const pending = this.pendingTasks.get(result.taskId)\n if (pending) {\n clearTimeout(pending.timeout)\n this.pendingTasks.delete(result.taskId)\n pending.resolve(result)\n }\n\n // Update agent stats\n const agent = this.agentRegistry.getAgent(result.agentId)\n if (agent) {\n agent.activeTaskCount--\n if (result.status === 'success') {\n agent.completedTaskCount++\n } else {\n agent.failedTaskCount++\n }\n }\n }\n\n private async executeLocally(task: AgentTask): Promise<AgentTaskResult> {\n const executor = this.localExecutors.get(task.capability)\n if (!executor) {\n return {\n taskId: task.id,\n agentId: 'local',\n status: 'error',\n error: `No local executor for ${task.capability}`,\n durationMs: 0,\n }\n }\n\n const start = Date.now()\n try {\n const output = await executor(task.input)\n return {\n taskId: task.id,\n agentId: 'local',\n status: 'success',\n output,\n durationMs: Date.now() - start,\n }\n } catch (err) {\n return {\n taskId: task.id,\n agentId: 'local',\n status: 'error',\n error: String(err),\n durationMs: Date.now() - start,\n }\n }\n }\n\n private sendToAgent(task: AgentTask, agent: AgentEntry): Promise<AgentTaskResult> {\n agent.activeTaskCount++\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n this.pendingTasks.delete(task.id)\n agent.activeTaskCount--\n agent.failedTaskCount++\n resolve({\n taskId: task.id,\n agentId: agent.info.id,\n status: 'timeout',\n durationMs: task.timeout,\n error: 'Task timed out',\n })\n }, task.timeout)\n\n this.pendingTasks.set(task.id, { resolve, reject: () => {}, timeout })\n\n this.events.emitTaskDispatched(task.id, agent.info.id, task.capability)\n })\n }\n}\n","import type {\n AgentToHubMessage,\n HubToAgentMessage,\n AgentRegistrationInfo,\n AgentRuntimeStatus,\n} from '@camstack/types'\nimport type { IScopedLogger } from '../logging/scoped-logger.js'\n\nconst RECONNECT_BASE_MS = 1000\nconst RECONNECT_MAX_MS = 30000\nconst HEARTBEAT_INTERVAL_MS = 10_000\n\nexport interface AgentClientConfig {\n readonly hubUrl: string\n readonly token?: string\n readonly logger: IScopedLogger\n readonly registrationInfo: AgentRegistrationInfo\n}\n\nexport type MessageHandler = (msg: HubToAgentMessage) => void\nexport type BinaryHandler = (data: Buffer) => void\nexport type ConnectionHandler = () => void\n\n/**\n * WebSocket client for agent mode. Framework-agnostic (no NestJS).\n * Connects to the hub, sends registration, handles messages,\n * reconnects with exponential backoff.\n */\nexport class AgentClient {\n private ws: import('ws').WebSocket | null = null\n private reconnectAttempt = 0\n private reconnectTimer: NodeJS.Timeout | null = null\n private heartbeatTimer: NodeJS.Timeout | null = null\n private destroyed = false\n\n private readonly messageHandlers: MessageHandler[] = []\n private readonly binaryHandlers: BinaryHandler[] = []\n private readonly connectHandlers: ConnectionHandler[] = []\n private readonly disconnectHandlers: ConnectionHandler[] = []\n\n private readonly logger: IScopedLogger\n private readonly hubUrl: string\n private readonly token?: string\n private readonly registrationInfo: AgentRegistrationInfo\n\n private runtimeStatus: AgentRuntimeStatus = {\n activeCameras: 0,\n cpuPercent: 0,\n memoryPercent: 0,\n fps: {},\n errors: [],\n }\n\n constructor(config: AgentClientConfig) {\n this.hubUrl = config.hubUrl\n this.token = config.token\n this.logger = config.logger\n this.registrationInfo = config.registrationInfo\n }\n\n /** Connect to the hub WebSocket */\n async connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.destroyed = false\n this.doConnect(resolve, reject)\n })\n }\n\n /** Disconnect and stop reconnecting */\n disconnect(): void {\n this.destroyed = true\n this.clearTimers()\n if (this.ws) {\n this.ws.close()\n this.ws = null\n }\n }\n\n /** Send a JSON control message to the hub */\n send(msg: AgentToHubMessage): void {\n if (!this.ws || this.ws.readyState !== 1 /* WebSocket.OPEN */) {\n this.logger.warn('send() called while not connected')\n return\n }\n this.ws.send(JSON.stringify(msg))\n }\n\n /** Send a binary frame to the hub */\n sendBinary(data: Buffer): void {\n if (!this.ws || this.ws.readyState !== 1) {\n return\n }\n this.ws.send(data)\n }\n\n /** Register a handler for JSON messages from hub */\n onMessage(handler: MessageHandler): void {\n this.messageHandlers.push(handler)\n }\n\n /** Register a handler for binary frames from hub */\n onBinaryFrame(handler: BinaryHandler): void {\n this.binaryHandlers.push(handler)\n }\n\n /** Register a handler for successful connection */\n onConnect(handler: ConnectionHandler): void {\n this.connectHandlers.push(handler)\n }\n\n /** Register a handler for disconnection */\n onDisconnect(handler: ConnectionHandler): void {\n this.disconnectHandlers.push(handler)\n }\n\n /** Update the runtime status (used in heartbeat) */\n updateStatus(status: AgentRuntimeStatus): void {\n this.runtimeStatus = status\n }\n\n /** Whether currently connected */\n get connected(): boolean {\n return this.ws?.readyState === 1\n }\n\n private doConnect(\n onConnect?: (value: void) => void,\n onError?: (err: Error) => void,\n ): void {\n if (this.destroyed) return\n\n // Dynamic import ws to keep this file framework-agnostic at the type level\n import('ws').then(({ default: WebSocket }) => {\n if (this.destroyed) return\n\n const url = this.token\n ? `${this.hubUrl}?token=${encodeURIComponent(this.token)}`\n : this.hubUrl\n\n // Accept self-signed certs when connecting over WSS (safe for local LAN)\n const wsOptions = this.hubUrl.startsWith('wss://')\n ? { rejectUnauthorized: false }\n : {}\n\n try {\n this.ws = new WebSocket(url, wsOptions)\n } catch (err) {\n this.scheduleReconnect()\n if (onError) {\n onError(err instanceof Error ? err : new Error(String(err)))\n onError = undefined\n }\n return\n }\n\n this.ws.once('open', () => {\n this.reconnectAttempt = 0\n this.logger.info(`Connected to hub: ${this.hubUrl}`)\n\n // Send registration\n this.send({ type: 'register', info: this.registrationInfo })\n\n // Start heartbeat\n this.startHeartbeat()\n\n for (const h of this.connectHandlers) h()\n\n if (onConnect) {\n onConnect()\n onConnect = undefined\n }\n })\n\n this.ws.on('message', (data: Buffer | string, isBinary: boolean) => {\n const buf = Buffer.isBuffer(data) ? data : Buffer.from(data as unknown as ArrayBuffer)\n if (isBinary) {\n for (const h of this.binaryHandlers) h(buf)\n } else {\n try {\n const msg = JSON.parse(buf.toString()) as HubToAgentMessage\n this.handleBuiltinMessage(msg)\n for (const h of this.messageHandlers) h(msg)\n } catch {\n this.logger.warn('Failed to parse message from hub')\n }\n }\n })\n\n this.ws.once('close', () => {\n this.stopHeartbeat()\n for (const h of this.disconnectHandlers) h()\n if (!this.destroyed) {\n this.logger.warn('Disconnected from hub, scheduling reconnect')\n this.scheduleReconnect()\n }\n })\n\n this.ws.once('error', (err) => {\n this.logger.error('WebSocket error', { message: err.message })\n if (onError) {\n onError(err)\n onError = undefined\n }\n })\n }).catch((err) => {\n this.logger.error('Failed to import ws module', { message: String(err) })\n if (onError) {\n onError(err instanceof Error ? err : new Error(String(err)))\n }\n })\n }\n\n private handleBuiltinMessage(msg: HubToAgentMessage): void {\n if (msg.type === 'ping') {\n this.send({ type: 'pong' })\n }\n }\n\n private scheduleReconnect(): void {\n if (this.destroyed) return\n const delay = Math.min(\n RECONNECT_BASE_MS * Math.pow(2, this.reconnectAttempt),\n RECONNECT_MAX_MS,\n )\n this.reconnectAttempt++\n this.logger.info(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt})`)\n this.reconnectTimer = setTimeout(() => {\n this.doConnect()\n }, delay)\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat()\n this.heartbeatTimer = setInterval(() => {\n this.send({ type: 'heartbeat', status: this.runtimeStatus })\n }, HEARTBEAT_INTERVAL_MS)\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer)\n this.heartbeatTimer = null\n }\n }\n\n private clearTimers(): void {\n this.stopHeartbeat()\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n }\n}\n","import type { ITaskHandler, TaskContext, TaskProgress } from '@camstack/types'\nimport type { IScopedLogger } from '../logging/scoped-logger.js'\nimport type { AgentClient } from './agent-client.js'\n\ninterface RunningTask {\n readonly taskId: string\n readonly taskType: string\n cancelled: boolean\n}\n\n/**\n * Receives task assignments from hub, routes to registered ITaskHandler instances.\n * Maintains handler registry, manages task lifecycle.\n * Framework-agnostic (no NestJS).\n */\nexport class AgentTaskRunner {\n private readonly handlers = new Map<string, ITaskHandler>()\n private readonly runningTasks = new Map<string, RunningTask>()\n private readonly logger: IScopedLogger\n\n constructor(\n private readonly agentId: string,\n private readonly client: AgentClient,\n logger: IScopedLogger,\n ) {\n this.logger = logger.child('TaskRunner')\n }\n\n /** Register a task handler for a given task type */\n registerHandler(handler: ITaskHandler): void {\n if (this.handlers.has(handler.taskType)) {\n this.logger.warn(`Overwriting handler for task type: ${handler.taskType}`)\n }\n this.handlers.set(handler.taskType, handler)\n this.logger.debug(`Registered handler: ${handler.taskType}`)\n }\n\n /** Unregister a task handler */\n unregisterHandler(taskType: string): void {\n this.handlers.delete(taskType)\n }\n\n /** Get all registered task types */\n getTaskTypes(): readonly string[] {\n return [...this.handlers.keys()]\n }\n\n /** Get a handler by task type */\n getHandler(taskType: string): ITaskHandler | undefined {\n return this.handlers.get(taskType)\n }\n\n /**\n * Execute a task dispatched from the hub.\n * Sends result or error back to hub via the AgentClient.\n */\n async executeTask(taskId: string, taskType: string, payload: unknown): Promise<void> {\n const handler = this.handlers.get(taskType)\n if (!handler) {\n this.client.send({\n type: 'task.result',\n taskId,\n success: false,\n error: `No handler registered for task type: ${taskType}`,\n })\n return\n }\n\n const runningTask: RunningTask = { taskId, taskType, cancelled: false }\n this.runningTasks.set(taskId, runningTask)\n\n const context: TaskContext = {\n taskId,\n agentId: this.agentId,\n logger: this.logger.child(taskType),\n reportProgress: (progress: TaskProgress) => {\n this.client.send({ type: 'task.progress', taskId, progress })\n },\n isCancelled: () => runningTask.cancelled,\n }\n\n try {\n const result = await handler.handle(payload, context)\n this.runningTasks.delete(taskId)\n\n if (!runningTask.cancelled) {\n this.client.send({\n type: 'task.result',\n taskId,\n success: true,\n result,\n })\n }\n } catch (err) {\n this.runningTasks.delete(taskId)\n\n this.logger.error(`Task ${taskType} (${taskId}) failed`, {\n message: err instanceof Error ? err.message : String(err),\n })\n\n this.client.send({\n type: 'task.result',\n taskId,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n /** Cancel a running task */\n async cancelTask(taskId: string): Promise<void> {\n const running = this.runningTasks.get(taskId)\n if (!running) return\n\n running.cancelled = true\n\n const handler = this.handlers.get(running.taskType)\n if (handler?.cancel) {\n try {\n await handler.cancel()\n } catch (err) {\n this.logger.error(`Error cancelling task ${taskId}`, {\n message: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n this.runningTasks.delete(taskId)\n }\n\n /** Number of currently running tasks */\n get activeTaskCount(): number {\n return this.runningTasks.size\n }\n\n /** Destroy: cancel all running tasks */\n async destroy(): Promise<void> {\n const taskIds = [...this.runningTasks.keys()]\n for (const taskId of taskIds) {\n await this.cancelTask(taskId)\n }\n this.handlers.clear()\n }\n}\n","import type { ITaskHandler, TaskContext } from '@camstack/types'\n\n/**\n * Stub task handler for pipeline.decode.\n * In the full implementation, this would start a StreamBroker for a camera\n * and send decoded frames to the hub via the AgentClient.\n */\nexport class DecodeTaskHandler implements ITaskHandler {\n readonly taskType = 'pipeline.decode'\n readonly description = 'Decode an RTSP stream and produce JPEG frames'\n\n async handle(payload: unknown, context: TaskContext): Promise<unknown> {\n const { logger } = context\n const config = payload as { cameraId?: string; rtspUrl?: string; fps?: number }\n\n if (!config.cameraId || !config.rtspUrl) {\n throw new Error('pipeline.decode requires cameraId and rtspUrl in payload')\n }\n\n logger.info(`Decode task started: camera=${config.cameraId} url=${config.rtspUrl} fps=${config.fps ?? 1}`)\n\n // Stub: actual implementation would start ffmpeg, produce frames,\n // and send them via the AgentClient's sendBinary method.\n return { status: 'started', cameraId: config.cameraId }\n }\n\n async cancel(): Promise<void> {\n // Stub: stop ffmpeg process\n }\n}\n\n/**\n * Stub task handler for pipeline.detect.\n * In the full implementation, this would receive frames (via binary WS),\n * run them through the detection engine, and send results back.\n */\nexport class DetectTaskHandler implements ITaskHandler {\n readonly taskType = 'pipeline.detect'\n readonly description = 'Run object detection on received frames'\n\n async handle(payload: unknown, context: TaskContext): Promise<unknown> {\n const { logger } = context\n const config = payload as {\n cameraId?: string\n modelId?: string\n runtime?: string\n confidence?: number\n }\n\n if (!config.cameraId) {\n throw new Error('pipeline.detect requires cameraId in payload')\n }\n\n logger.info(`Detect task started: camera=${config.cameraId} model=${config.modelId ?? 'default'} runtime=${config.runtime ?? 'auto'}`)\n\n // Stub: actual implementation would subscribe to binary frame stream,\n // run inference, and send detection results back to hub.\n return { status: 'started', cameraId: config.cameraId }\n }\n\n async cancel(): Promise<void> {\n // Stub: stop detection loop\n }\n}\n\n/**\n * Stub task handler for pipeline.record.\n * In the full implementation, this would start recording an RTSP stream\n * to disk in segments and report segment metadata back to the hub.\n */\nexport class RecordTaskHandler implements ITaskHandler {\n readonly taskType = 'pipeline.record'\n readonly description = 'Record an RTSP stream to disk segments'\n\n async handle(payload: unknown, context: TaskContext): Promise<unknown> {\n const { logger } = context\n const config = payload as { cameraId?: string; rtspUrl?: string; storagePath?: string }\n\n if (!config.cameraId || !config.rtspUrl) {\n throw new Error('pipeline.record requires cameraId and rtspUrl in payload')\n }\n\n logger.info(`Record task started: camera=${config.cameraId} url=${config.rtspUrl}`)\n\n // Stub: actual implementation would start ffmpeg copy-mode recording.\n return { status: 'started', cameraId: config.cameraId }\n }\n\n async cancel(): Promise<void> {\n // Stub: stop recording process\n }\n}\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type {\n IStorageProvider as INewStorageProvider,\n StorageLocationType,\n} from '@camstack/types'\n\n// Inline constants to avoid runtime dependency on @camstack/types\n// (types is external in tsup bundle, may not be resolvable from data/addons/)\nconst STORAGE_LOCATION_TYPES: readonly StorageLocationType[] = [\n 'recordings-high', 'recordings-low', 'recordings-clips', 'event-images',\n 'models', 'addons-data', 'cache', 'logs',\n]\n\nconst DEFAULT_LOCATION_SUBDIRS: Readonly<Record<StorageLocationType, string>> = {\n 'recordings-high': 'recordings-high',\n 'recordings-low': 'recordings-low',\n 'recordings-clips': 'recordings-clips',\n 'event-images': 'event-images',\n 'models': 'models',\n 'addons-data': 'addons-data',\n 'cache': '/tmp/camstack-cache',\n 'logs': 'logs',\n}\n\n/**\n * Filesystem storage provider — serves all location types from a local directory tree.\n *\n * Default layout:\n * {rootPath}/recordings-high/\n * {rootPath}/recordings-low/\n * {rootPath}/recordings-clips/\n * {rootPath}/event-images/\n * {rootPath}/models/\n * {rootPath}/addons-data/\n * {rootPath}/logs/\n * /tmp/camstack-cache/ (cache is always local)\n *\n * Individual location paths can be overridden.\n */\nexport class FilesystemStorageProvider implements INewStorageProvider {\n readonly id = 'local'\n readonly name = 'Local Filesystem'\n readonly supportedLocations: readonly StorageLocationType[] = [...STORAGE_LOCATION_TYPES]\n\n private readonly rootPath: string\n private readonly locationPaths: Map<StorageLocationType, string>\n\n constructor(rootPath: string, overrides?: Partial<Record<StorageLocationType, string>>) {\n this.rootPath = path.resolve(rootPath)\n this.locationPaths = new Map()\n\n for (const loc of STORAGE_LOCATION_TYPES) {\n const override = overrides?.[loc]\n if (override) {\n this.locationPaths.set(loc, path.resolve(override))\n } else {\n const subdir = DEFAULT_LOCATION_SUBDIRS[loc]\n // Absolute paths (like /tmp/camstack-cache) are used as-is\n this.locationPaths.set(\n loc,\n path.isAbsolute(subdir) ? subdir : path.join(this.rootPath, subdir),\n )\n }\n }\n }\n\n resolve(location: StorageLocationType, relativePath: string): string {\n const base = this.locationPaths.get(location)\n if (!base) throw new Error(`Unknown storage location: ${location}`)\n return path.join(base, relativePath)\n }\n\n async write(location: StorageLocationType, relativePath: string, data: Buffer | NodeJS.ReadableStream): Promise<void> {\n const filePath = this.resolve(location, relativePath)\n await fs.promises.mkdir(path.dirname(filePath), { recursive: true })\n\n if (Buffer.isBuffer(data)) {\n await fs.promises.writeFile(filePath, data)\n } else {\n // Stream\n const writeStream = fs.createWriteStream(filePath)\n await new Promise<void>((resolve, reject) => {\n (data as NodeJS.ReadableStream).pipe(writeStream)\n writeStream.on('finish', resolve)\n writeStream.on('error', reject)\n })\n }\n }\n\n async read(location: StorageLocationType, relativePath: string): Promise<Buffer> {\n return fs.promises.readFile(this.resolve(location, relativePath))\n }\n\n async exists(location: StorageLocationType, relativePath: string): Promise<boolean> {\n try {\n await fs.promises.access(this.resolve(location, relativePath))\n return true\n } catch {\n return false\n }\n }\n\n async list(location: StorageLocationType, prefix?: string): Promise<readonly string[]> {\n const base = this.locationPaths.get(location)\n if (!base) return []\n const dir = prefix ? path.join(base, prefix) : base\n try {\n const entries = await fs.promises.readdir(dir, { withFileTypes: true })\n return entries.map(e => (prefix ? `${prefix}/${e.name}` : e.name))\n } catch {\n return []\n }\n }\n\n async delete(location: StorageLocationType, relativePath: string): Promise<void> {\n const filePath = this.resolve(location, relativePath)\n await fs.promises.rm(filePath, { force: true })\n }\n\n async getAvailableSpace(location: StorageLocationType): Promise<number | null> {\n const base = this.locationPaths.get(location)\n if (!base) return null\n try {\n const stats = await fs.promises.statfs(base)\n return stats.bavail * stats.bsize\n } catch {\n return null\n }\n }\n\n async initialize(): Promise<void> {\n for (const [, dirPath] of this.locationPaths) {\n await fs.promises.mkdir(dirPath, { recursive: true })\n }\n }\n\n async shutdown(): Promise<void> {\n // Nothing to clean up for filesystem\n }\n\n /** Get the resolved path for a location type */\n getLocationPath(location: StorageLocationType): string {\n const p = this.locationPaths.get(location)\n if (!p) throw new Error(`Unknown storage location: ${location}`)\n return p\n }\n\n /** Get the root path */\n getRootPath(): string {\n return this.rootPath\n }\n}\n\nexport default FilesystemStorageProvider\n","import Database from 'better-sqlite3'\nimport { randomUUID } from 'node:crypto'\nimport type {\n ISettingsBackend,\n SettingsCollection,\n SettingsRecord,\n QueryFilter,\n TableSchema,\n TableQueryOptions,\n} from '@camstack/types'\n\n/**\n * SQLite implementation of ISettingsBackend.\n *\n * One table per collection, auto-created on first access.\n * All data stored as JSON in a TEXT column.\n * WAL mode for concurrent reads.\n */\nexport class SqliteSettingsBackend implements ISettingsBackend {\n private db: Database.Database | null = null\n private readonly ensuredTables = new Set<string>()\n private readonly structuredTables = new Set<string>()\n private readonly runtimeDefaults: Record<string, unknown>\n\n constructor(private readonly dbPath: string, runtimeDefaults?: Record<string, unknown>) {\n this.runtimeDefaults = runtimeDefaults ?? {}\n }\n\n async initialize(): Promise<void> {\n // Ensure parent directory exists\n const dir = this.dbPath.substring(0, this.dbPath.lastIndexOf('/'))\n if (dir) {\n const fs = await import('node:fs')\n fs.mkdirSync(dir, { recursive: true })\n }\n this.db = new Database(this.dbPath)\n this.db.pragma('journal_mode = WAL')\n this.db.pragma('foreign_keys = ON')\n\n // Seed system-settings on first boot\n const isEmpty = await this.isEmpty('system-settings')\n if (isEmpty) {\n await this.seedDefaults()\n }\n }\n\n async shutdown(): Promise<void> {\n this.db?.close()\n this.db = null\n }\n\n // ---------------------------------------------------------------------------\n // ISettingsBackend implementation\n // ---------------------------------------------------------------------------\n\n async get(collection: SettingsCollection, key: string): Promise<unknown> {\n this.ensureCollectionTable(collection)\n const row = this.getDb()\n .prepare<[string], { data: string }>(`SELECT data FROM \"${collection}\" WHERE id = ?`)\n .get(key)\n if (!row) return undefined\n return JSON.parse(row.data)\n }\n\n async set(collection: SettingsCollection, key: string, value: unknown): Promise<void> {\n this.ensureCollectionTable(collection)\n this.getDb()\n .prepare(`INSERT INTO \"${collection}\" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data`)\n .run(key, JSON.stringify(value))\n }\n\n async query(collection: SettingsCollection, filter?: QueryFilter): Promise<readonly SettingsRecord[]> {\n this.ensureCollectionTable(collection)\n let sql = `SELECT id, data FROM \"${collection}\"`\n const params: unknown[] = []\n\n const whereClauses: string[] = []\n\n if (filter?.where) {\n for (const [field, value] of Object.entries(filter.where)) {\n if (field === 'id') {\n whereClauses.push('id = ?')\n params.push(value)\n } else {\n whereClauses.push(`json_extract(data, '$.${field}') = ?`)\n params.push(typeof value === 'object' ? JSON.stringify(value) : value)\n }\n }\n }\n\n if (filter?.whereIn) {\n for (const [field, values] of Object.entries(filter.whereIn)) {\n const placeholders = values.map(() => '?').join(', ')\n if (field === 'id') {\n whereClauses.push(`id IN (${placeholders})`)\n } else {\n whereClauses.push(`json_extract(data, '$.${field}') IN (${placeholders})`)\n }\n params.push(...values)\n }\n }\n\n if (filter?.whereBetween) {\n for (const [field, [low, high]] of Object.entries(filter.whereBetween)) {\n if (field === 'id') {\n whereClauses.push('id BETWEEN ? AND ?')\n } else {\n whereClauses.push(`json_extract(data, '$.${field}') BETWEEN ? AND ?`)\n }\n params.push(low, high)\n }\n }\n\n if (whereClauses.length > 0) {\n sql += ` WHERE ${whereClauses.join(' AND ')}`\n }\n\n if (filter?.orderBy) {\n const dir = filter.orderBy.direction === 'desc' ? 'DESC' : 'ASC'\n if (filter.orderBy.field === 'id') {\n sql += ` ORDER BY id ${dir}`\n } else {\n sql += ` ORDER BY json_extract(data, '$.${filter.orderBy.field}') ${dir}`\n }\n }\n\n if (filter?.limit) {\n sql += ` LIMIT ?`\n params.push(filter.limit)\n }\n\n if (filter?.offset) {\n sql += ` OFFSET ?`\n params.push(filter.offset)\n }\n\n const rows = this.getDb()\n .prepare<unknown[], { id: string; data: string }>(sql)\n .all(...params)\n\n return rows.map(row => ({\n id: row.id,\n data: JSON.parse(row.data),\n }))\n }\n\n async insert(collection: SettingsCollection, record: SettingsRecord): Promise<void> {\n this.ensureCollectionTable(collection)\n const id = record.id || randomUUID()\n this.getDb()\n .prepare(`INSERT INTO \"${collection}\" (id, data) VALUES (?, ?)`)\n .run(id, JSON.stringify(record.data))\n }\n\n async update(collection: SettingsCollection, id: string, data: Record<string, unknown>): Promise<void> {\n this.ensureCollectionTable(collection)\n this.getDb()\n .prepare(`UPDATE \"${collection}\" SET data = ? WHERE id = ?`)\n .run(JSON.stringify(data), id)\n }\n\n async delete(collection: SettingsCollection, key: string): Promise<void> {\n this.ensureCollectionTable(collection)\n this.getDb()\n .prepare(`DELETE FROM \"${collection}\" WHERE id = ?`)\n .run(key)\n }\n\n async count(collection: SettingsCollection, filter?: QueryFilter): Promise<number> {\n this.ensureCollectionTable(collection)\n if (!filter) {\n const row = this.getDb()\n .prepare<[], { cnt: number }>(`SELECT COUNT(*) AS cnt FROM \"${collection}\"`)\n .get()\n return row?.cnt ?? 0\n }\n const rows = await this.query(collection, { ...filter, limit: undefined, offset: undefined })\n return rows.length\n }\n\n async isEmpty(collection: SettingsCollection): Promise<boolean> {\n this.ensureCollectionTable(collection)\n const row = this.getDb()\n .prepare<[], { cnt: number }>(`SELECT COUNT(*) AS cnt FROM \"${collection}\"`)\n .get()\n return (row?.cnt ?? 0) === 0\n }\n\n // ---------------------------------------------------------------------------\n // Legacy SettingsStore compatibility (used by ConfigManager.setSettingsStore)\n // ---------------------------------------------------------------------------\n\n /** Get a system setting by dot-notation key */\n getSystem(key: string): unknown {\n this.ensureCollectionTable('system-settings')\n const row = this.getDb()\n .prepare<[string], { data: string }>('SELECT data FROM \"system-settings\" WHERE id = ?')\n .get(key)\n if (!row) return undefined\n return JSON.parse(row.data)\n }\n\n /** Set a system setting */\n setSystem(key: string, value: unknown): void {\n this.ensureCollectionTable('system-settings')\n this.getDb()\n .prepare('INSERT INTO \"system-settings\" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data')\n .run(key, JSON.stringify(value))\n }\n\n /** Get all system settings as flat key-value */\n getAllSystem(): Record<string, unknown> {\n this.ensureCollectionTable('system-settings')\n const rows = this.getDb()\n .prepare<[], { id: string; data: string }>('SELECT id, data FROM \"system-settings\"')\n .all()\n return Object.fromEntries(rows.map(r => [r.id, JSON.parse(r.data)]))\n }\n\n /** Get all settings for an addon */\n getAllAddon(addonId: string): Record<string, unknown> {\n this.ensureCollectionTable('addon-settings')\n const rows = this.getDb()\n .prepare<[string], { id: string; data: string }>('SELECT id, data FROM \"addon-settings\" WHERE json_extract(data, \\'$.addonId\\') = ?')\n .all(addonId)\n if (rows.length === 0) return {}\n // addon-settings stores all keys for an addon as separate rows with id = \"addonId.key\"\n const result: Record<string, unknown> = {}\n for (const row of rows) {\n const parsed = JSON.parse(row.data)\n const key = row.id.startsWith(`${addonId}.`) ? row.id.slice(addonId.length + 1) : row.id\n result[key] = parsed.value ?? parsed\n }\n return result\n }\n\n /** Bulk-set all settings for an addon */\n setAllAddon(addonId: string, config: Record<string, unknown>): void {\n this.ensureCollectionTable('addon-settings')\n const db = this.getDb()\n const deleteStmt = db.prepare('DELETE FROM \"addon-settings\" WHERE id LIKE ? || \\'%\\'')\n const insertStmt = db.prepare('INSERT INTO \"addon-settings\" (id, data) VALUES (?, ?)')\n db.transaction(() => {\n deleteStmt.run(`${addonId}.`)\n for (const [key, value] of Object.entries(config)) {\n insertStmt.run(`${addonId}.${key}`, JSON.stringify({ addonId, key, value }))\n }\n })()\n }\n\n /** Get all settings for a provider */\n getAllProvider(providerId: string): Record<string, unknown> {\n return this.getAllScoped('provider-settings', providerId)\n }\n\n /** Set a provider setting */\n setProvider(providerId: string, key: string, value: unknown): void {\n this.setScopedKey('provider-settings', providerId, key, value)\n }\n\n /** Get all settings for a device */\n getAllDevice(deviceId: string): Record<string, unknown> {\n return this.getAllScoped('device-settings', deviceId)\n }\n\n /** Set a device setting */\n setDevice(deviceId: string, key: string, value: unknown): void {\n this.setScopedKey('device-settings', deviceId, key, value)\n }\n\n /** Seed system-settings with runtime defaults (first boot) */\n private async seedDefaults(): Promise<void> {\n this.ensureCollectionTable('system-settings')\n const insert = this.getDb().prepare(\n 'INSERT OR IGNORE INTO \"system-settings\" (id, data) VALUES (?, ?)',\n )\n this.getDb().transaction(() => {\n for (const [key, value] of Object.entries(this.runtimeDefaults)) {\n insert.run(key, JSON.stringify(value))\n }\n })()\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private getDb(): Database.Database {\n if (!this.db) throw new Error('SqliteSettingsBackend not initialized — call initialize() first')\n return this.db\n }\n\n private ensureCollectionTable(collection: string): void {\n if (this.ensuredTables.has(collection)) return\n this.getDb().exec(\n `CREATE TABLE IF NOT EXISTS \"${collection}\" (id TEXT PRIMARY KEY, data TEXT NOT NULL)`,\n )\n this.ensuredTables.add(collection)\n }\n\n private getAllScoped(collection: string, scopeId: string): Record<string, unknown> {\n this.ensureCollectionTable(collection)\n const rows = this.getDb()\n .prepare<[string], { id: string; data: string }>(`SELECT id, data FROM \"${collection}\" WHERE id LIKE ? || '.%'`)\n .all(scopeId)\n const result: Record<string, unknown> = {}\n for (const row of rows) {\n const key = row.id.slice(scopeId.length + 1)\n const parsed = JSON.parse(row.data)\n result[key] = parsed.value ?? parsed\n }\n return result\n }\n\n private setScopedKey(collection: string, scopeId: string, key: string, value: unknown): void {\n this.ensureCollectionTable(collection)\n this.getDb()\n .prepare(`INSERT INTO \"${collection}\" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data`)\n .run(`${scopeId}.${key}`, JSON.stringify({ scopeId, key, value }))\n }\n\n // ── Structured table operations ────────────────────────────────────\n\n async ensureTable(table: string, schema?: TableSchema): Promise<void> {\n if (!schema) {\n // Legacy: ensure JSON-blob collection table\n if (!this.ensuredTables.has(table)) {\n this.getDb().exec(`CREATE TABLE IF NOT EXISTS \"${table}\" (id TEXT PRIMARY KEY, data TEXT NOT NULL)`)\n this.ensuredTables.add(table)\n }\n return\n }\n if (this.structuredTables.has(table)) return\n\n const colDefs = schema.columns.map(col => {\n const parts = [`\"${col.name}\" ${col.type}`]\n if (col.primaryKey) parts.push('PRIMARY KEY')\n if (col.notNull) parts.push('NOT NULL')\n if (col.unique) parts.push('UNIQUE')\n if (col.defaultValue !== undefined) {\n parts.push(`DEFAULT ${typeof col.defaultValue === 'string' ? `'${col.defaultValue}'` : col.defaultValue === null ? 'NULL' : String(col.defaultValue)}`)\n }\n return parts.join(' ')\n })\n\n this.getDb().exec(`CREATE TABLE IF NOT EXISTS \"${table}\" (${colDefs.join(', ')})`)\n\n if (schema.indexes) {\n for (const idx of schema.indexes) {\n const unique = idx.unique ? 'UNIQUE ' : ''\n const cols = idx.columns.map(c => `\"${c}\"`).join(', ')\n this.getDb().exec(`CREATE ${unique}INDEX IF NOT EXISTS \"${idx.name}\" ON \"${table}\" (${cols})`)\n }\n }\n\n this.structuredTables.add(table)\n }\n\n async tableInsert(table: string, row: Record<string, unknown>): Promise<void> {\n const keys = Object.keys(row)\n const cols = keys.map(k => `\"${k}\"`).join(', ')\n const placeholders = keys.map(() => '?').join(', ')\n const values = keys.map(k => {\n const v = row[k]\n return typeof v === 'object' && v !== null ? JSON.stringify(v) : v\n })\n this.getDb().prepare(`INSERT INTO \"${table}\" (${cols}) VALUES (${placeholders})`).run(...values)\n }\n\n async tableUpdate(table: string, filter: Record<string, unknown>, updates: Record<string, unknown>): Promise<number> {\n const setClauses: string[] = []\n const setValues: unknown[] = []\n for (const [k, v] of Object.entries(updates)) {\n setClauses.push(`\"${k}\" = ?`)\n setValues.push(typeof v === 'object' && v !== null ? JSON.stringify(v) : v)\n }\n\n const { whereSql, whereValues } = this.buildWhere(filter)\n const result = this.getDb()\n .prepare(`UPDATE \"${table}\" SET ${setClauses.join(', ')}${whereSql}`)\n .run(...setValues, ...whereValues)\n return result.changes\n }\n\n async tableDelete(table: string, filter: Record<string, unknown>): Promise<number> {\n const { whereSql, whereValues } = this.buildWhere(filter)\n const result = this.getDb().prepare(`DELETE FROM \"${table}\"${whereSql}`).run(...whereValues)\n return result.changes\n }\n\n async tableQuery(table: string, options?: TableQueryOptions): Promise<readonly Record<string, unknown>[]> {\n let sql = `SELECT * FROM \"${table}\"`\n const values: unknown[] = []\n\n if (options?.where) {\n const { whereSql, whereValues } = this.buildWhere(options.where)\n sql += whereSql\n values.push(...whereValues)\n }\n\n if (options?.orderBy) {\n sql += ` ORDER BY \"${options.orderBy.field}\" ${options.orderBy.direction === 'desc' ? 'DESC' : 'ASC'}`\n }\n\n if (options?.limit !== undefined) {\n sql += ` LIMIT ?`\n values.push(options.limit)\n }\n\n if (options?.offset !== undefined) {\n sql += ` OFFSET ?`\n values.push(options.offset)\n }\n\n return this.getDb().prepare(sql).all(...values) as Record<string, unknown>[]\n }\n\n async tableGet(table: string, filter: Record<string, unknown>): Promise<Record<string, unknown> | null> {\n const { whereSql, whereValues } = this.buildWhere(filter)\n const row = this.getDb().prepare(`SELECT * FROM \"${table}\"${whereSql} LIMIT 1`).get(...whereValues)\n return (row as Record<string, unknown>) ?? null\n }\n\n async tableCount(table: string, filter?: Record<string, unknown>): Promise<number> {\n let sql = `SELECT COUNT(*) as count FROM \"${table}\"`\n const values: unknown[] = []\n\n if (filter) {\n const { whereSql, whereValues } = this.buildWhere(filter)\n sql += whereSql\n values.push(...whereValues)\n }\n\n const row = this.getDb().prepare(sql).get(...values) as { count: number }\n return row.count\n }\n\n private buildWhere(filter: Record<string, unknown>): { whereSql: string; whereValues: unknown[] } {\n const conditions: string[] = []\n const values: unknown[] = []\n for (const [k, v] of Object.entries(filter)) {\n conditions.push(`\"${k}\" = ?`)\n values.push(typeof v === 'object' && v !== null ? JSON.stringify(v) : v)\n }\n const whereSql = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : ''\n return { whereSql, whereValues: values }\n }\n}\n\nexport default SqliteSettingsBackend\n","import Database from 'better-sqlite3'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { randomUUID } from 'node:crypto'\nimport type {\n IStorageProvider,\n IStorageLocation,\n IStructuredStorage,\n IFileStorage,\n StorageLocationName,\n StorageRecord,\n QueryFilter,\n} from '@camstack/types'\n\ntype LocationType = 'structured' | 'files' | 'both'\n\n/** Which locations need structured (SQL) storage, files storage, or both.\n * All structured locations share a SINGLE SQLite database (camstack.db).\n * File locations use the filesystem at their configured path. */\nconst LOCATION_TYPES: Record<string, LocationType> = {\n // New location names (from StorageLocationManager)\n data: 'structured', // settings, events, trails — SQL only\n media: 'files', // crops, snapshots, thumbnails — files only\n recordings: 'files', // video segments — files only\n models: 'files', // ONNX/TFLite models — files only\n cache: 'files', // temp files — files only\n logs: 'files', // Winston log files — files only\n // Legacy location names (backward compat)\n config: 'structured',\n events: 'structured',\n addon: 'both',\n}\n\nclass SqliteStructuredStorage implements IStructuredStorage {\n private readonly ensuredTables = new Set<string>()\n\n constructor(private readonly db: Database.Database) {}\n\n private ensureTable(collection: string): void {\n if (this.ensuredTables.has(collection)) return\n this.db.exec(\n `CREATE TABLE IF NOT EXISTS \"${collection}\" (id TEXT PRIMARY KEY, data TEXT)`,\n )\n this.ensuredTables.add(collection)\n }\n\n async insert(record: StorageRecord): Promise<StorageRecord> {\n this.ensureTable(record.collection)\n const id = record.id || randomUUID()\n const newRecord: StorageRecord = {\n collection: record.collection,\n id,\n data: record.data,\n }\n this.db\n .prepare(`INSERT INTO \"${record.collection}\" (id, data) VALUES (?, ?)`)\n .run(id, JSON.stringify(newRecord.data))\n return newRecord\n }\n\n async query(collection: string, filter?: QueryFilter): Promise<readonly StorageRecord[]> {\n this.ensureTable(collection)\n const { sql, params } = this.buildSelect(collection, filter)\n const rows = this.db.prepare(sql).all(...params) as Array<{ id: string; data: string }>\n return rows.map((row) => ({\n collection,\n id: row.id,\n data: JSON.parse(row.data) as Record<string, unknown>,\n }))\n }\n\n async update(\n collection: string,\n id: string,\n data: Record<string, unknown>,\n ): Promise<StorageRecord> {\n this.ensureTable(collection)\n this.db\n .prepare(`UPDATE \"${collection}\" SET data = ? WHERE id = ?`)\n .run(JSON.stringify(data), id)\n return { collection, id, data }\n }\n\n async delete(collection: string, id: string): Promise<void> {\n this.ensureTable(collection)\n this.db.prepare(`DELETE FROM \"${collection}\" WHERE id = ?`).run(id)\n }\n\n async count(collection: string, filter?: QueryFilter): Promise<number> {\n this.ensureTable(collection)\n const { sql, params } = this.buildCount(collection, filter)\n const row = this.db.prepare(sql).get(...params) as { cnt: number }\n return row.cnt\n }\n\n private buildWhereClause(filter?: QueryFilter): { clause: string; params: unknown[] } {\n if (!filter) return { clause: '', params: [] }\n\n const conditions: string[] = []\n const params: unknown[] = []\n\n if (filter.where) {\n for (const [field, value] of Object.entries(filter.where)) {\n if (field === 'id') {\n conditions.push('id = ?')\n params.push(value)\n } else {\n conditions.push(`json_extract(data, '$.${field}') = ?`)\n params.push(value)\n }\n }\n }\n\n if (filter.whereIn) {\n for (const [field, values] of Object.entries(filter.whereIn)) {\n const placeholders = values.map(() => '?').join(', ')\n if (field === 'id') {\n conditions.push(`id IN (${placeholders})`)\n } else {\n conditions.push(`json_extract(data, '$.${field}') IN (${placeholders})`)\n }\n params.push(...values)\n }\n }\n\n if (filter.whereBetween) {\n for (const [field, [low, high]] of Object.entries(filter.whereBetween)) {\n if (field === 'id') {\n conditions.push('id BETWEEN ? AND ?')\n } else {\n conditions.push(`json_extract(data, '$.${field}') BETWEEN ? AND ?`)\n }\n params.push(low, high)\n }\n }\n\n const clause = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : ''\n return { clause, params }\n }\n\n private buildSelect(collection: string, filter?: QueryFilter): { sql: string; params: unknown[] } {\n const { clause, params } = this.buildWhereClause(filter)\n let sql = `SELECT id, data FROM \"${collection}\"${clause}`\n\n if (filter?.orderBy) {\n const dir = filter.orderBy.direction === 'desc' ? 'DESC' : 'ASC'\n if (filter.orderBy.field === 'id') {\n sql += ` ORDER BY id ${dir}`\n } else {\n sql += ` ORDER BY json_extract(data, '$.${filter.orderBy.field}') ${dir}`\n }\n }\n\n if (filter?.limit !== undefined) {\n sql += ` LIMIT ?`\n params.push(filter.limit)\n }\n\n if (filter?.offset !== undefined) {\n sql += ` OFFSET ?`\n params.push(filter.offset)\n }\n\n return { sql, params }\n }\n\n private buildCount(collection: string, filter?: QueryFilter): { sql: string; params: unknown[] } {\n const { clause, params } = this.buildWhereClause(filter)\n return { sql: `SELECT COUNT(*) as cnt FROM \"${collection}\"${clause}`, params }\n }\n}\n\nexport class FileSystemStorage implements IFileStorage {\n constructor(private readonly basePath: string) {}\n\n async readFile(filePath: string): Promise<Buffer> {\n const fullPath = path.join(this.basePath, filePath)\n return fs.promises.readFile(fullPath)\n }\n\n async writeFile(filePath: string, data: Buffer): Promise<void> {\n const fullPath = path.join(this.basePath, filePath)\n fs.mkdirSync(path.dirname(fullPath), { recursive: true })\n await fs.promises.writeFile(fullPath, data)\n }\n\n async deleteFile(filePath: string): Promise<void> {\n const fullPath = path.join(this.basePath, filePath)\n await fs.promises.unlink(fullPath)\n }\n\n async listFiles(prefix?: string): Promise<readonly string[]> {\n const searchDir = prefix ? path.join(this.basePath, prefix) : this.basePath\n try {\n const entries = await fs.promises.readdir(searchDir, { recursive: true })\n const files: string[] = []\n for (const entry of entries) {\n const entryStr = String(entry)\n const relative = prefix ? path.join(prefix, entryStr) : entryStr\n const fullPath = path.join(this.basePath, relative)\n try {\n const stat = await fs.promises.stat(fullPath)\n if (stat.isFile()) {\n files.push(relative)\n }\n } catch {\n // Skip entries that can't be stat'd\n }\n }\n return files\n } catch {\n return []\n }\n }\n\n async getFileUrl(_path: string): Promise<string> {\n return null as unknown as string\n }\n\n async exists(filePath: string): Promise<boolean> {\n const fullPath = path.join(this.basePath, filePath)\n try {\n await fs.promises.access(fullPath, fs.constants.F_OK)\n return true\n } catch {\n return false\n }\n }\n}\n\n/** @deprecated Use FilesystemStorageProvider + SqliteSettingsBackend instead */\nexport class SqliteStorageProvider {\n private mainDb: Database.Database | null = null\n private sharedStructured: SqliteStructuredStorage | null = null\n private readonly locations = new Map<StorageLocationName, IStorageLocation>()\n\n async initialize(): Promise<void> {\n // Called by interface contract; actual setup done via configure()\n }\n\n /**\n * Configure all storage locations.\n * ONE single SQLite database (camstack.db) is used for ALL structured storage.\n * File-based locations use the filesystem at their configured path.\n */\n async configure(config: { locations: Record<string, string> }): Promise<void> {\n // Find the 'data' location path for the single DB (fall back to first structured location)\n const dataPath = config.locations['data'] ?? config.locations['config'] ?? Object.values(config.locations)[0]\n if (!dataPath) throw new Error('No data path configured for SQLite storage')\n\n // Create single database\n fs.mkdirSync(dataPath, { recursive: true })\n const dbPath = path.join(dataPath, 'camstack.db')\n this.mainDb = new Database(dbPath)\n this.mainDb.pragma('journal_mode = WAL')\n this.sharedStructured = new SqliteStructuredStorage(this.mainDb)\n\n // Configure each location\n for (const [name, dirPath] of Object.entries(config.locations)) {\n const locationName = name as StorageLocationName\n const locationType = LOCATION_TYPES[name] ?? 'files'\n\n fs.mkdirSync(dirPath, { recursive: true })\n\n const location: IStorageLocation = {}\n\n // All structured storage shares the single DB\n if (locationType === 'structured' || locationType === 'both') {\n location.structured = this.sharedStructured\n }\n\n if (locationType === 'files' || locationType === 'both') {\n location.files = new FileSystemStorage(dirPath)\n }\n\n this.locations.set(locationName, location)\n }\n }\n\n getLocation(name: StorageLocationName): IStorageLocation {\n const location = this.locations.get(name)\n if (!location) {\n throw new Error(`Storage location \"${name}\" not found`)\n }\n return location\n }\n\n async shutdown(): Promise<void> {\n if (this.mainDb) {\n this.mainDb.close()\n this.mainDb = null\n this.sharedStructured = null\n }\n this.locations.clear()\n }\n\n async export(_locationName: StorageLocationName): Promise<Buffer> {\n throw new Error('Export not yet implemented')\n }\n\n async import(_locationName: StorageLocationName, _data: Buffer): Promise<void> {\n throw new Error('Import not yet implemented')\n }\n}\n","import type {\n ICamstackAddon,\n AddonManifest,\n AddonContext,\n IConfigurable,\n ConfigUISchema,\n CapabilityProviderMap,\n} from '@camstack/types'\nimport { SqliteStorageProvider } from './sqlite-storage.provider'\n\nexport class SqliteStorageAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'sqlite-storage',\n name: 'SQLite Storage',\n version: '1.0.0',\n capabilities: ['storage'],\n }\n\n private provider: SqliteStorageProvider | null = null\n\n async initialize(context: AddonContext): Promise<void> {\n const storageConfig = {\n locations: { ...context.locationPaths } as Record<string, string>,\n }\n this.provider = new SqliteStorageProvider()\n await this.provider.configure(storageConfig)\n context.logger.info('SQLite storage initialized')\n }\n\n async shutdown(): Promise<void> {\n await this.provider?.shutdown()\n }\n\n getProvider(): SqliteStorageProvider {\n if (!this.provider) throw new Error('SQLite storage not initialized')\n return this.provider\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'storage' && this.provider) {\n return this.provider as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [],\n }\n }\n\n getConfig(): Record<string, unknown> {\n return {}\n }\n\n async onConfigChange(_config: Record<string, unknown>): Promise<void> {\n // No configurable fields\n }\n}\n","import Database from 'better-sqlite3'\nimport { CORE_TABLE_DDL } from './sql-schema.js'\nimport { RUNTIME_DEFAULTS } from '@camstack/kernel'\n\n/**\n * Thin wrapper over better-sqlite3 that manages the four settings tables:\n * system_settings, addon_settings, provider_settings, device_settings.\n *\n * All values are stored as JSON text and deserialized on read.\n */\nexport class SettingsStore {\n private readonly db: Database.Database\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath)\n this.db.pragma('journal_mode = WAL')\n this.db.pragma('foreign_keys = ON')\n this.initTables()\n }\n\n // ---------------------------------------------------------------------------\n // System settings\n // ---------------------------------------------------------------------------\n\n getSystem(key: string): unknown {\n const row = this.db\n .prepare<[string], { value: string }>('SELECT value FROM system_settings WHERE key = ?')\n .get(key)\n if (row === undefined) return undefined\n return JSON.parse(row.value)\n }\n\n setSystem(key: string, value: unknown): void {\n this.db\n .prepare(\n `INSERT INTO system_settings (key, value, updated_at) VALUES (?, json(?), unixepoch())\n ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,\n )\n .run(key, JSON.stringify(value))\n }\n\n getAllSystem(): Record<string, unknown> {\n const rows = this.db\n .prepare<[], { key: string; value: string }>('SELECT key, value FROM system_settings')\n .all()\n return Object.fromEntries(rows.map(r => [r.key, JSON.parse(r.value)]))\n }\n\n // ---------------------------------------------------------------------------\n // Addon settings\n // ---------------------------------------------------------------------------\n\n getAddon(addonId: string, key: string): unknown {\n const row = this.db\n .prepare<[string, string], { value: string }>(\n 'SELECT value FROM addon_settings WHERE addon_id = ? AND key = ?',\n )\n .get(addonId, key)\n if (row === undefined) return undefined\n return JSON.parse(row.value)\n }\n\n setAddon(addonId: string, key: string, value: unknown): void {\n this.db\n .prepare(\n `INSERT INTO addon_settings (addon_id, key, value, updated_at) VALUES (?, ?, json(?), unixepoch())\n ON CONFLICT(addon_id, key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,\n )\n .run(addonId, key, JSON.stringify(value))\n }\n\n getAllAddon(addonId: string): Record<string, unknown> {\n const rows = this.db\n .prepare<[string], { key: string; value: string }>(\n 'SELECT key, value FROM addon_settings WHERE addon_id = ?',\n )\n .all(addonId)\n return Object.fromEntries(rows.map(r => [r.key, JSON.parse(r.value)]))\n }\n\n /** Bulk-replace all keys for an addon (within a transaction). */\n setAllAddon(addonId: string, config: Record<string, unknown>): void {\n const deleteStmt = this.db.prepare('DELETE FROM addon_settings WHERE addon_id = ?')\n const insertStmt = this.db.prepare(\n `INSERT INTO addon_settings (addon_id, key, value, updated_at) VALUES (?, ?, json(?), unixepoch())`,\n )\n this.db.transaction(() => {\n deleteStmt.run(addonId)\n for (const [key, value] of Object.entries(config)) {\n insertStmt.run(addonId, key, JSON.stringify(value))\n }\n })()\n }\n\n // ---------------------------------------------------------------------------\n // Provider settings\n // ---------------------------------------------------------------------------\n\n getProvider(providerId: string, key: string): unknown {\n const row = this.db\n .prepare<[string, string], { value: string }>(\n 'SELECT value FROM provider_settings WHERE provider_id = ? AND key = ?',\n )\n .get(providerId, key)\n if (row === undefined) return undefined\n return JSON.parse(row.value)\n }\n\n setProvider(providerId: string, key: string, value: unknown): void {\n this.db\n .prepare(\n `INSERT INTO provider_settings (provider_id, key, value, updated_at) VALUES (?, ?, json(?), unixepoch())\n ON CONFLICT(provider_id, key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,\n )\n .run(providerId, key, JSON.stringify(value))\n }\n\n getAllProvider(providerId: string): Record<string, unknown> {\n const rows = this.db\n .prepare<[string], { key: string; value: string }>(\n 'SELECT key, value FROM provider_settings WHERE provider_id = ?',\n )\n .all(providerId)\n return Object.fromEntries(rows.map(r => [r.key, JSON.parse(r.value)]))\n }\n\n // ---------------------------------------------------------------------------\n // Device settings\n // ---------------------------------------------------------------------------\n\n getDevice(deviceId: string, key: string): unknown {\n const row = this.db\n .prepare<[string, string], { value: string }>(\n 'SELECT value FROM device_settings WHERE device_id = ? AND key = ?',\n )\n .get(deviceId, key)\n if (row === undefined) return undefined\n return JSON.parse(row.value)\n }\n\n setDevice(deviceId: string, key: string, value: unknown): void {\n this.db\n .prepare(\n `INSERT INTO device_settings (device_id, key, value, updated_at) VALUES (?, ?, json(?), unixepoch())\n ON CONFLICT(device_id, key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,\n )\n .run(deviceId, key, JSON.stringify(value))\n }\n\n getAllDevice(deviceId: string): Record<string, unknown> {\n const rows = this.db\n .prepare<[string], { key: string; value: string }>(\n 'SELECT key, value FROM device_settings WHERE device_id = ?',\n )\n .all(deviceId)\n return Object.fromEntries(rows.map(r => [r.key, JSON.parse(r.value)]))\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /** Close the SQLite connection (call on shutdown). */\n close(): void {\n this.db.close()\n }\n\n /** Check if system_settings is empty (used for first-boot seeding). */\n isSystemSettingsEmpty(): boolean {\n const row = this.db\n .prepare<[], { cnt: number }>('SELECT COUNT(*) AS cnt FROM system_settings')\n .get()\n return (row?.cnt ?? 0) === 0\n }\n\n /** Seed system_settings with RUNTIME_DEFAULTS (only on first boot). */\n seedDefaults(): void {\n const insert = this.db.prepare(\n `INSERT OR IGNORE INTO system_settings (key, value, updated_at) VALUES (?, json(?), unixepoch())`,\n )\n this.db.transaction(() => {\n for (const [key, value] of Object.entries(RUNTIME_DEFAULTS)) {\n insert.run(key, JSON.stringify(value))\n }\n })()\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private initTables(): void {\n this.db.transaction(() => {\n for (const stmt of CORE_TABLE_DDL) {\n this.db.prepare(stmt).run()\n }\n })()\n }\n}\n","/** Core table DDL statements -- executed on first boot */\nexport const CORE_TABLE_DDL: readonly string[] = [\n // Settings tables\n `CREATE TABLE IF NOT EXISTS system_settings (\n key TEXT PRIMARY KEY,\n value JSON NOT NULL,\n updated_at INTEGER NOT NULL DEFAULT (unixepoch())\n )`,\n `CREATE TABLE IF NOT EXISTS addon_settings (\n addon_id TEXT NOT NULL,\n key TEXT NOT NULL,\n value JSON NOT NULL,\n updated_at INTEGER NOT NULL DEFAULT (unixepoch()),\n PRIMARY KEY (addon_id, key)\n )`,\n `CREATE TABLE IF NOT EXISTS provider_settings (\n provider_id TEXT NOT NULL,\n key TEXT NOT NULL,\n value JSON NOT NULL,\n updated_at INTEGER NOT NULL DEFAULT (unixepoch()),\n PRIMARY KEY (provider_id, key)\n )`,\n `CREATE TABLE IF NOT EXISTS device_settings (\n device_id TEXT NOT NULL,\n key TEXT NOT NULL,\n value JSON NOT NULL,\n updated_at INTEGER NOT NULL DEFAULT (unixepoch()),\n PRIMARY KEY (device_id, key)\n )`,\n\n // Detection events\n `CREATE TABLE IF NOT EXISTS detection_events (\n id TEXT PRIMARY KEY,\n timestamp INTEGER NOT NULL,\n device_id TEXT NOT NULL,\n class_name TEXT NOT NULL,\n score REAL NOT NULL,\n severity TEXT NOT NULL,\n track_id TEXT,\n zones JSON,\n recognition JSON,\n media_files JSON,\n data JSON\n )`,\n `CREATE INDEX IF NOT EXISTS idx_det_device_ts ON detection_events(device_id, timestamp)`,\n `CREATE INDEX IF NOT EXISTS idx_det_class_ts ON detection_events(class_name, timestamp)`,\n\n // Audio levels\n `CREATE TABLE IF NOT EXISTS audio_levels (\n id TEXT PRIMARY KEY,\n timestamp INTEGER NOT NULL,\n device_id TEXT NOT NULL,\n dbfs REAL NOT NULL,\n rms REAL NOT NULL,\n state TEXT NOT NULL\n )`,\n `CREATE INDEX IF NOT EXISTS idx_audio_device_ts ON audio_levels(device_id, timestamp)`,\n\n // Track trails\n `CREATE TABLE IF NOT EXISTS track_trails (\n track_id TEXT PRIMARY KEY,\n device_id TEXT NOT NULL,\n class_name TEXT NOT NULL,\n first_seen INTEGER NOT NULL,\n last_seen INTEGER NOT NULL,\n positions JSON NOT NULL,\n snapshots JSON,\n total_distance REAL,\n zones_visited JSON\n )`,\n `CREATE INDEX IF NOT EXISTS idx_trails_device_ts ON track_trails(device_id, first_seen)`,\n]\n\n/** Addon table schema declaration */\nexport interface AddonTableSchema {\n readonly name: string\n readonly columns: ReadonlyArray<{\n readonly name: string\n readonly type: 'TEXT' | 'INTEGER' | 'REAL' | 'JSON'\n readonly primaryKey?: boolean\n readonly notNull?: boolean\n }>\n readonly indexes?: ReadonlyArray<{\n readonly name: string\n readonly columns: readonly string[]\n readonly unique?: boolean\n }>\n}\n\n/** Generate CREATE TABLE DDL from addon schema */\nexport function addonTableToDdl(schema: AddonTableSchema): string[] {\n const pks = schema.columns.filter(c => c.primaryKey).map(c => c.name)\n const colDefs = schema.columns.map(c => {\n const parts = [c.name, c.type]\n if (c.notNull) parts.push('NOT NULL')\n return parts.join(' ')\n })\n\n let ddl = `CREATE TABLE IF NOT EXISTS ${schema.name} (\\n ${colDefs.join(',\\n ')}`\n if (pks.length > 0) {\n ddl += `,\\n PRIMARY KEY (${pks.join(', ')})`\n }\n ddl += '\\n)'\n\n const stmts = [ddl]\n for (const idx of schema.indexes ?? []) {\n const unique = idx.unique ? 'UNIQUE ' : ''\n stmts.push(`CREATE ${unique}INDEX IF NOT EXISTS ${idx.name} ON ${schema.name}(${idx.columns.join(', ')})`)\n }\n return stmts\n}\n","import * as winston from 'winston'\nimport DailyRotateFile from 'winston-daily-rotate-file'\nimport * as path from 'node:path'\nimport type { ILogDestination, LogEntry, LogFilter } from '@camstack/types'\n\ninterface WinstonConfig {\n readonly level: string\n readonly retentionDays: number\n /** Resolved absolute path to the logs directory (replaces the old dataPath field). */\n readonly logsDir: string\n}\n\nfunction formatScope(scope: readonly string[]): string {\n if (scope.length === 0) return ''\n const [first, ...rest] = scope\n const restFormatted = rest.map((s) => `[${s}]`).join('')\n return `(${first})${restFormatted}`\n}\n\nexport class WinstonDestination implements ILogDestination {\n private logger: winston.Logger | null = null\n\n async initialize(config?: WinstonConfig): Promise<void> {\n const {\n level = 'info',\n retentionDays = 30,\n logsDir = path.join('camstack-data', 'logs'),\n } = config ?? {}\n\n const consoleFormat = winston.format.combine(\n winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),\n winston.format.colorize(),\n winston.format.printf(({ timestamp, level: lvl, message, scope }) => {\n const scopeStr = scope ? ` ${scope}` : ''\n return `${timestamp} [${lvl}]${scopeStr} - ${message}`\n }),\n )\n\n const fileFormat = winston.format.combine(\n winston.format.timestamp(),\n winston.format.json(),\n )\n\n this.logger = winston.createLogger({\n level,\n transports: [\n new winston.transports.Console({\n format: consoleFormat,\n }),\n new DailyRotateFile({\n dirname: logsDir,\n filename: 'camstack-%DATE%.log',\n datePattern: 'YYYY-MM-DD',\n maxFiles: `${retentionDays}d`,\n format: fileFormat,\n }),\n ],\n })\n }\n\n write(entry: LogEntry): void {\n if (!this.logger) return\n\n const scope = formatScope(entry.scope)\n const meta = entry.meta ?? {}\n\n this.logger.log({\n level: entry.level,\n message: entry.message,\n scope,\n timestamp: entry.timestamp.toISOString(),\n ...meta,\n })\n }\n\n async query(_filter: LogFilter): Promise<readonly LogEntry[]> {\n // File-based log querying is not implemented; use structured storage for log queries\n return []\n }\n\n async shutdown(): Promise<void> {\n if (!this.logger) return\n\n await new Promise<void>((resolve) => {\n this.logger!.on('finish', resolve)\n this.logger!.end()\n })\n this.logger = null\n }\n}\n","import type {\n ICamstackAddon,\n AddonManifest,\n AddonContext,\n IConfigurable,\n ConfigUISchema,\n CapabilityProviderMap,\n} from '@camstack/types'\nimport { WinstonDestination } from './winston-destination'\n\nexport class WinstonLoggingAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'winston-logging',\n name: 'Winston Logging',\n version: '1.0.0',\n capabilities: ['log-destination'],\n }\n\n private destination: WinstonDestination | null = null\n private currentConfig = {\n level: 'info',\n retentionDays: 30,\n }\n\n async initialize(context: AddonContext): Promise<void> {\n this.currentConfig = {\n level: (context.addonConfig.level as string) ?? this.currentConfig.level,\n retentionDays: (context.addonConfig.retentionDays as number) ?? this.currentConfig.retentionDays,\n }\n const logsDir = context.locationPaths.logs\n this.destination = new WinstonDestination()\n await this.destination.initialize({ ...this.currentConfig, logsDir })\n context.logger.info('Winston logging initialized')\n }\n\n async shutdown(): Promise<void> {\n await this.destination?.shutdown()\n }\n\n getDestination(): WinstonDestination {\n if (!this.destination) throw new Error('Winston not initialized')\n return this.destination\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'log-destination' && this.destination) {\n return this.destination as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'winston-retention',\n title: 'Log Retention',\n description: 'How long Winston keeps rotated log files on disk.',\n columns: 1,\n fields: [\n {\n type: 'number',\n key: 'retentionDays',\n label: 'Retention (days)',\n description: 'Number of days to keep rotated log files before deletion',\n min: 1,\n max: 365,\n step: 1,\n unit: 'days',\n },\n ],\n },\n ],\n }\n }\n\n getConfig(): Record<string, unknown> {\n return { ...this.currentConfig }\n }\n\n async onConfigChange(config: Record<string, unknown>): Promise<void> {\n this.currentConfig = {\n level: (config.level as string) ?? this.currentConfig.level,\n retentionDays: (config.retentionDays as number) ?? this.currentConfig.retentionDays,\n }\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { IScopedLogger, IEventBus, IStorageLocation, BackupManifest } from '@camstack/types'\n\nexport type { BackupManifest }\n\nexport interface BackupConfig {\n readonly backupDir: string\n readonly retentionCount: number\n}\n\nexport class LocalBackupService {\n private manifests: BackupManifest[] = []\n\n constructor(\n private readonly config: BackupConfig,\n private readonly logger: IScopedLogger,\n private readonly eventBus: IEventBus,\n private readonly storage: IStorageLocation,\n ) {}\n\n /** Create a backup of specified locations */\n async backup(options?: {\n locations?: string[]\n label?: string\n }): Promise<BackupManifest> {\n const id = randomUUID()\n const timestamp = Date.now()\n const locations = options?.locations ?? ['config', 'events', 'logs']\n\n this.logger.info(`Starting backup ${id} (${locations.join(', ')})`)\n\n const manifest: BackupManifest = {\n id,\n timestamp,\n label: options?.label,\n locations,\n sizeMB: 0,\n path: `${this.config.backupDir}/${id}`,\n }\n\n const updated = [...this.manifests, manifest]\n this.manifests = updated\n\n await this.pruneOldBackups()\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'local-backup' },\n category: 'backup.completed',\n data: { backupId: id, locations: [...locations], sizeMB: manifest.sizeMB },\n })\n\n this.logger.info(`Backup ${id} completed`)\n return manifest\n }\n\n /** Restore from a backup */\n async restore(backupId: string): Promise<void> {\n const manifest = this.manifests.find((m) => m.id === backupId)\n if (!manifest) throw new Error(`Backup ${backupId} not found`)\n\n this.logger.info(`Restoring from backup ${backupId}`)\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'local-backup' },\n category: 'backup.restored',\n data: { backupId },\n })\n }\n\n /** List all backups sorted by timestamp descending */\n list(): readonly BackupManifest[] {\n return [...this.manifests].sort((a, b) => b.timestamp - a.timestamp)\n }\n\n /** Delete a specific backup */\n async delete(backupId: string): Promise<void> {\n this.manifests = this.manifests.filter((m) => m.id !== backupId)\n }\n\n private async pruneOldBackups(): Promise<void> {\n const sorted = [...this.manifests].sort((a, b) => a.timestamp - b.timestamp)\n\n while (sorted.length > this.config.retentionCount) {\n const oldest = sorted.shift()\n if (oldest) {\n this.logger.info(`Pruning old backup ${oldest.id}`)\n this.manifests = this.manifests.filter((m) => m.id !== oldest.id)\n }\n }\n }\n}\n","import * as path from 'node:path'\nimport type {\n ICamstackAddon, AddonManifest, AddonContext,\n IConfigurable, ConfigUISchema, CapabilityProviderMap,\n} from '@camstack/types'\nimport { LocalBackupService } from './local-backup'\nimport type { BackupConfig } from './local-backup'\n\nexport class LocalBackupAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'local-backup',\n name: 'Local Backup',\n version: '1.0.0',\n capabilities: ['backup'],\n }\n\n private service: LocalBackupService | null = null\n private currentConfig = {\n retentionCount: 7,\n }\n\n async initialize(context: AddonContext): Promise<void> {\n this.currentConfig = {\n retentionCount: (context.addonConfig.retentionCount as number) ?? this.currentConfig.retentionCount,\n }\n const backupConfig: BackupConfig = {\n backupDir: path.join(context.locationPaths.data, 'backups'),\n retentionCount: this.currentConfig.retentionCount,\n }\n this.service = new LocalBackupService(\n backupConfig,\n context.logger,\n context.eventBus,\n context.storage,\n )\n context.logger.info('Local Backup initialized')\n }\n\n async shutdown(): Promise<void> {\n this.service = null\n }\n\n getService(): LocalBackupService {\n if (!this.service) throw new Error('Local Backup not initialized')\n return this.service\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'backup' as string && this.service) {\n return this.service as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'backup-retention',\n title: 'Backup Retention',\n description: 'How many local backup snapshots to keep on disk.',\n columns: 1,\n fields: [\n {\n type: 'number',\n key: 'retentionCount',\n label: 'Retention Count',\n description: 'Number of backup snapshots to keep before deleting the oldest',\n min: 1,\n max: 100,\n step: 1,\n },\n ],\n },\n ],\n }\n }\n\n getConfig(): Record<string, unknown> {\n return { ...this.currentConfig }\n }\n\n async onConfigChange(config: Record<string, unknown>): Promise<void> {\n this.currentConfig = {\n retentionCount: (config.retentionCount as number) ?? this.currentConfig.retentionCount,\n }\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { IScopedLogger, IEventBus } from '@camstack/types'\n\nexport type ElementState = 'stopped' | 'starting' | 'running' | 'stopping' | 'error' | 'disabled'\n\nexport interface ElementStatus {\n state: ElementState\n error?: string\n startedAt?: number\n stoppedAt?: number\n restartCount: number\n uptime: number\n}\n\nconst VALID_TRANSITIONS: Readonly<Record<ElementState, readonly ElementState[]>> = {\n stopped: ['starting', 'disabled'],\n starting: ['running', 'error', 'stopping'],\n running: ['stopping', 'error'],\n stopping: ['stopped', 'error'],\n error: ['starting', 'stopped', 'disabled'],\n disabled: ['stopped'],\n}\n\nexport class LifecycleStateMachine {\n private _state: ElementState = 'stopped'\n private _error?: string\n private _startedAt?: number\n private _stoppedAt?: number\n private _restartCount = 0\n private _hasStartedOnce = false\n\n constructor(\n private readonly elementId: string,\n private readonly elementType: 'provider' | 'device' | 'addon' | 'process',\n private readonly eventBus: IEventBus,\n private readonly logger: IScopedLogger,\n ) {}\n\n get state(): ElementState {\n return this._state\n }\n\n getStatus(): ElementStatus {\n return {\n state: this._state,\n error: this._error,\n startedAt: this._startedAt,\n stoppedAt: this._stoppedAt,\n restartCount: this._restartCount,\n uptime:\n this._state === 'running' && this._startedAt\n ? Date.now() - this._startedAt\n : 0,\n }\n }\n\n transition(to: ElementState, error?: string): boolean {\n const from = this._state\n\n if (!this.isValidTransition(from, to)) {\n this.logger.warn(`Invalid state transition: ${from} → ${to}`)\n return false\n }\n\n this._state = to\n this._error = error\n\n if (to === 'running') {\n if (this._hasStartedOnce) {\n this._restartCount++\n }\n this._hasStartedOnce = true\n this._startedAt = Date.now()\n this._stoppedAt = undefined\n }\n\n if (to === 'stopped' || to === 'error' || to === 'disabled') {\n this._stoppedAt = Date.now()\n }\n\n this.logger.info(`State: ${from} → ${to}${error ? ` (${error})` : ''}`)\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: this.elementType, id: this.elementId },\n category: `${this.elementType}.state.${to}`,\n data: { from, to, error, elementId: this.elementId },\n })\n\n return true\n }\n\n incrementRestartCount(): void {\n this._restartCount++\n }\n\n private isValidTransition(from: ElementState, to: ElementState): boolean {\n return VALID_TRANSITIONS[from]?.includes(to) ?? false\n }\n}\n","import type { FeatureManifest, FeatureFlag } from '@camstack/types'\n\nexport type { FeatureManifest, FeatureFlag }\n\nexport type FeatureConfigReader = {\n readonly features: FeatureManifest\n}\n\nexport class FeatureManager {\n constructor(private readonly configReader: FeatureConfigReader) {}\n\n isEnabled(flag: FeatureFlag): boolean {\n return this.configReader.features[flag]\n }\n\n getManifest(): FeatureManifest {\n return { ...this.configReader.features }\n }\n}\n","import type {\n EventSource,\n SystemEvent,\n EventFilter,\n IEventBus,\n} from '@camstack/types'\n\nexport type { EventSource, SystemEvent, EventFilter }\n\ninterface Subscriber {\n readonly filter: EventFilter\n readonly callback: (event: SystemEvent) => void\n}\n\nclass EventRingBuffer {\n private readonly buffer: Array<SystemEvent | undefined>\n private head = 0\n private count = 0\n\n constructor(private readonly capacity: number) {\n this.buffer = new Array(capacity)\n }\n\n push(event: SystemEvent): void {\n this.buffer[this.head] = event\n this.head = (this.head + 1) % this.capacity\n if (this.count < this.capacity) {\n this.count++\n }\n }\n\n getAll(): readonly SystemEvent[] {\n const result: SystemEvent[] = []\n for (let i = 0; i < this.count; i++) {\n const index = (this.head - 1 - i + this.capacity) % this.capacity\n result.push(this.buffer[index]!)\n }\n return result\n }\n\n query(filter?: EventFilter, limit?: number): readonly SystemEvent[] {\n let result = [...this.getAll()]\n\n if (filter) {\n result = result.filter((event) => matchesFilter(event, filter))\n }\n\n if (limit !== undefined && limit > 0) {\n return result.slice(0, limit)\n }\n\n return result\n }\n}\n\nfunction matchesCategory(eventCategory: string, filterCategory: string): boolean {\n if (filterCategory.endsWith('.*')) {\n const prefix = filterCategory.slice(0, -2)\n return eventCategory.startsWith(prefix + '.') || eventCategory === prefix\n }\n return eventCategory === filterCategory\n}\n\nfunction matchesFilter(event: SystemEvent, filter: EventFilter): boolean {\n if (filter.category && !matchesCategory(event.category, filter.category)) {\n return false\n }\n\n if (filter.source) {\n if (event.source.type !== filter.source.type || event.source.id !== filter.source.id) {\n return false\n }\n }\n\n if (filter.since && event.timestamp < filter.since) {\n return false\n }\n\n return true\n}\n\nexport class SystemEventBus implements IEventBus {\n private readonly ringBuffer: EventRingBuffer\n private readonly subscribers: Subscriber[] = []\n\n constructor(bufferSize: number = 10000) {\n this.ringBuffer = new EventRingBuffer(bufferSize)\n }\n\n emit(event: SystemEvent): void {\n this.ringBuffer.push(event)\n\n for (const subscriber of this.subscribers) {\n if (matchesFilter(event, subscriber.filter)) {\n queueMicrotask(() => {\n try {\n subscriber.callback(event)\n } catch (err) {\n console.error(`[EventBus] Subscriber error for ${event.category}:`, err)\n }\n })\n }\n }\n }\n\n subscribe(filter: EventFilter, handler: (event: SystemEvent) => void): () => void {\n const subscriber: Subscriber = { filter, callback: handler }\n this.subscribers.push(subscriber)\n\n return () => {\n const index = this.subscribers.indexOf(subscriber)\n if (index !== -1) {\n this.subscribers.splice(index, 1)\n }\n }\n }\n\n getRecent(filter?: EventFilter, limit?: number): readonly SystemEvent[] {\n return this.ringBuffer.query(filter, limit)\n }\n}\n","import type { LogLevel, LogEntry, LogFilter } from '@camstack/types'\n\nexport type { LogLevel, LogEntry, LogFilter }\n\nexport class LogRingBuffer {\n private readonly buffer: Array<LogEntry | undefined>\n private head = 0\n private count = 0\n\n constructor(private readonly capacity: number = 10000) {\n this.buffer = new Array(capacity)\n }\n\n push(entry: LogEntry): void {\n this.buffer[this.head] = entry\n this.head = (this.head + 1) % this.capacity\n if (this.count < this.capacity) {\n this.count++\n }\n }\n\n getAll(): LogEntry[] {\n const result: LogEntry[] = []\n\n for (let i = 0; i < this.count; i++) {\n const index = (this.head - 1 - i + this.capacity) % this.capacity\n result.push(this.buffer[index]!)\n }\n\n return result\n }\n\n query(filter: LogFilter): LogEntry[] {\n const all = this.getAll()\n let result = all\n\n if (filter.scope && filter.scope.length > 0) {\n result = result.filter((entry) => {\n for (let i = 0; i < filter.scope!.length; i++) {\n if (entry.scope[i] !== filter.scope![i]) return false\n }\n return true\n })\n }\n\n if (filter.level) {\n result = result.filter((entry) => entry.level === filter.level)\n }\n\n if (filter.since) {\n result = result.filter((entry) => entry.timestamp >= filter.since!)\n }\n\n if (filter.until) {\n result = result.filter((entry) => entry.timestamp <= filter.until!)\n }\n\n if (filter.limit !== undefined && filter.limit > 0) {\n result = result.slice(0, filter.limit)\n }\n\n return result\n }\n}\n","import type { IScopedLogger } from '@camstack/types'\nimport type { LogEntry, LogLevel } from './log-ring-buffer.js'\n\nexport type { IScopedLogger }\n\nexport class ScopedLogger implements IScopedLogger {\n constructor(\n private readonly scope: string[],\n private readonly writeFn: (entry: LogEntry) => void,\n ) {}\n\n debug(message: string, meta?: Record<string, unknown>): void {\n this.write('debug', message, meta)\n }\n\n info(message: string, meta?: Record<string, unknown>): void {\n this.write('info', message, meta)\n }\n\n warn(message: string, meta?: Record<string, unknown>): void {\n this.write('warn', message, meta)\n }\n\n error(message: string, meta?: Record<string, unknown>): void {\n this.write('error', message, meta)\n }\n\n child(childScope: string): IScopedLogger {\n return new ScopedLogger([...this.scope, childScope], this.writeFn)\n }\n\n private write(level: LogLevel, message: string, meta?: Record<string, unknown>): void {\n const entry: LogEntry = {\n timestamp: new Date(),\n level,\n scope: this.scope,\n message,\n ...(meta !== undefined ? { meta } : {}),\n }\n this.writeFn(entry)\n }\n}\n","import { LogRingBuffer, type LogEntry, type LogFilter } from './log-ring-buffer.js'\nimport { ScopedLogger, type IScopedLogger } from './scoped-logger.js'\n\nexport interface ILogDestination {\n initialize(): Promise<void>\n shutdown(): Promise<void>\n write(entry: LogEntry): void\n query?(filter: LogFilter): Promise<readonly LogEntry[]>\n}\n\nexport class LogManager {\n private readonly ringBuffer: LogRingBuffer\n private readonly destinations: ILogDestination[] = []\n private readonly subscribers = new Map<string, { filter: Partial<LogFilter>; callback: (entry: LogEntry) => void }>()\n\n constructor(bufferSize: number = 10000) {\n this.ringBuffer = new LogRingBuffer(bufferSize)\n }\n\n createLogger(scope: string): IScopedLogger {\n return new ScopedLogger([scope], (entry: LogEntry) => {\n this.ringBuffer.push(entry)\n for (const dest of this.destinations) {\n dest.write(entry)\n }\n // Notify real-time subscribers\n for (const [, sub] of this.subscribers) {\n if (this.matchesFilter(entry, sub.filter)) {\n try { sub.callback(entry) } catch { /* subscriber error — ignore */ }\n }\n }\n })\n }\n\n /** Subscribe to live logs matching a filter. Returns an unsubscribe function. */\n subscribe(filter: Partial<LogFilter>, callback: (entry: LogEntry) => void): () => void {\n const id = Math.random().toString(36).slice(2)\n this.subscribers.set(id, { filter, callback })\n return () => { this.subscribers.delete(id) }\n }\n\n private matchesFilter(entry: LogEntry, filter: Partial<LogFilter>): boolean {\n if (filter.scope && filter.scope.length > 0) {\n const entryScope = entry.scope?.[0] ?? ''\n if (!filter.scope.some(s => entryScope === s || entryScope.startsWith(s))) return false\n }\n if (filter.level) {\n const levels: string[] = ['debug', 'info', 'warn', 'error']\n const minIdx = levels.indexOf(filter.level)\n const entryIdx = levels.indexOf(entry.level)\n if (entryIdx < minIdx) return false\n }\n return true\n }\n\n addDestination(dest: ILogDestination): void {\n this.destinations.push(dest)\n }\n\n removeDestination(dest: ILogDestination): void {\n const index = this.destinations.indexOf(dest)\n if (index !== -1) {\n this.destinations.splice(index, 1)\n }\n }\n\n query(filter: LogFilter): LogEntry[] {\n return this.ringBuffer.query(filter)\n }\n}\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { StorageLocationManager, StorageLocationName } from './storage-location-manager.js'\nimport type {\n IStorageProvider as INewStorageProvider,\n ISettingsBackend,\n} from '@camstack/types'\n\n// Legacy interfaces — still used by consumers during migration\nexport interface IStorageProvider {\n initialize(): Promise<void>\n shutdown(): Promise<void>\n getLocation(name: StorageLocationName): IStorageLocation\n export?(locationName: StorageLocationName): Promise<Buffer>\n import?(locationName: StorageLocationName, data: Buffer): Promise<void>\n}\n\nexport interface QueryFilter {\n where?: Record<string, unknown>\n whereIn?: Record<string, unknown[]>\n whereBetween?: Record<string, [unknown, unknown]>\n orderBy?: { field: string; direction: 'asc' | 'desc' }\n limit?: number\n offset?: number\n}\n\nexport interface StorageRecord {\n collection: string\n id: string\n data: Record<string, unknown>\n}\n\nexport interface IStructuredStorage {\n query(collection: string, filter?: QueryFilter): Promise<readonly StorageRecord[]>\n insert(record: StorageRecord): Promise<StorageRecord>\n update(collection: string, id: string, data: Record<string, unknown>): Promise<StorageRecord>\n delete(collection: string, id: string): Promise<void>\n count(collection: string, filter?: QueryFilter): Promise<number>\n}\n\nexport interface IFileStorage {\n readFile(path: string): Promise<Buffer>\n writeFile(path: string, data: Buffer): Promise<void>\n deleteFile(path: string): Promise<void>\n listFiles(prefix?: string): Promise<readonly string[]>\n getFileUrl(path: string): Promise<string>\n exists(path: string): Promise<boolean>\n}\n\nexport interface IStorageLocation {\n structured?: IStructuredStorage\n files?: IFileStorage\n}\n\n/**\n * StorageManager — bridge between legacy code (getLocation/getLocationPath)\n * and the new capability-based storage system.\n *\n * Legacy consumers call getLocation('addon', namespace) to get structured + file storage.\n * This manager builds the response from:\n * - SettingsBackend (for structured queries) — provided by sqlite-settings addon\n * - LocationManager (for file paths) — set during Phase 2 boot\n */\nexport class StorageManager {\n private legacyProvider: IStorageProvider | null = null\n private locationManager: StorageLocationManager | null = null\n private newStorageProvider: INewStorageProvider | null = null\n private settingsBackend: ISettingsBackend | null = null\n\n /** @deprecated Set by legacy capability consumer — use setNewStorageProvider instead */\n setProvider(provider: IStorageProvider | INewStorageProvider): void {\n // Check if it's the new provider (has 'supportedLocations') or legacy (has 'getLocation')\n if ('getLocation' in provider && typeof (provider as any).getLocation === 'function') {\n this.legacyProvider = provider as IStorageProvider\n } else {\n this.newStorageProvider = provider as INewStorageProvider\n }\n }\n\n setNewStorageProvider(provider: INewStorageProvider): void {\n this.newStorageProvider = provider\n }\n\n setSettingsBackend(backend: ISettingsBackend): void {\n this.settingsBackend = backend\n }\n\n getProvider(): IStorageProvider {\n if (this.legacyProvider) return this.legacyProvider\n if (!this.newStorageProvider && !this.settingsBackend && !this.locationManager) {\n throw new Error('No storage provider configured')\n }\n // Return a shim that wraps new providers\n return this.createLegacyShim()\n }\n\n setLocationManager(manager: StorageLocationManager): void {\n this.locationManager = manager\n }\n\n getLocationManager(): StorageLocationManager {\n if (!this.locationManager) {\n throw new Error('StorageLocationManager not initialized')\n }\n return this.locationManager\n }\n\n async initializeLocations(dataPath: string): Promise<void> {\n const { StorageLocationManager } = await import('./storage-location-manager.js')\n const manager = new StorageLocationManager(dataPath)\n await manager.initializeDefaults()\n this.locationManager = manager\n }\n\n getLocationPath(name: StorageLocationName): string {\n return this.getLocationManager().getBackend(name).basePath\n }\n\n /**\n * Get a storage location with optional namespace scoping.\n * Builds IStorageLocation from settingsBackend (structured) + locationManager (files).\n */\n getLocation(name: StorageLocationName | string, namespace?: string): IStorageLocation {\n if (!this.legacyProvider && !this.newStorageProvider && !this.settingsBackend && !this.locationManager) {\n throw new Error('No storage provider configured')\n }\n // Try legacy provider first\n if (this.legacyProvider) {\n try {\n const LEGACY_MAP: Record<string, string> = { config: 'data', events: 'data', addon: 'data' }\n const mappedName = (LEGACY_MAP[name] ?? name) as StorageLocationName\n const location = this.legacyProvider.getLocation(mappedName)\n return namespace ? this.createNamespacedLocation(location, namespace) : location\n } catch {\n // Fall through to new approach\n }\n }\n\n // Build from new providers\n const location: IStorageLocation = {}\n\n // Structured storage from settingsBackend\n if (this.settingsBackend) {\n const backend = this.settingsBackend\n location.structured = {\n async query(collection: string, filter?: QueryFilter) {\n const results = await backend.query(collection as any, filter)\n return results.map(r => ({ collection, id: r.id, data: r.data }))\n },\n async insert(record: StorageRecord) {\n const id = record.id || (await import('node:crypto')).randomUUID()\n await backend.insert(record.collection as any, { id, data: record.data })\n return { ...record, id }\n },\n async update(collection: string, id: string, data: Record<string, unknown>) {\n await backend.update(collection as any, id, data)\n return { collection, id, data }\n },\n async delete(collection: string, id: string) {\n await backend.delete(collection as any, id)\n },\n async count(collection: string, filter?: QueryFilter) {\n return backend.count(collection as any, filter)\n },\n }\n }\n\n // File storage from locationManager\n if (this.locationManager) {\n const LEGACY_MAP: Record<string, string> = { config: 'data', events: 'data', addon: 'data' }\n const mappedName = (LEGACY_MAP[name] ?? name) as StorageLocationName\n try {\n const basePath = this.locationManager.getBackend(mappedName).basePath\n location.files = {\n async readFile(p: string) { return fs.promises.readFile(path.join(basePath, p)) },\n async writeFile(p: string, data: Buffer) {\n const full = path.join(basePath, p)\n await fs.promises.mkdir(path.dirname(full), { recursive: true })\n await fs.promises.writeFile(full, data)\n },\n async deleteFile(p: string) { await fs.promises.rm(path.join(basePath, p), { force: true }) },\n async listFiles(prefix?: string) {\n const dir = prefix ? path.join(basePath, prefix) : basePath\n try { return (await fs.promises.readdir(dir)).map(f => prefix ? `${prefix}/${f}` : f) } catch { return [] }\n },\n async getFileUrl(p: string) { return path.join(basePath, p) },\n async exists(p: string) { try { await fs.promises.access(path.join(basePath, p)); return true } catch { return false } },\n }\n } catch {\n // Location not available\n }\n }\n\n return namespace ? this.createNamespacedLocation(location, namespace) : location\n }\n\n private createLegacyShim(): IStorageProvider {\n const self = this\n return {\n async initialize() {},\n async shutdown() {},\n getLocation(name: StorageLocationName) { return self.getLocation(name) },\n }\n }\n\n private createNamespacedLocation(location: IStorageLocation, namespace: string): IStorageLocation {\n const prefix = namespace.endsWith('/') ? namespace : `${namespace}/`\n\n return {\n structured: location.structured ? {\n async query(collection: string, filter?: QueryFilter) {\n return location.structured!.query(`${prefix}${collection}`, filter)\n },\n async insert(record: StorageRecord) {\n return location.structured!.insert({ ...record, collection: `${prefix}${record.collection}` })\n },\n async update(collection: string, id: string, data: Record<string, unknown>) {\n return location.structured!.update(`${prefix}${collection}`, id, data)\n },\n async delete(collection: string, id: string) {\n return location.structured!.delete(`${prefix}${collection}`, id)\n },\n async count(collection: string, filter?: QueryFilter) {\n return location.structured!.count(`${prefix}${collection}`, filter)\n },\n } : undefined,\n\n files: location.files ? {\n async readFile(p: string) { return location.files!.readFile(`${prefix}${p}`) },\n async writeFile(p: string, data: Buffer) { return location.files!.writeFile(`${prefix}${p}`, data) },\n async deleteFile(p: string) { return location.files!.deleteFile(`${prefix}${p}`) },\n async listFiles(filePrefix?: string) { return location.files!.listFiles(`${prefix}${filePrefix ?? ''}`) },\n async getFileUrl(p: string) { return location.files!.getFileUrl(`${prefix}${p}`) },\n async exists(p: string) { return location.files!.exists(`${prefix}${p}`) },\n } : undefined,\n }\n }\n}\n","import * as jwt from 'jsonwebtoken'\nimport * as bcrypt from 'bcryptjs'\nimport * as crypto from 'node:crypto'\nimport type { ScopedToken, UserRole, TokenPayload } from '@camstack/types'\nimport type { ScopedTokenManager } from './scoped-token-manager.js'\n\nexport type { UserRole, TokenPayload }\n\nexport type AuthConfigReader = {\n get<T>(path: string): T\n update(section: string, data: Record<string, unknown>): void\n}\n\nexport class AuthManager {\n private readonly jwtSecret: string\n private scopedTokenManager: ScopedTokenManager | null = null\n\n constructor(private readonly config: AuthConfigReader) {\n const configured = this.config.get<string>('auth.jwtSecret')\n if (configured) {\n this.jwtSecret = configured\n } else {\n const secret = crypto.randomBytes(32).toString('hex')\n // Persist directly into config.yaml so it survives restarts\n this.config.update('auth', { jwtSecret: secret })\n console.log('[AuthManager] Generated JWT secret and saved to config.yaml (auth.jwtSecret)')\n this.jwtSecret = secret\n }\n }\n\n signToken(payload: Omit<TokenPayload, 'iat' | 'exp'>): string {\n return jwt.sign({ ...payload }, this.jwtSecret, { expiresIn: '24h' })\n }\n\n verifyToken(token: string): TokenPayload {\n return jwt.verify(token, this.jwtSecret) as TokenPayload\n }\n\n async hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, 10)\n }\n\n async comparePassword(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash)\n }\n\n generateApiKey(): { token: string; hash: string; prefix: string } {\n const token = crypto.randomBytes(32).toString('hex')\n const hash = crypto.createHash('sha256').update(token).digest('hex')\n const prefix = token.slice(0, 8)\n return { token, hash, prefix }\n }\n\n validateApiKey(token: string, storedHash: string): boolean {\n const hash = crypto.createHash('sha256').update(token).digest('hex')\n return hash === storedHash\n }\n\n /**\n * Create a service token for agent/worker authentication.\n * Used when forking workers or when agents register.\n */\n createServiceToken(opts: {\n readonly agentId: string\n readonly role?: string\n readonly expiresIn?: string\n }): string {\n const payload: Record<string, unknown> = {\n userId: opts.agentId,\n username: opts.agentId,\n role: opts.role ?? 'agent',\n type: 'service',\n agentId: opts.agentId,\n allowedProviders: '*',\n allowedDevices: {},\n }\n const expiresIn = (opts.expiresIn ?? '24h') as jwt.SignOptions['expiresIn']\n return jwt.sign(payload as object, this.jwtSecret, { expiresIn })\n }\n\n /**\n * Set the scoped token manager for the auth chain.\n */\n setScopedTokenManager(manager: ScopedTokenManager): void {\n this.scopedTokenManager = manager\n }\n\n /**\n * Validate a scoped token string.\n * Returns the token record if valid, null otherwise.\n */\n async validateScopedToken(rawToken: string): Promise<ScopedToken | null> {\n if (!this.scopedTokenManager) {\n return null\n }\n return this.scopedTokenManager.validate(rawToken)\n }\n\n /**\n * Check whether a scoped token grants access to a given addon/route/capability.\n */\n matchesScopedTokenScope(\n token: ScopedToken,\n addonId?: string,\n routePath?: string,\n capability?: string,\n ): boolean {\n if (!this.scopedTokenManager) {\n return false\n }\n return this.scopedTokenManager.matchesScope(token, addonId, routePath, capability)\n }\n}\n","import * as crypto from 'node:crypto'\nimport type { AuthManager, UserRole } from './auth-manager.js'\nimport type { IStructuredStorage, StorageRecord, QueryFilter } from '../storage/storage-manager.js'\n\nexport interface ApiKeyRecord {\n id: string\n label: string\n role: UserRole\n allowedProviders: string[] | '*'\n allowedDevices: Record<string, string[] | '*'>\n tokenHash: string\n tokenPrefix: string\n createdAt: number\n lastUsedAt?: number\n}\n\ninterface CreateApiKeyInput {\n label: string\n role: UserRole\n allowedProviders?: string[] | '*'\n allowedDevices?: Record<string, string[] | '*'>\n}\n\nconst API_KEYS_COLLECTION = 'api_keys'\n\nexport type ApiKeyStorageAccess = {\n getStructuredStorage(): IStructuredStorage\n}\n\nexport class ApiKeyManager {\n constructor(\n private readonly storageAccess: ApiKeyStorageAccess,\n private readonly auth: AuthManager,\n ) {}\n\n private get structured(): IStructuredStorage {\n return this.storageAccess.getStructuredStorage()\n }\n\n async create(input: CreateApiKeyInput): Promise<{ record: ApiKeyRecord; token: string }> {\n const { token, hash, prefix } = this.auth.generateApiKey()\n const now = Date.now()\n\n const record: ApiKeyRecord = {\n id: crypto.randomUUID(),\n label: input.label,\n role: input.role,\n allowedProviders: input.allowedProviders ?? '*',\n allowedDevices: input.allowedDevices ?? {},\n tokenHash: hash,\n tokenPrefix: prefix,\n createdAt: now,\n }\n\n await this.structured.insert({\n collection: API_KEYS_COLLECTION,\n id: record.id,\n data: record as unknown as Record<string, unknown>,\n })\n\n return { record, token }\n }\n\n async validateToken(token: string): Promise<ApiKeyRecord | null> {\n const allKeys = await this.structured.query(API_KEYS_COLLECTION)\n\n for (const entry of allKeys) {\n const record = entry.data as unknown as ApiKeyRecord\n if (this.auth.validateApiKey(token, record.tokenHash)) {\n const updatedData: Record<string, unknown> = {\n ...record,\n lastUsedAt: Date.now(),\n }\n await this.structured.update(API_KEYS_COLLECTION, record.id, updatedData)\n return { ...record, lastUsedAt: updatedData.lastUsedAt as number }\n }\n }\n\n return null\n }\n\n async listAll(): Promise<Omit<ApiKeyRecord, 'tokenHash'>[]> {\n const results = await this.structured.query(API_KEYS_COLLECTION)\n return results.map((r) => {\n const { tokenHash, ...rest } = r.data as unknown as ApiKeyRecord\n return rest\n })\n }\n\n async revoke(id: string): Promise<void> {\n await this.structured.delete(API_KEYS_COLLECTION, id)\n }\n\n async findById(id: string): Promise<ApiKeyRecord | null> {\n const results = await this.structured.query(API_KEYS_COLLECTION, {\n where: { id },\n })\n\n if (results.length === 0) {\n return null\n }\n\n return results[0]!.data as unknown as ApiKeyRecord\n }\n}\n","import * as crypto from 'node:crypto'\nimport type { AuthManager, UserRole } from './auth-manager.js'\nimport type { IStructuredStorage } from '../storage/storage-manager.js'\nimport type { UserRecord } from '@camstack/types'\n\nexport type { UserRecord }\n\ninterface CreateUserInput {\n username: string\n password: string\n role: UserRole\n allowedProviders?: string[] | '*'\n allowedDevices?: Record<string, string[] | '*'>\n}\n\ntype UpdatableUserFields = Partial<Pick<UserRecord, 'role' | 'allowedProviders' | 'allowedDevices'>>\n\nconst USERS_COLLECTION = 'users'\n\nexport type UserStorageAccess = {\n getStructuredStorage(): IStructuredStorage\n}\n\nexport type UserConfigReader = {\n get<T>(path: string): T\n}\n\nexport class UserManager {\n constructor(\n private readonly storageAccess: UserStorageAccess,\n private readonly auth: AuthManager,\n private readonly config: UserConfigReader,\n ) {}\n\n private get structured(): IStructuredStorage {\n return this.storageAccess.getStructuredStorage()\n }\n\n async create(input: CreateUserInput): Promise<UserRecord> {\n const existing = await this.findByUsername(input.username)\n if (existing) {\n throw new Error(`User with username \"${input.username}\" already exists`)\n }\n\n const passwordHash = await this.auth.hashPassword(input.password)\n const now = Date.now()\n const record: UserRecord = {\n id: crypto.randomUUID(),\n username: input.username,\n passwordHash,\n role: input.role,\n allowedProviders: input.allowedProviders ?? '*',\n allowedDevices: input.allowedDevices ?? {},\n createdAt: now,\n updatedAt: now,\n }\n\n await this.structured.insert({\n collection: USERS_COLLECTION,\n id: record.id,\n data: record as unknown as Record<string, unknown>,\n })\n\n return record\n }\n\n async findByUsername(username: string): Promise<UserRecord | null> {\n const results = await this.structured.query(USERS_COLLECTION, {\n where: { username },\n })\n\n if (results.length === 0) {\n return null\n }\n\n return results[0]!.data as unknown as UserRecord\n }\n\n async findById(id: string): Promise<UserRecord | null> {\n const results = await this.structured.query(USERS_COLLECTION, {\n where: { id },\n })\n\n if (results.length === 0) {\n return null\n }\n\n return results[0]!.data as unknown as UserRecord\n }\n\n async validateCredentials(username: string, password: string): Promise<UserRecord | null> {\n const user = await this.findByUsername(username)\n if (!user) {\n return null\n }\n\n const valid = await this.auth.comparePassword(password, user.passwordHash)\n return valid ? user : null\n }\n\n async listAll(): Promise<Omit<UserRecord, 'passwordHash'>[]> {\n const results = await this.structured.query(USERS_COLLECTION)\n return results.map((r) => {\n const { passwordHash, ...rest } = r.data as unknown as UserRecord\n return rest\n })\n }\n\n async update(id: string, data: UpdatableUserFields): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new Error(`User with id \"${id}\" not found`)\n }\n\n const updatedData: Record<string, unknown> = {\n ...existing,\n ...data,\n updatedAt: Date.now(),\n }\n\n await this.structured.update(USERS_COLLECTION, id, updatedData)\n }\n\n async delete(id: string): Promise<void> {\n await this.structured.delete(USERS_COLLECTION, id)\n }\n\n async resetPassword(id: string, newPassword: string): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new Error(`User with id \"${id}\" not found`)\n }\n\n const passwordHash = await this.auth.hashPassword(newPassword)\n const updatedData: Record<string, unknown> = {\n ...existing,\n passwordHash,\n updatedAt: Date.now(),\n }\n\n await this.structured.update(USERS_COLLECTION, id, updatedData)\n }\n\n async ensureAdminExists(): Promise<void> {\n const adminUsername = this.config.get<string>('auth.adminUsername')\n const adminPassword = this.config.get<string>('auth.adminPassword')\n\n if (!adminUsername || !adminPassword) {\n return\n }\n\n const existing = await this.findByUsername(adminUsername)\n if (existing) {\n return\n }\n\n await this.create({\n username: adminUsername,\n password: adminPassword,\n role: 'super_admin',\n allowedProviders: '*',\n allowedDevices: {},\n })\n }\n}\n","import * as crypto from 'node:crypto'\nimport type { ScopedToken, TokenScope } from '@camstack/types'\nimport type { IStructuredStorage, StorageRecord } from '../storage/storage-manager.js'\n\nconst TOKENS_COLLECTION = 'scoped_tokens'\nconst TOKEN_PREFIX = 'cst_'\n\n/**\n * Manages scoped API tokens with restricted addon/route/capability access.\n * Framework-agnostic — dependencies injected via constructor.\n */\nexport class ScopedTokenManager {\n constructor(private readonly storage: IStructuredStorage) {}\n\n /**\n * Create a new scoped token. Returns the raw token string (shown once)\n * and the stored record (with hash, not the raw token).\n */\n async create(\n userId: string,\n name: string,\n scopes: TokenScope[],\n expiresAt?: number,\n ): Promise<{ token: string; record: ScopedToken }> {\n const rawHex = crypto.randomBytes(32).toString('hex')\n const rawToken = `${TOKEN_PREFIX}${rawHex}`\n const tokenHash = crypto.createHash('sha256').update(rawToken).digest('hex')\n const tokenPrefix = rawToken.slice(0, 12)\n\n const record: ScopedToken = {\n id: crypto.randomUUID(),\n userId,\n name,\n tokenHash,\n tokenPrefix,\n scopes: scopes.map((s) => ({ ...s })),\n expiresAt,\n lastUsedAt: undefined,\n createdAt: Date.now(),\n }\n\n await this.storage.insert({\n collection: TOKENS_COLLECTION,\n id: record.id,\n data: record as unknown as Record<string, unknown>,\n })\n\n return { token: rawToken, record }\n }\n\n /**\n * Validate a raw token string. Returns the token record if valid, null otherwise.\n */\n async validate(rawToken: string): Promise<ScopedToken | null> {\n if (!rawToken.startsWith(TOKEN_PREFIX)) {\n return null\n }\n\n const tokenHash = crypto.createHash('sha256').update(rawToken).digest('hex')\n const results = await this.storage.query(TOKENS_COLLECTION, {\n where: { tokenHash },\n })\n\n if (results.length === 0) {\n return null\n }\n\n const record = results[0]!.data as unknown as ScopedToken\n if (record.expiresAt !== undefined && record.expiresAt !== null && Date.now() > record.expiresAt) {\n return null\n }\n\n // Update last used timestamp (fire and forget)\n this.updateLastUsed(record.id).catch(() => {})\n\n return record\n }\n\n /**\n * Check whether a token's scopes grant access to the given addon, route, or capability.\n */\n matchesScope(\n token: ScopedToken,\n addonId?: string,\n routePath?: string,\n capability?: string,\n ): boolean {\n for (const scope of token.scopes) {\n switch (scope.type) {\n case 'addon':\n if (addonId && scope.target === addonId) return true\n break\n case 'route-prefix':\n if (routePath && routePath.startsWith(scope.target)) return true\n break\n case 'capability':\n if (capability && scope.target === capability) return true\n break\n }\n }\n return false\n }\n\n /**\n * Revoke a token by ID.\n */\n async revoke(tokenId: string): Promise<void> {\n await this.storage.delete(TOKENS_COLLECTION, tokenId)\n }\n\n /**\n * List all tokens for a user (without exposing the raw token).\n */\n async listForUser(userId: string): Promise<ScopedToken[]> {\n const results = await this.storage.query(TOKENS_COLLECTION, {\n where: { userId },\n })\n return results.map((r: StorageRecord) => r.data as unknown as ScopedToken)\n }\n\n /**\n * Update the lastUsedAt timestamp for a token.\n */\n async updateLastUsed(tokenId: string): Promise<void> {\n const results = await this.storage.query(TOKENS_COLLECTION, {\n where: { id: tokenId },\n })\n if (results.length === 0) return\n\n const existing = results[0]!.data as unknown as ScopedToken\n await this.storage.update(TOKENS_COLLECTION, tokenId, {\n ...existing,\n lastUsedAt: Date.now(),\n } as unknown as Record<string, unknown>)\n }\n}\n","import type { INotificationOutput, Notification } from '@camstack/types'\nimport type { IScopedLogger } from '../logging/scoped-logger.js'\nimport type { CapabilityRegistry } from '@camstack/kernel'\n\n/**\n * Central notification service that routes notifications to configured outputs.\n * Framework-agnostic — dependencies injected via constructor.\n *\n * Outputs are resolved from the CapabilityRegistry's 'notification-output'\n * collection on each call (proxy pattern). Falls back to a local map\n * when no registry is provided (backward compat).\n */\nexport class NotificationService {\n private readonly localOutputs = new Map<string, INotificationOutput>()\n private readonly routing = new Map<string, string[]>()\n private readonly rateLimits = new Map<string, number>()\n private readonly lastSent = new Map<string, number>()\n private registry: CapabilityRegistry | null = null\n\n constructor(private readonly logger: IScopedLogger) {}\n\n /** Set the registry for live output lookup. Called once during boot. */\n setRegistry(registry: CapabilityRegistry): void {\n this.registry = registry\n }\n\n /** Resolve all outputs — prefers registry, falls back to local map */\n private get outputs(): ReadonlyMap<string, INotificationOutput> {\n if (this.registry) {\n const collection = this.registry.getCollection<INotificationOutput>('notification-output')\n const map = new Map<string, INotificationOutput>()\n for (const output of collection) {\n map.set(output.id, output)\n }\n return map\n }\n return this.localOutputs\n }\n\n /** @deprecated Use registry-based resolution. Kept for backward compat only. */\n addOutput(output: INotificationOutput): void {\n this.localOutputs.set(output.id, output)\n this.logger.info(`Notification output added: ${output.name} (${output.id})`)\n }\n\n /** @deprecated Use registry-based resolution. Kept for backward compat only. */\n removeOutput(id: string): void {\n this.localOutputs.delete(id)\n this.logger.info(`Notification output removed: ${id}`)\n }\n\n setRouting(category: string, outputIds: string[]): void {\n this.routing.set(category, [...outputIds])\n }\n\n setRateLimit(category: string, minIntervalMs: number): void {\n this.rateLimits.set(category, minIntervalMs)\n }\n\n async notify(notification: Notification): Promise<void> {\n const { category, deviceId } = notification\n\n // Rate limit check\n const rateLimitKey = deviceId ? `${category}:${deviceId}` : category\n const minInterval = this.rateLimits.get(category) ?? 0\n if (minInterval > 0) {\n const last = this.lastSent.get(rateLimitKey) ?? 0\n if (notification.timestamp - last < minInterval) {\n this.logger.debug(`Rate limited: ${rateLimitKey}`)\n return\n }\n }\n\n // Determine target outputs\n const targetIds = this.routing.get(category) ?? this.routing.get('*') ?? []\n if (targetIds.length === 0) {\n this.logger.debug(`No routing configured for category \"${category}\"`)\n return\n }\n\n const currentOutputs = this.outputs\n\n // Update last-sent timestamp\n this.lastSent.set(rateLimitKey, notification.timestamp)\n\n // Send to all targets in parallel with error isolation\n await Promise.allSettled(\n targetIds\n .map((id) => currentOutputs.get(id))\n .filter((output): output is INotificationOutput => output !== undefined)\n .map(async (output) => {\n try {\n await output.send(notification)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n this.logger.error(`Notification output \"${output.id}\" failed: ${msg}`)\n }\n }),\n )\n\n return undefined\n }\n\n getOutputs(): ReadonlyArray<{ id: string; name: string; icon: string }> {\n return Array.from(this.outputs.values()).map(({ id, name, icon }) => ({ id, name, icon }))\n }\n\n getRouting(): ReadonlyMap<string, string[]> {\n return this.routing\n }\n\n getOutput(id: string): INotificationOutput | undefined {\n return this.outputs.get(id)\n }\n}\n","import type { Toast } from '@camstack/types'\n\nexport type Unsubscribe = () => void\n\ninterface ListenerEntry {\n readonly userId: string\n readonly callback: (toast: Toast) => void\n}\n\n/**\n * Service for broadcasting toast notifications to connected UI clients.\n * Framework-agnostic — integrates with tRPC subscriptions via subscribe().\n */\nexport class ToastService {\n private readonly listeners = new Map<string, ListenerEntry>()\n\n /**\n * Subscribe to toast events for a specific user.\n * Returns an unsubscribe function.\n */\n subscribe(connectionId: string, userId: string, callback: (toast: Toast) => void): Unsubscribe {\n this.listeners.set(connectionId, { userId, callback })\n return () => {\n this.listeners.delete(connectionId)\n }\n }\n\n /**\n * Broadcast a toast to all connected clients.\n */\n broadcast(toast: Toast): void {\n for (const entry of this.listeners.values()) {\n entry.callback(toast)\n }\n }\n\n /**\n * Send a toast to a specific user's connections only.\n */\n sendToUser(userId: string, toast: Toast): void {\n for (const entry of this.listeners.values()) {\n if (entry.userId === userId) {\n entry.callback(toast)\n }\n }\n }\n}\n","import type { IAddonHttpRoute, IAddonRouteProvider } from '@camstack/types'\n\ninterface RouteMatch {\n readonly route: IAddonHttpRoute\n readonly addonId: string\n readonly params: Record<string, string>\n}\n\ninterface RegisteredRoute {\n readonly addonId: string\n readonly route: IAddonHttpRoute\n /** Full path including /addon/{addonId}/ prefix */\n readonly fullPath: string\n}\n\n/**\n * Registry for dynamic HTTP routes registered by addons.\n * Framework-agnostic — the server HTTP layer queries this registry to dispatch requests.\n */\nexport class AddonRouteRegistry {\n private readonly routes = new Map<string, RegisteredRoute[]>()\n\n /**\n * Register all routes from an addon's route provider.\n */\n registerRoutes(addonId: string, provider: IAddonRouteProvider): void {\n const addonRoutes = provider.getRoutes()\n const registered: RegisteredRoute[] = addonRoutes.map((route) => {\n const normalizedPath = route.path.startsWith('/') ? route.path : `/${route.path}`\n return {\n addonId,\n route,\n fullPath: `/addon/${addonId}${normalizedPath}`,\n }\n })\n this.routes.set(addonId, registered)\n }\n\n /**\n * Unregister all routes for an addon.\n */\n unregisterRoutes(addonId: string): void {\n this.routes.delete(addonId)\n }\n\n /**\n * Match an incoming request method + path to a registered route.\n * Supports simple path parameters (e.g., /items/:id).\n */\n matchRoute(method: string, path: string): RouteMatch | null {\n const normalizedMethod = method.toUpperCase()\n\n for (const registeredRoutes of this.routes.values()) {\n for (const entry of registeredRoutes) {\n if (entry.route.method !== normalizedMethod) continue\n\n const params = matchPath(entry.fullPath, path)\n if (params !== null) {\n return {\n route: entry.route,\n addonId: entry.addonId,\n params,\n }\n }\n }\n }\n\n return null\n }\n\n /**\n * List all registered routes across all addons.\n */\n listRoutes(): ReadonlyArray<{ addonId: string; method: string; path: string; access: string; description?: string }> {\n const result: Array<{ addonId: string; method: string; path: string; access: string; description?: string }> = []\n for (const registeredRoutes of this.routes.values()) {\n for (const entry of registeredRoutes) {\n result.push({\n addonId: entry.addonId,\n method: entry.route.method,\n path: entry.fullPath,\n access: entry.route.access,\n description: entry.route.description,\n })\n }\n }\n return result\n }\n}\n\n/**\n * Match a route pattern against an actual path.\n * Supports :param segments (e.g., /addon/:addonId/items/:id).\n * Returns extracted params or null if no match.\n */\nfunction matchPath(pattern: string, path: string): Record<string, string> | null {\n const patternParts = pattern.split('/').filter(Boolean)\n const pathParts = path.split('/').filter(Boolean)\n\n if (patternParts.length !== pathParts.length) {\n return null\n }\n\n const params: Record<string, string> = {}\n\n for (let i = 0; i < patternParts.length; i++) {\n const patternPart = patternParts[i]!\n const pathPart = pathParts[i]!\n\n if (patternPart.startsWith(':')) {\n params[patternPart.slice(1)] = pathPart\n } else if (patternPart !== pathPart) {\n return null\n }\n }\n\n return params\n}\n","import { randomUUID } from 'node:crypto'\nimport type { IScopedLogger, IEventBus, LoggerFactory } from '@camstack/types'\n\nexport interface IRegisteredDevice {\n readonly id: string\n readonly name: string\n readonly providerId: string\n readonly capabilities: readonly string[]\n}\n\nexport class DeviceRegistry<T extends IRegisteredDevice = IRegisteredDevice> {\n private readonly devices = new Map<string, T>()\n private readonly logger: IScopedLogger\n\n constructor(\n private readonly eventBus: IEventBus,\n loggingService: LoggerFactory,\n ) {\n this.logger = loggingService.createLogger('device-registry')\n }\n\n registerDevice(device: T): void {\n this.devices.set(device.id, device)\n this.logger.info(`Device registered: ${device.id} (${device.name})`)\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'core', id: 'device-registry' },\n category: 'device.registered',\n data: { deviceId: device.id, name: device.name, providerId: device.providerId },\n })\n }\n\n unregisterDevice(id: string): void {\n const device = this.devices.get(id)\n if (!device) {\n return\n }\n\n this.devices.delete(id)\n this.logger.info(`Device unregistered: ${id}`)\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'core', id: 'device-registry' },\n category: 'device.unregistered',\n data: { deviceId: id },\n })\n }\n\n getDevice(id: string): T | null {\n return this.devices.get(id) ?? null\n }\n\n listDevices(): T[] {\n return Array.from(this.devices.values())\n }\n\n getDevicesByProvider(providerId: string): T[] {\n return Array.from(this.devices.values()).filter(\n (device) => device.providerId === providerId,\n )\n }\n\n getDevicesWithCapability(cap: string): T[] {\n return Array.from(this.devices.values()).filter((device) =>\n device.capabilities.includes(cap),\n )\n }\n\n registerProviderDevices(providerId: string, devices: readonly T[]): void {\n for (const device of devices) {\n this.registerDevice(device)\n }\n this.logger.info(`Bulk registered ${devices.length} devices for provider ${providerId}`)\n }\n\n unregisterProviderDevices(providerId: string): void {\n const providerDevices = this.getDevicesByProvider(providerId)\n for (const device of providerDevices) {\n this.unregisterDevice(device.id)\n }\n this.logger.info(`Bulk unregistered ${providerDevices.length} devices for provider ${providerId}`)\n }\n}\n","export interface IDeviceCapability {\n kind: string\n}\n\nexport interface CapabilityBinding {\n source: 'native' | 'addon' | 'disabled'\n addonId?: string\n config?: Record<string, unknown>\n}\n\nexport interface IResolvableDevice {\n readonly id: string\n readonly capabilities: string[]\n getCapability<T extends IDeviceCapability>(cap: string): T | null\n}\n\nexport interface IAddonRegistryAccess {\n getAddon(addonId: string): unknown | null\n}\n\nexport class CapabilityResolver {\n private readonly bindings = new Map<\n string,\n Partial<Record<string, CapabilityBinding>>\n >()\n\n constructor(\n private readonly addonRegistry: IAddonRegistryAccess,\n ) {}\n\n resolve<T extends IDeviceCapability>(\n device: IResolvableDevice,\n cap: string,\n ): T | null {\n const deviceBindings = this.bindings.get(device.id)\n const binding = deviceBindings?.[cap]\n\n if (binding) {\n if (binding.source === 'disabled') {\n return null\n }\n\n if (binding.source === 'addon' && binding.addonId) {\n const addon = this.addonRegistry.getAddon(binding.addonId)\n if (addon && typeof (addon as any).getCapabilityForDevice === 'function') {\n return (\n (addon as any).getCapabilityForDevice(device, cap, binding.config) ?? null\n )\n }\n return null\n }\n }\n\n // native or no explicit binding -- delegate to device\n return device.getCapability<T>(cap)\n }\n\n setBinding(\n deviceId: string,\n cap: string,\n binding: CapabilityBinding,\n ): void {\n const existing = this.bindings.get(deviceId) ?? {}\n this.bindings.set(deviceId, { ...existing, [cap]: binding })\n }\n\n removeBinding(deviceId: string, cap: string): void {\n const existing = this.bindings.get(deviceId)\n if (!existing) {\n return\n }\n const updated = { ...existing }\n delete updated[cap]\n this.bindings.set(deviceId, updated)\n }\n\n getBindings(\n deviceId: string,\n ): Partial<Record<string, CapabilityBinding>> {\n return this.bindings.get(deviceId) ?? {}\n }\n\n getEffectiveCapabilities(device: IResolvableDevice): string[] {\n const deviceBindings = this.bindings.get(device.id) ?? {}\n\n const result: string[] = []\n\n // Include native capabilities that are not disabled\n for (const cap of device.capabilities) {\n const binding = deviceBindings[cap]\n if (!binding || binding.source !== 'disabled') {\n result.push(cap)\n }\n }\n\n // Include addon-bound capabilities not already in the native list\n for (const [cap, binding] of Object.entries(deviceBindings)) {\n if (\n binding && binding.source === 'addon' &&\n !device.capabilities.includes(cap)\n ) {\n result.push(cap)\n }\n }\n\n return result\n }\n}\n","import { X509Certificate } from 'node:crypto'\nimport { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport * as os from 'node:os'\n\nconst execFileAsync = promisify(execFile)\n\nexport interface TlsCertPair {\n readonly cert: Buffer\n readonly key: Buffer\n}\n\nexport interface EnsureTlsResult {\n readonly certPath: string\n readonly keyPath: string\n readonly generated: boolean\n}\n\nexport interface CertOptions {\n /** Common Name for the cert (default: 'camstack.local') */\n readonly commonName?: string\n /** Validity in days (default: 825 — max for browsers) */\n readonly validDays?: number\n /** Additional SANs (DNS names or IPs) */\n readonly extraSans?: readonly string[]\n}\n\n/**\n * Ensure a self-signed TLS certificate exists in the given directory.\n * Generates one if missing. Returns paths to cert and key files.\n */\nexport async function ensureTlsCert(\n dataDir: string,\n options?: CertOptions,\n): Promise<EnsureTlsResult> {\n const tlsDir = join(dataDir, 'tls')\n const certPath = join(tlsDir, 'camstack.crt')\n const keyPath = join(tlsDir, 'camstack.key')\n\n // Already exists — reuse\n if (existsSync(certPath) && existsSync(keyPath)) {\n try {\n const certPem = readFileSync(certPath)\n const x509 = new X509Certificate(certPem)\n const validTo = new Date(x509.validTo)\n if (validTo > new Date()) {\n return { certPath, keyPath, generated: false }\n }\n // Expired — regenerate below\n } catch {\n // Corrupted — regenerate below\n }\n }\n\n mkdirSync(tlsDir, { recursive: true })\n\n const cn = options?.commonName ?? 'camstack.local'\n const validDays = options?.validDays ?? 825\n\n // Collect SANs: localhost, 127.0.0.1, all local IPs, hostname\n const sanDns = new Set<string>(['localhost', cn, os.hostname()])\n const sanIps = new Set<string>(['127.0.0.1', '::1'])\n\n // Add all local network IPs\n const interfaces = os.networkInterfaces()\n for (const addrs of Object.values(interfaces)) {\n if (!addrs) continue\n for (const addr of addrs) {\n if (!addr.internal) {\n sanIps.add(addr.address)\n }\n }\n }\n\n // Add extra SANs\n for (const san of options?.extraSans ?? []) {\n if (san.match(/^\\d+\\.\\d+\\.\\d+\\.\\d+$/) || san.includes(':')) {\n sanIps.add(san)\n } else {\n sanDns.add(san)\n }\n }\n\n // Build SAN string for openssl\n const sanParts: string[] = []\n for (const dns of sanDns) {\n sanParts.push(`DNS:${dns}`)\n }\n for (const ip of sanIps) {\n sanParts.push(`IP:${ip}`)\n }\n const sanString = sanParts.join(',')\n\n // Generate self-signed certificate using openssl CLI\n await execFileAsync('openssl', [\n 'req', '-x509',\n '-newkey', 'rsa:2048',\n '-keyout', keyPath,\n '-out', certPath,\n '-days', String(validDays),\n '-nodes',\n '-subj', `/CN=${cn}`,\n '-addext', `subjectAltName=${sanString}`,\n ])\n\n // Set restrictive permissions on the key file\n const { chmod } = await import('node:fs/promises')\n await chmod(keyPath, 0o600)\n\n return { certPath, keyPath, generated: true }\n}\n\n/**\n * Load TLS cert+key from files. Returns Buffers suitable for Node.js TLS options.\n */\nexport function loadTlsCert(certPath: string, keyPath: string): TlsCertPair {\n return {\n cert: readFileSync(certPath),\n key: readFileSync(keyPath),\n }\n}\n","/**\n * Factory for creating tRPC clients for addons.\n *\n * Two modes:\n * - Direct caller (in-process): zero overhead, uses createCallerFactory\n * - WSS client (worker/agent): real WebSocket connection to the server\n */\n\nexport interface DirectCallerOptions {\n /** The tRPC router instance (from buildAppRouter) */\n readonly router: unknown\n /** Context for the caller (user identity, etc.) */\n readonly context: { readonly user: { readonly id: string; readonly username: string; readonly role: string } }\n}\n\nexport interface WssClientOptions {\n /** WebSocket URL (e.g., wss://localhost:4443/trpc) */\n readonly url: string\n /** Auth token for the connection */\n readonly token: string\n}\n\nexport class AddonApiFactory {\n /**\n * Build a WSS URL from host and port.\n */\n buildWssUrl(host: string, port: number): string {\n return `wss://${host}:${port}/trpc`\n }\n\n /**\n * Create a direct caller -- calls tRPC procedures directly in-process.\n * Zero network overhead. Used for in-process addons and dev mode.\n *\n * @param options.router - The tRPC router from buildAppRouter()\n * @param options.context - The auth context (service account)\n * @returns A tRPC caller that can be used as context.api\n */\n async createDirectCaller(options: DirectCallerOptions): Promise<unknown> {\n const { initTRPC } = await import('@trpc/server')\n const t = initTRPC.create()\n const callerFactory = t.createCallerFactory(options.router as never)\n return callerFactory(options.context as never)\n }\n\n /**\n * Create a WSS tRPC client -- connects to the server via WebSocket.\n * Used for forked workers and remote agents.\n *\n * @param options.url - WSS URL (e.g., wss://localhost:4443/trpc)\n * @param options.token - Bearer token for authentication\n * @returns A tRPC client that can be used as context.api\n */\n async createWssClient(options: WssClientOptions): Promise<{ readonly client: unknown; readonly close: () => void }> {\n const { createTRPCClient, createWSClient, wsLink } = await import('@trpc/client')\n\n const wsClient = createWSClient({\n url: options.url,\n connectionParams: () => ({ token: options.token }),\n })\n\n const client = createTRPCClient({\n links: [wsLink({ client: wsClient })],\n })\n\n return {\n client,\n close: () => wsClient.close(),\n }\n }\n}\n","import * as os from 'node:os'\nimport { execFileSync } from 'node:child_process'\nimport type { HardwareInfo, GpuInfo, NpuInfo, PlatformScore, PlatformCapabilities } from '@camstack/types'\n\n/**\n * Get reliable \"available\" RAM in MB, cross-platform.\n * os.freemem() is unreliable on macOS (reports ~200MB on a 36GB system).\n * Uses systeminformation when available, falls back to native commands.\n */\nasync function getAvailableRAM_MB(): Promise<number> {\n try {\n const si = await import('systeminformation')\n const mem = await si.mem()\n return Math.round(mem.available / 1024 / 1024)\n } catch {\n // Fallback: platform-specific\n const platform = os.platform()\n try {\n if (platform === 'darwin') {\n // Parse vm_stat: (free + inactive + purgeable) * pageSize\n const output = execFileSync('vm_stat', { encoding: 'utf8', timeout: 3000 })\n const pageSize = parseInt(output.match(/page size of (\\d+)/)?.[1] ?? '16384')\n const free = parseInt(output.match(/Pages free:\\s+(\\d+)/)?.[1] ?? '0')\n const inactive = parseInt(output.match(/Pages inactive:\\s+(\\d+)/)?.[1] ?? '0')\n const purgeable = parseInt(output.match(/Pages purgeable:\\s+(\\d+)/)?.[1] ?? '0')\n return Math.round((free + inactive + purgeable) * pageSize / 1024 / 1024)\n } else if (platform === 'linux') {\n // Parse /proc/meminfo: MemAvailable\n const { readFileSync } = await import('node:fs')\n const meminfo = readFileSync('/proc/meminfo', 'utf8')\n const match = meminfo.match(/MemAvailable:\\s+(\\d+)\\s+kB/)\n if (match) return Math.round(parseInt(match[1]!) / 1024)\n }\n } catch { /* ignore */ }\n // Ultimate fallback: total RAM (conservative but safe)\n return Math.round(os.totalmem() / 1024 / 1024)\n }\n}\n\nexport class PlatformScorer {\n private cached: PlatformCapabilities | null = null\n\n /** Probe hardware + runtimes and score all backend combos. Cached after first call. */\n async probe(): Promise<PlatformCapabilities> {\n if (this.cached) return this.cached\n\n const start = Date.now()\n console.log('[PlatformScorer] Probing hardware...')\n const hardware = await this.probeHardware()\n console.log(`[PlatformScorer] Hardware: ${hardware.platform}/${hardware.arch}, ${hardware.cpuModel} (${hardware.cpuCores} cores), RAM ${Math.round(hardware.totalRAM_MB / 1024)}GB`)\n if (hardware.gpu) console.log(`[PlatformScorer] GPU: ${hardware.gpu.name}`)\n if (hardware.npu) console.log(`[PlatformScorer] NPU: ${hardware.npu.type}`)\n\n console.log('[PlatformScorer] Probing Node.js backends...')\n const nodeBackends = await this.probeNodeBackends()\n console.log(`[PlatformScorer] Node backends: ${nodeBackends.map(b => b.id).join(', ')}`)\n\n console.log('[PlatformScorer] Probing Python backends...')\n const pythonInfo = this.probePythonBackends()\n if (pythonInfo.pythonPath) {\n console.log(`[PlatformScorer] Python: ${pythonInfo.pythonPath} → ${pythonInfo.backends.filter(b => b.available).map(b => b.id).join(', ') || 'no backends'}`)\n } else {\n console.log('[PlatformScorer] Python: not found')\n }\n\n const scores = this.scoreBackends(hardware, nodeBackends, pythonInfo.backends)\n const bestScore = scores.find(s => s.available) ?? scores[scores.length - 1]!\n\n const elapsed = Date.now() - start\n console.log(`[PlatformScorer] Scoring complete in ${elapsed}ms — ${scores.length} combos`)\n console.log(`[PlatformScorer] Best: ${bestScore.runtime}/${bestScore.backend} (${bestScore.format}) — ${bestScore.reason} [score: ${bestScore.score}]`)\n for (const s of scores) {\n console.log(`[PlatformScorer] ${s.available ? '✓' : '✗'} ${s.runtime}/${s.backend} (${s.format}) — score ${s.score} — ${s.reason}`)\n }\n\n this.cached = {\n hardware,\n scores,\n bestScore,\n pythonPath: pythonInfo.pythonPath,\n }\n return this.cached\n }\n\n async probeHardware(): Promise<HardwareInfo> {\n const platform = os.platform() as HardwareInfo['platform']\n const arch = os.arch() as HardwareInfo['arch']\n const cpus = os.cpus()\n const cpuModel = cpus[0]?.model ?? 'unknown'\n const cpuCores = cpus.length\n const totalRAM_MB = Math.round(os.totalmem() / 1024 / 1024)\n const availableRAM_MB = await getAvailableRAM_MB()\n console.log(`[PlatformScorer] RAM: total=${totalRAM_MB}MB, available=${availableRAM_MB}MB (via systeminformation)`)\n\n let gpu: GpuInfo | null = null\n let npu: NpuInfo | null = null\n\n // macOS Apple Silicon\n if (platform === 'darwin' && arch === 'arm64') {\n gpu = { type: 'apple', name: 'Apple Silicon GPU' }\n npu = { type: 'apple-ane' }\n }\n\n // Linux NVIDIA\n if (platform === 'linux') {\n try {\n const output = execFileSync('nvidia-smi', ['--query-gpu=name,memory.total', '--format=csv,noheader'], {\n encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'],\n }).trim()\n if (output) {\n const [name, mem] = output.split(',').map(s => s.trim())\n gpu = {\n type: 'nvidia',\n name: name ?? 'NVIDIA GPU',\n memoryMB: parseInt(mem ?? '0'),\n }\n }\n } catch { /* no NVIDIA GPU */ }\n }\n\n return { platform, arch, cpuModel, cpuCores, totalRAM_MB, availableRAM_MB, gpu, npu }\n }\n\n private async probeNodeBackends(): Promise<Array<{ id: string; available: boolean }>> {\n const backends: Array<{ id: string; available: boolean }> = [\n { id: 'cpu', available: true },\n ]\n\n try {\n const ort = await import('onnxruntime-node') as any\n const providers: string[] = ort.InferenceSession?.getAvailableProviders?.() ?? []\n for (const p of providers) {\n const n = p.toLowerCase().replace('executionprovider', '')\n if (n === 'coreml') backends.push({ id: 'coreml', available: true })\n else if (n === 'cuda') backends.push({ id: 'cuda', available: true })\n else if (n === 'tensorrt') backends.push({ id: 'tensorrt', available: true })\n }\n } catch { /* onnxruntime not available */ }\n\n // macOS always has CoreML potential\n if (os.platform() === 'darwin' && !backends.some(b => b.id === 'coreml')) {\n backends.push({ id: 'coreml', available: true })\n }\n\n return backends\n }\n\n private probePythonBackends(): { pythonPath: string | null; backends: Array<{ id: string; format: string; available: boolean }> } {\n let pythonPath: string | null = null\n for (const cmd of ['python3', 'python']) {\n try {\n execFileSync(cmd, ['--version'], { timeout: 5000, stdio: 'pipe' })\n pythonPath = cmd\n break\n } catch { /* not found */ }\n }\n\n if (!pythonPath) return { pythonPath: null, backends: [] }\n\n const checks: Array<[string, string, string]> = [\n // [pythonModule, backendId, modelFormat]\n ['coremltools', 'coreml', 'coreml'],\n ['openvino.runtime', 'openvino', 'openvino'],\n ['torch', 'pytorch', 'onnx'],\n ['onnxruntime', 'onnx-py', 'onnx'],\n ]\n\n const backends: Array<{ id: string; format: string; available: boolean }> = []\n for (const [mod, id, format] of checks) {\n let available = false\n const probeStart = Date.now()\n try {\n execFileSync(pythonPath, ['-c', `import ${mod}`], { timeout: 30000, stdio: 'ignore' })\n available = true\n } catch { /* module not installed */ }\n const probeMs = Date.now() - probeStart\n console.log(`[PlatformScorer] Python ${mod}: ${available ? '✓' : '✗'} (${probeMs}ms)`)\n\n // Always show CoreML on macOS even if not installed\n if (id === 'coreml' && os.platform() === 'darwin') {\n backends.push({ id, format, available })\n } else if (available) {\n backends.push({ id, format, available })\n }\n }\n\n return { pythonPath, backends }\n }\n\n private scoreBackends(\n hardware: HardwareInfo,\n nodeBackends: Array<{ id: string; available: boolean }>,\n pythonBackends: Array<{ id: string; format: string; available: boolean }>,\n ): PlatformScore[] {\n const scores: PlatformScore[] = []\n\n // macOS Apple Silicon\n if (hardware.platform === 'darwin' && hardware.arch === 'arm64') {\n const pyCoreMl = pythonBackends.find(b => b.id === 'coreml')\n if (pyCoreMl) {\n scores.push({ runtime: 'python', backend: 'coreml', format: 'coreml', score: 95, reason: 'Apple Neural Engine (Python CoreML)', available: pyCoreMl.available })\n }\n const nodeCoreMl = nodeBackends.find(b => b.id === 'coreml')\n if (nodeCoreMl) {\n scores.push({ runtime: 'node', backend: 'coreml', format: 'onnx', score: 90, reason: 'CoreML via ONNX Runtime', available: nodeCoreMl.available })\n }\n }\n\n // NVIDIA\n if (hardware.gpu?.type === 'nvidia') {\n const tensorrt = nodeBackends.find(b => b.id === 'tensorrt')\n if (tensorrt) scores.push({ runtime: 'node', backend: 'tensorrt', format: 'onnx', score: 95, reason: 'NVIDIA TensorRT', available: true })\n const cuda = nodeBackends.find(b => b.id === 'cuda')\n if (cuda) scores.push({ runtime: 'node', backend: 'cuda', format: 'onnx', score: 85, reason: 'NVIDIA CUDA', available: true })\n }\n\n // Intel OpenVINO\n const openvino = pythonBackends.find(b => b.id === 'openvino')\n if (openvino) {\n const score = hardware.npu?.type === 'intel-npu' ? 90 : 80\n scores.push({ runtime: 'python', backend: 'openvino', format: 'openvino', score, reason: 'Intel OpenVINO', available: openvino.available })\n }\n\n // CPU fallbacks\n scores.push({ runtime: 'node', backend: 'cpu', format: 'onnx', score: 50, reason: 'CPU (ONNX Runtime Node)', available: true })\n const pyOnnx = pythonBackends.find(b => b.id === 'onnx-py')\n if (pyOnnx) {\n scores.push({ runtime: 'python', backend: 'cpu', format: 'onnx', score: 45, reason: 'CPU (Python ONNX)', available: pyOnnx.available })\n }\n\n return scores.sort((a, b) => b.score - a.score)\n }\n}\n","import type { PlatformScore, HardwareInfo, ModelRequirement, ResolvedInferenceConfig } from '@camstack/types'\n\nexport class InferenceConfigResolver {\n constructor(\n private readonly scores: readonly PlatformScore[],\n private readonly hardware: HardwareInfo,\n ) {}\n\n /**\n * Compute accuracy/backend weights based on available system RAM.\n * availableRAM_MB is now sourced from systeminformation (reliable cross-platform),\n * not os.freemem() which is broken on macOS.\n *\n * - > 16 GB available: prefer larger, more accurate models (accuracy 0.6, backend 0.4)\n * - > 8 GB available: balanced (accuracy 0.5, backend 0.5)\n * - <= 8 GB available: prefer speed (accuracy 0.4, backend 0.6)\n */\n private getWeights(): { accuracyWeight: number; backendWeight: number } {\n const ramMB = this.hardware.availableRAM_MB\n if (ramMB > 16_384) return { accuracyWeight: 0.6, backendWeight: 0.4 }\n if (ramMB > 8_192) return { accuracyWeight: 0.5, backendWeight: 0.5 }\n return { accuracyWeight: 0.4, backendWeight: 0.6 }\n }\n\n /**\n * Given an addon's model requirements, pick the best model + runtime + backend.\n *\n * Algorithm:\n * 1. Filter models by available RAM (minRAM_MB < 25% of available RAM)\n * 2. For each remaining model, find the best platform score whose format\n * is available in the model's formats\n * 3. Pick the model with the highest combined score using RAM-adaptive weights:\n * - High RAM (>16 GB): accuracy × 0.6 + backend × 0.4 (prefer accuracy)\n * - Mid RAM (>8 GB): accuracy × 0.5 + backend × 0.5 (balanced)\n * - Low RAM (<=8 GB): accuracy × 0.4 + backend × 0.6 (prefer speed)\n */\n resolve(requirements: readonly ModelRequirement[]): ResolvedInferenceConfig {\n if (requirements.length === 0) {\n return { modelId: '', runtime: 'node', backend: 'cpu', format: 'onnx', reason: 'No models declared' }\n }\n\n // Budget: 25% of available RAM (now reliable via systeminformation)\n const ramBudget = this.hardware.availableRAM_MB * 0.25\n const { accuracyWeight, backendWeight } = this.getWeights()\n\n console.log(`[InferenceConfigResolver] availableRAM: ${this.hardware.availableRAM_MB}MB, budget: ${Math.round(ramBudget)}MB, weights: accuracy=${accuracyWeight}, backend=${backendWeight}`)\n\n // Filter models that fit in memory\n const fits = requirements.filter(m => m.minRAM_MB < ramBudget)\n const candidates = fits.length > 0 ? fits : [requirements[0]!] // fallback to first/smallest\n\n console.log(`[InferenceConfigResolver] ${candidates.length}/${requirements.length} models fit RAM budget`)\n\n // For each model, find best compatible platform score\n let bestCombo: { model: ModelRequirement; score: PlatformScore; combined: number } | null = null\n\n for (const model of candidates) {\n for (const score of this.scores) {\n if (!score.available) continue\n if (!model.formats.includes(score.format)) continue\n\n const combined = model.accuracyScore * accuracyWeight + score.score * backendWeight\n\n if (!bestCombo || combined > bestCombo.combined) {\n console.log(`[InferenceConfigResolver] New best: ${model.modelId} (accuracy=${model.accuracyScore}) + ${score.backend}/${score.format} (score=${score.score}) → combined=${Math.round(combined)}`)\n bestCombo = { model, score, combined }\n }\n }\n }\n\n if (!bestCombo) {\n return {\n modelId: candidates[0]!.modelId,\n runtime: 'node',\n backend: 'cpu',\n format: 'onnx',\n reason: 'No compatible backend — CPU fallback',\n }\n }\n\n return {\n modelId: bestCombo.model.modelId,\n runtime: bestCombo.score.runtime,\n backend: bestCombo.score.backend,\n format: bestCombo.score.format,\n reason: `${bestCombo.model.name} on ${bestCombo.score.reason} (score: ${Math.round(bestCombo.combined)})`,\n }\n }\n}\n","import type {\n Integration, Device,\n CreateIntegrationInput, CreateDeviceInput,\n IIntegrationRegistry,\n ISettingsBackend,\n TableSchema,\n} from '@camstack/types'\n\nfunction serializeSetting(value: unknown): { value: string; valueType: string } {\n if (typeof value === 'number') return { value: String(value), valueType: 'number' }\n if (typeof value === 'boolean') return { value: String(value), valueType: 'boolean' }\n if (typeof value === 'string') return { value, valueType: 'string' }\n return { value: JSON.stringify(value), valueType: 'json' }\n}\n\nfunction deserializeSetting(value: string, valueType: string): unknown {\n switch (valueType) {\n case 'number': return Number(value)\n case 'boolean': return value === 'true'\n case 'json': try { return JSON.parse(value) } catch { return value }\n default: return value\n }\n}\n\nlet integrationCounter = 0\nlet deviceCounter = 0\n\nfunction nextIntegrationId(): string {\n return `int_${String(++integrationCounter).padStart(4, '0')}`\n}\n\nfunction nextDeviceId(): string {\n return `dev_${String(++deviceCounter).padStart(4, '0')}`\n}\n\nconst INTEGRATIONS_SCHEMA: TableSchema = {\n columns: [\n { name: 'id', type: 'TEXT', primaryKey: true },\n { name: 'addon_id', type: 'TEXT', notNull: true },\n { name: 'name', type: 'TEXT', notNull: true },\n { name: 'enabled', type: 'INTEGER', notNull: true, defaultValue: 1 },\n { name: 'info', type: 'TEXT', notNull: true, defaultValue: '{}' },\n { name: 'created_at', type: 'INTEGER', notNull: true },\n { name: 'updated_at', type: 'INTEGER', notNull: true },\n ],\n indexes: [\n { name: 'idx_integrations_addon', columns: ['addon_id'] },\n ],\n}\n\nconst INTEGRATION_SETTINGS_SCHEMA: TableSchema = {\n columns: [\n { name: 'integration_id', type: 'TEXT', notNull: true },\n { name: 'key', type: 'TEXT', notNull: true },\n { name: 'value', type: 'TEXT', notNull: true },\n { name: 'value_type', type: 'TEXT', notNull: true, defaultValue: 'string' },\n ],\n}\n\nconst DEVICES_SCHEMA: TableSchema = {\n columns: [\n { name: 'id', type: 'TEXT', primaryKey: true },\n { name: 'integration_id', type: 'TEXT', notNull: true },\n { name: 'stable_id', type: 'TEXT', notNull: true, unique: true },\n { name: 'type', type: 'TEXT', notNull: true, defaultValue: 'camera' },\n { name: 'name', type: 'TEXT', notNull: true },\n { name: 'enabled', type: 'INTEGER', notNull: true, defaultValue: 1 },\n { name: 'info', type: 'TEXT', notNull: true, defaultValue: '{}' },\n { name: 'created_at', type: 'INTEGER', notNull: true },\n { name: 'updated_at', type: 'INTEGER', notNull: true },\n ],\n indexes: [\n { name: 'idx_devices_integration', columns: ['integration_id'] },\n { name: 'idx_devices_stable', columns: ['stable_id'], unique: true },\n { name: 'idx_devices_type', columns: ['type'] },\n ],\n}\n\nconst DEVICE_SETTINGS_SCHEMA: TableSchema = {\n columns: [\n { name: 'device_id', type: 'TEXT', notNull: true },\n { name: 'key', type: 'TEXT', notNull: true },\n { name: 'value', type: 'TEXT', notNull: true },\n { name: 'value_type', type: 'TEXT', notNull: true, defaultValue: 'string' },\n ],\n}\n\nexport class IntegrationRegistry implements IIntegrationRegistry {\n private readonly backend: ISettingsBackend\n\n constructor(backend: ISettingsBackend) {\n this.backend = backend\n }\n\n async initialize(): Promise<void> {\n await this.backend.ensureTable?.('integrations', INTEGRATIONS_SCHEMA)\n await this.backend.ensureTable?.('integration_settings', INTEGRATION_SETTINGS_SCHEMA)\n await this.backend.ensureTable?.('devices', DEVICES_SCHEMA)\n await this.backend.ensureTable?.('device_settings_kv', DEVICE_SETTINGS_SCHEMA)\n\n // Resume counters from max existing IDs\n const ints = await this.backend.tableQuery?.('integrations', { orderBy: { field: 'id', direction: 'desc' }, limit: 1 }) ?? []\n if (ints[0]) {\n const num = parseInt(String(ints[0]['id']).replace('int_', ''), 10)\n if (!isNaN(num)) integrationCounter = num\n }\n const devs = await this.backend.tableQuery?.('devices', { orderBy: { field: 'id', direction: 'desc' }, limit: 1 }) ?? []\n if (devs[0]) {\n const num = parseInt(String(devs[0]['id']).replace('dev_', ''), 10)\n if (!isNaN(num)) deviceCounter = num\n }\n }\n\n // --- Integrations ---\n\n createIntegration(input: CreateIntegrationInput): Integration {\n const id = nextIntegrationId()\n const now = Math.floor(Date.now() / 1000)\n\n void this.backend.tableInsert?.('integrations', {\n id,\n addon_id: input.addonId,\n name: input.name,\n enabled: input.enabled !== false ? 1 : 0,\n info: JSON.stringify(input.info ?? {}),\n created_at: now,\n updated_at: now,\n })\n\n if (input.settings) {\n this.setIntegrationSettings(id, input.settings)\n }\n\n return {\n id,\n addonId: input.addonId,\n name: input.name,\n enabled: input.enabled !== false,\n info: input.info ?? {},\n createdAt: now,\n updatedAt: now,\n }\n }\n\n getIntegration(id: string): Integration | null {\n // tableGet is async but we need sync — use fire-and-forget pattern\n // This works because SqliteSettingsBackend is synchronous under the hood\n let result: Integration | null = null\n void this.backend.tableGet?.('integrations', { id }).then(row => {\n if (row) result = this.mapIntegration(row)\n })\n // For sync SQLite, the promise resolves immediately\n return result\n }\n\n getIntegrationByAddonId(addonId: string): Integration | null {\n let result: Integration | null = null\n void this.backend.tableGet?.('integrations', { addon_id: addonId }).then(row => {\n if (row) result = this.mapIntegration(row)\n })\n return result\n }\n\n listIntegrations(): readonly Integration[] {\n let result: readonly Integration[] = []\n void this.backend.tableQuery?.('integrations', { orderBy: { field: 'created_at', direction: 'asc' } }).then(rows => {\n result = rows.map(r => this.mapIntegration(r))\n })\n return result\n }\n\n updateIntegration(id: string, updates: Partial<Pick<Integration, 'name' | 'enabled' | 'info'>>): Integration | null {\n const updateRow: Record<string, unknown> = { updated_at: Math.floor(Date.now() / 1000) }\n if (updates.name !== undefined) updateRow['name'] = updates.name\n if (updates.enabled !== undefined) updateRow['enabled'] = updates.enabled ? 1 : 0\n if (updates.info !== undefined) updateRow['info'] = JSON.stringify(updates.info)\n\n void this.backend.tableUpdate?.('integrations', { id }, updateRow)\n return this.getIntegration(id)\n }\n\n deleteIntegration(id: string): boolean {\n // Cascade: delete devices + their settings, then integration settings, then integration\n const devices = this.listDevices(id)\n for (const d of devices) {\n void this.backend.tableDelete?.('device_settings_kv', { device_id: d.id })\n }\n void this.backend.tableDelete?.('devices', { integration_id: id })\n void this.backend.tableDelete?.('integration_settings', { integration_id: id })\n void this.backend.tableDelete?.('integrations', { id })\n return true\n }\n\n // --- Integration Settings ---\n\n getIntegrationSettings(integrationId: string): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n void this.backend.tableQuery?.('integration_settings', { where: { integration_id: integrationId } }).then(rows => {\n for (const row of rows) {\n result[String(row['key'])] = deserializeSetting(String(row['value']), String(row['value_type']))\n }\n })\n return result\n }\n\n setIntegrationSetting(integrationId: string, key: string, value: unknown): void {\n const s = serializeSetting(value)\n // Upsert: delete then insert (no composite PK support in generic tableInsert)\n void this.backend.tableDelete?.('integration_settings', { integration_id: integrationId, key })\n void this.backend.tableInsert?.('integration_settings', {\n integration_id: integrationId,\n key,\n value: s.value,\n value_type: s.valueType,\n })\n }\n\n setIntegrationSettings(integrationId: string, settings: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(settings)) {\n this.setIntegrationSetting(integrationId, key, value)\n }\n }\n\n // --- Devices ---\n\n createDevice(input: CreateDeviceInput): Device {\n const id = nextDeviceId()\n const now = Math.floor(Date.now() / 1000)\n\n void this.backend.tableInsert?.('devices', {\n id,\n integration_id: input.integrationId,\n stable_id: input.stableId,\n type: input.type,\n name: input.name,\n enabled: input.enabled !== false ? 1 : 0,\n info: JSON.stringify(input.info ?? {}),\n created_at: now,\n updated_at: now,\n })\n\n if (input.settings) {\n this.setDeviceSettings(id, input.settings)\n }\n\n return {\n id,\n integrationId: input.integrationId,\n stableId: input.stableId,\n type: input.type,\n name: input.name,\n enabled: input.enabled !== false,\n info: input.info ?? {},\n createdAt: now,\n updatedAt: now,\n }\n }\n\n getDevice(id: string): Device | null {\n let result: Device | null = null\n void this.backend.tableGet?.('devices', { id }).then(row => {\n if (row) result = this.mapDevice(row)\n })\n return result\n }\n\n getDeviceByStableId(stableId: string): Device | null {\n let result: Device | null = null\n void this.backend.tableGet?.('devices', { stable_id: stableId }).then(row => {\n if (row) result = this.mapDevice(row)\n })\n return result\n }\n\n listDevices(integrationId?: string): readonly Device[] {\n let result: readonly Device[] = []\n const options = integrationId\n ? { where: { integration_id: integrationId }, orderBy: { field: 'created_at' as const, direction: 'asc' as const } }\n : { orderBy: { field: 'created_at' as const, direction: 'asc' as const } }\n void this.backend.tableQuery?.('devices', options).then(rows => {\n result = rows.map(r => this.mapDevice(r))\n })\n return result\n }\n\n listCameras(): readonly Device[] {\n let result: readonly Device[] = []\n void this.backend.tableQuery?.('devices', { where: { type: 'camera' }, orderBy: { field: 'created_at', direction: 'asc' } }).then(rows => {\n result = rows.map(r => this.mapDevice(r))\n })\n return result\n }\n\n updateDevice(id: string, updates: Partial<Pick<Device, 'name' | 'enabled' | 'info'>>): Device | null {\n const updateRow: Record<string, unknown> = { updated_at: Math.floor(Date.now() / 1000) }\n if (updates.name !== undefined) updateRow['name'] = updates.name\n if (updates.enabled !== undefined) updateRow['enabled'] = updates.enabled ? 1 : 0\n if (updates.info !== undefined) updateRow['info'] = JSON.stringify(updates.info)\n\n void this.backend.tableUpdate?.('devices', { id }, updateRow)\n return this.getDevice(id)\n }\n\n deleteDevice(id: string): boolean {\n void this.backend.tableDelete?.('device_settings_kv', { device_id: id })\n void this.backend.tableDelete?.('devices', { id })\n return true\n }\n\n // --- Device Settings ---\n\n getDeviceSettings(deviceId: string): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n void this.backend.tableQuery?.('device_settings_kv', { where: { device_id: deviceId } }).then(rows => {\n for (const row of rows) {\n result[String(row['key'])] = deserializeSetting(String(row['value']), String(row['value_type']))\n }\n })\n return result\n }\n\n setDeviceSetting(deviceId: string, key: string, value: unknown): void {\n const s = serializeSetting(value)\n void this.backend.tableDelete?.('device_settings_kv', { device_id: deviceId, key })\n void this.backend.tableInsert?.('device_settings_kv', {\n device_id: deviceId,\n key,\n value: s.value,\n value_type: s.valueType,\n })\n }\n\n setDeviceSettings(deviceId: string, settings: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(settings)) {\n this.setDeviceSetting(deviceId, key, value)\n }\n }\n\n // --- Mappers ---\n\n private mapIntegration(row: Record<string, unknown>): Integration {\n return {\n id: String(row['id']),\n addonId: String(row['addon_id']),\n name: String(row['name']),\n enabled: row['enabled'] === 1,\n info: typeof row['info'] === 'string' ? JSON.parse(row['info']) : {},\n createdAt: Number(row['created_at']),\n updatedAt: Number(row['updated_at']),\n }\n }\n\n private mapDevice(row: Record<string, unknown>): Device {\n return {\n id: String(row['id']),\n integrationId: String(row['integration_id']),\n stableId: String(row['stable_id']),\n type: String(row['type']),\n name: String(row['name']),\n enabled: row['enabled'] === 1,\n info: typeof row['info'] === 'string' ? JSON.parse(row['info']) : {},\n createdAt: Number(row['created_at']),\n updatedAt: Number(row['updated_at']),\n }\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { IScopedLogger, IEventBus, LoggerFactory, ProviderListItem } from '@camstack/types'\nimport { LifecycleStateMachine, type ElementStatus } from '../lifecycle/lifecycle-state-machine.js'\n\n/** Minimal device registry interface for provider management */\nexport type ProviderDeviceRegistry = {\n registerProviderDevices(providerId: string, devices: readonly IRegistrableDevice[]): void\n unregisterProviderDevices(providerId: string): void\n}\n\nexport interface IRegistrableDevice {\n readonly id: string\n readonly name: string\n readonly providerId: string\n readonly capabilities: readonly string[]\n}\n\nexport interface ProviderStatus {\n connected: boolean\n error?: string\n deviceCount: number\n}\n\nexport interface LiveEvent {\n type: string\n camera: string\n timestamp: number\n data: Record<string, unknown>\n}\n\nexport interface IManagedProvider {\n readonly id: string\n readonly type: string\n readonly name: string\n start(): Promise<void>\n stop(): Promise<void>\n getStatus(): ProviderStatus\n getDevices(): readonly IRegistrableDevice[]\n subscribeLiveEvents(callback: (event: LiveEvent) => void): () => void\n}\n\ninterface ProviderEntry<P extends IManagedProvider> {\n readonly provider: P\n readonly lifecycle: LifecycleStateMachine\n started: boolean\n unsubscribe?: () => void\n}\n\nexport type { ProviderListItem }\n\nexport class ProviderManager<P extends IManagedProvider = IManagedProvider> {\n private readonly providers = new Map<string, ProviderEntry<P>>()\n private readonly logger: IScopedLogger\n\n constructor(\n private readonly deviceRegistry: ProviderDeviceRegistry,\n private readonly eventBus: IEventBus,\n private readonly loggingService: LoggerFactory,\n ) {\n this.logger = loggingService.createLogger('provider-manager')\n }\n\n registerProvider(provider: P): void {\n const providerLogger = this.loggingService.createLogger(`provider:${provider.id}`)\n const lifecycle = new LifecycleStateMachine(\n provider.id,\n 'provider',\n this.eventBus,\n providerLogger,\n )\n this.providers.set(provider.id, { provider, lifecycle, started: false })\n this.logger.info(`Provider registered: ${provider.id} (${provider.name})`)\n }\n\n async startProvider(id: string): Promise<void> {\n const entry = this.providers.get(id)\n if (!entry) {\n throw new Error(`Provider \"${id}\" is not registered`)\n }\n\n if (entry.lifecycle.state === 'disabled') {\n throw new Error(`Provider \"${id}\" is disabled`)\n }\n\n entry.lifecycle.transition('starting')\n\n try {\n await entry.provider.start()\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err)\n entry.lifecycle.transition('error', message)\n throw err\n }\n\n entry.lifecycle.transition('running')\n\n const devices = entry.provider.getDevices()\n this.deviceRegistry.registerProviderDevices(id, devices)\n\n const unsubscribe = entry.provider.subscribeLiveEvents((event: LiveEvent) => {\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'provider', id },\n category: `provider.${event.type}`,\n data: event.data,\n })\n })\n\n entry.started = true\n entry.unsubscribe = unsubscribe\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'core', id: 'provider-manager' },\n category: 'provider.started',\n data: { providerId: id },\n })\n\n this.logger.info(`Provider started: ${id}`)\n }\n\n async stopProvider(id: string): Promise<void> {\n const entry = this.providers.get(id)\n if (!entry) {\n throw new Error(`Provider \"${id}\" is not registered`)\n }\n\n entry.lifecycle.transition('stopping')\n\n if (entry.unsubscribe) {\n entry.unsubscribe()\n entry.unsubscribe = undefined\n }\n\n this.deviceRegistry.unregisterProviderDevices(id)\n\n await entry.provider.stop()\n entry.started = false\n\n entry.lifecycle.transition('stopped')\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'core', id: 'provider-manager' },\n category: 'provider.stopped',\n data: { providerId: id },\n })\n\n this.logger.info(`Provider stopped: ${id}`)\n }\n\n async disableProvider(id: string): Promise<void> {\n const entry = this.providers.get(id)\n if (!entry) {\n throw new Error(`Provider \"${id}\" is not registered`)\n }\n\n if (entry.lifecycle.state === 'running' || entry.started) {\n await this.stopProvider(id)\n }\n\n entry.lifecycle.transition('disabled')\n this.logger.info(`Provider disabled: ${id}`)\n }\n\n async enableProvider(id: string): Promise<void> {\n const entry = this.providers.get(id)\n if (!entry) {\n throw new Error(`Provider \"${id}\" is not registered`)\n }\n\n if (entry.lifecycle.state !== 'disabled') {\n throw new Error(`Provider \"${id}\" is not disabled`)\n }\n\n entry.lifecycle.transition('stopped')\n this.logger.info(`Provider enabled: ${id}`)\n }\n\n async restartProvider(id: string): Promise<void> {\n await this.stopProvider(id)\n await this.startProvider(id)\n }\n\n getProvider(id: string): P | null {\n const entry = this.providers.get(id)\n return entry?.provider ?? null\n }\n\n getProviderStatus(id: string): ElementStatus | null {\n const entry = this.providers.get(id)\n return entry?.lifecycle.getStatus() ?? null\n }\n\n listProviders(): readonly ProviderListItem[] {\n return Array.from(this.providers.values()).map((entry) => ({\n id: entry.provider.id,\n type: entry.provider.type,\n name: entry.provider.name,\n status: entry.provider.getStatus(),\n started: entry.started,\n lifecycle: entry.lifecycle.getStatus(),\n }))\n }\n\n async shutdownAll(): Promise<void> {\n const startedIds = Array.from(this.providers.entries())\n .filter(([, entry]) => entry.started)\n .map(([id]) => id)\n\n for (const id of startedIds) {\n await this.stopProvider(id)\n }\n\n this.logger.info(`All providers shut down (${startedIds.length} stopped)`)\n }\n}\n"],"mappings":"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","names":["import_node_fs","import_node_path","import_node_path","path","_typeof","module","o","toPrimitive","toPropertyKey","r","opts: {\n links: OperationLink<TRouter, TInput, TOutput>[];\n op: Operation<TInput>;\n}","value: TType | TType[]","opts: {\n condition: (op: Operation) => boolean;\n /**\n * The link to execute next if the test function returns `true`.\n */\n true: TRPCLink<TRouter> | TRPCLink<TRouter>[];\n /**\n * The link to execute next if the test function returns `false`.\n */\n false: TRPCLink<TRouter> | TRPCLink<TRouter>[];\n}","cause: unknown","obj: unknown","err: unknown","fallback: string","TRPCClientError","message: string","opts?: {\n result?: Maybe<TRPCErrorResponse<inferErrorShape<TRouterOrProcedure>>>;\n cause?: Error;\n meta?: Record<string, unknown>;\n }","_cause: Error | TRPCErrorResponse<any> | object","opts: { meta?: Record<string, unknown>; cause?: Error }","transformer:\n | TransformerOptions<{ transformer: false }>['transformer']\n | TransformerOptions<{ transformer: true }>['transformer']\n | undefined","customFetchImpl?: FetchEsque | NativeFetchEsque","opts: HTTPLinkBaseOptions<AnyClientTypes>","array: unknown[]","dict: Record<number, unknown>","opts: GetInputOptions","opts: HTTPRequestOptions","import_objectSpread2","getUrl: GetUrl","getBody: GetBody","jsonHttpRequester: Requester","fn: unknown","queryParts: string[]","signal: Maybe<AbortSignal>","input: unknown","opts: HTTPLinkOptions<TRouter['_def']['_config']['$types']>","path","import_objectSpread2","meta: HTTPResult['meta'] | undefined","universalRequester: Requester","batchLoader: BatchLoader<TKey, TValue>","pendingItems: BatchItem<TKey, TValue>[] | null","dispatchTimer: ReturnType<typeof setTimeout> | null","items: BatchItem<TKey, TValue>[]","groupedItems: BatchItem<TKey, TValue>[][]","batch: Batch<TKey, TValue>","key: TKey","item: BatchItem<TKey, TValue>","resolve","signal: AbortSignal","opts: HTTPBatchLinkOptions<TRouter['_def']['_config']['$types']>","type: ProcedureType","path","import_objectSpread2","isFormData","value: unknown","opts: LoggerLinkFnOptions<any> & {\n colorMode: ColorMode;\n withContext?: boolean;\n }","path","parts: string[]","args: any[]","import_objectSpread2","opts: LoggerLinkOptions<TRouter>","result:\n | OperationResultEnvelope<unknown, TRPCClientError<TRouter>>\n | TRPCClientError<TRouter>","fn: 'error' | 'log'","resolve: (value: T | PromiseLike<T>) => void","reject: (reason?: any) => void","resolve","urlOptions: UrlOptionsWithConnectionParams","connectionParams: CallbackOrValue<TRPCRequestInfo['connectionParams']>","encoder: Encoder","message: TRPCConnectionParamsMessage","ws: WebSocket","pingTimeout: ReturnType<typeof setTimeout> | undefined","pongTimeout: ReturnType<typeof setTimeout> | undefined","connection: WsConnection","opts: WebSocketClientOptions","opts: WebSocketLinkOptions<TRouter>","jsonEncoder: Encoder","lazyDefaults: LazyOptions","keepAliveDefaults: KeepAliveOptions","attemptIndex: number","value: T | ((...args: TArgs) => T)","TRPCWebSocketClosedError","opts: { message: string; cause?: unknown }","onTimeout: () => void","timeoutMs: number","message: TRPCClientOutgoingMessage","callbacks: TCallbacks","messageId: MessageIdLike","WsConnection","opts: WebSocketConnectionOptions","this","import_objectSpread2","requestsToAwait: Promise<void>[]","path","closedError: TRPCWebSocketClosedError","cause: unknown","message: TRPCResponseMessage","message: TRPCClientIncomingRequest","messageOrMessages: TRPCClientOutgoingMessage | TRPCClientOutgoingMessage[]","message","opts: CreateTRPCClientOptions<TRouter>","client: TRPCUntypedClient<TRouter>","path","client: TRPCClient<TRouter>","opts: HTTPBatchStreamLinkOptions<TRouter['_def']['_config']['$types']>","type: ProcedureType","opts","promises","json: TRPCResponse","input: unknown","lastEventId: string | undefined","opts: UrlOptionsWithConnectionParams","opts: HTTPSubscriptionLinkOptions<\n inferClientTypes<TInferrable>,\n TEventSource\n >","result: TRPCResult<unknown>","opts: RetryLinkOptions<TInferrable>","next$: Unsubscribable","callNextTimeout: ReturnType<typeof setTimeout> | undefined","attempts: number","opts: LocalLinkOptions<TRouter>","chunk: unknown","ctx: inferRouterContext<TRouter> | undefined","newInput: unknown","cause: unknown","chunk: TRPCResult<unknown>","import_objectSpread2","clientCallTypeMap: Record<\n keyof DecorateProcedure<any, any>,\n ProcedureType\n>","experimental_localLink: typeof unstable_localLink","opts: CreateTRPCClientOptions<TInferrable>","opts: {\n type: TRPCType;\n input: TInput;\n path: string;\n context?: OperationContext;\n signal: Maybe<AbortSignal>;\n }","path: string","input?: unknown","opts?: TRPCRequestOptions","opts: Partial<\n TRPCSubscriptionObserver<unknown, TRPCClientError<AnyRouter>>\n > &\n TRPCRequestOptions","clientCallType: string","_asyncIterator","r","AsyncFromSyncIterator","module","e","n","o","OverloadYield","_awaitAsyncGenerator","_wrapAsyncGenerator","t","platform","rmSync","import_node_path","platform","arch","import_node_path","import_node_fs","import_node_child_process","import_promises","import_node_stream","platform","arch","unlinkSync","resolve","hash","fs","path","format","import_node_child_process","fs","path","import_node_crypto","promises","import_node_child_process","resolve","resolve","resolve","WebSocket","fs","path","import_node_crypto","import_better_sqlite3","fs","path","import_node_crypto","Database","import_better_sqlite3","Database","path","DailyRotateFile","resolve","import_node_crypto","path","import_node_crypto","fs","path","StorageLocationManager","location","hash","crypto","hash","crypto","crypto","path","import_node_crypto","import_node_crypto","import_node_child_process","import_node_util","import_node_fs","import_node_path","execFileAsync","createTRPCClient","createWSClient","wsLink","os","import_node_child_process","platform","readFileSync","arch","cpus","format","import_node_crypto"]}
1
+ {"version":3,"sources":["../src/process/resource-monitor.ts","../src/storage/fs-storage-backend.ts","../src/storage/storage-location-manager.ts","../src/index.ts","../src/events/event-bus.ts","../src/download/model-downloader.ts","../src/download/model-download-service.ts","../src/python/python-env-manager.ts","../src/pipeline/pipeline-validator.ts","../src/pipeline/pipeline-runner.ts","../src/pipeline/engine-manager-resolver.ts","../src/network/network-quality.ts","../src/repl/repl-engine.ts","../src/builtins/sqlite-storage/index.ts","../src/builtins/sqlite-storage/filesystem-storage.addon.ts","../src/builtins/sqlite-storage/sqlite-settings-backend.ts","../src/builtins/sqlite-storage/sqlite-settings.addon.ts","../src/builtins/sqlite-storage/settings-store.ts","../src/builtins/sqlite-storage/sql-schema.ts","../src/builtins/sqlite-storage/device-store.ts","../src/builtins/sqlite-storage/config-store.ts","../src/builtins/winston-logging/winston-logging.addon.ts","../src/builtins/winston-logging/winston-destination.ts","../src/logging/formatter.ts","../src/builtins/console-logging/console-logging.addon.ts","../src/builtins/console-logging/console-destination.ts","../src/builtins/hub-forwarder/hub-forwarder.addon.ts","../src/builtins/hub-forwarder/hub-forwarder-destination.ts","../src/builtins/local-backup/local-backup.ts","../src/builtins/local-backup/local-backup.addon.ts","../src/builtins/native-metrics/native-metrics.addon.ts","../src/builtins/native-metrics/native-metrics-provider.ts","../src/builtins/alerts/alerts.addon.ts","../src/builtins/system-config/system-config.addon.ts","../src/builtins/local-auth/local-auth.addon.ts","../src/auth/auth-manager.ts","../src/auth/user-manager.ts","../src/auth/parse-record.ts","../src/auth/api-key-manager.ts","../src/auth/scoped-token-manager.ts","../src/builtins/local-auth/auth-schema.ts","../src/builtins/device-manager/device-manager.addon.ts","../src/builtins/device-manager/device-event-propagator.ts","../src/lifecycle/lifecycle-state-machine.ts","../src/feature/feature-manager.ts","../src/events/system-event-bus.ts","../src/logging/log-ring-buffer.ts","../src/logging/scoped-logger.ts","../src/logging/log-manager.ts","../src/storage/storage-manager.ts","../src/notification/notification-service.ts","../src/notification/toast-service.ts","../src/addon-routes/addon-route-registry.ts","../src/tls/cert-manager.ts","../src/addon/addon-api-factory.ts","../src/builtins/sqlite-storage/integration-registry.ts"],"sourcesContent":["import { execFile } from 'node:child_process'\n\n// ===========================================================================\n// Per-PID resource usage — zero dependencies, uses ps (macOS/Linux).\n//\n// These are process-management utilities used by:\n// - native-metrics-provider.ts (system metrics collection)\n// - addon-registry.service.ts (addon process stats)\n//\n// System-wide metrics (CPU, memory, disk, network, GPU, temp, PSI)\n// have moved to @camstack/addon-metrics-native via the IMetricsProvider\n// interface defined in @camstack/types.\n// ===========================================================================\n\nexport interface PidStats {\n cpu: number // 0–100 percentage\n memory: number // RSS in bytes\n}\n\nfunction execPsForPids(pids: readonly number[]): Promise<string> {\n return new Promise((resolve, reject) => {\n execFile('ps', ['-o', 'pid=,pcpu=,rss=', '-p', pids.join(',')], {\n timeout: 5000,\n }, (err, stdout) => {\n if (err) return reject(err)\n resolve(stdout)\n })\n })\n}\n\nfunction parsePsOutput(stdout: string): ReadonlyMap<number, PidStats> {\n const result = new Map<number, PidStats>()\n for (const line of stdout.trim().split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed) continue\n const parts = trimmed.split(/\\s+/)\n if (parts.length < 3) continue\n const pid = parseInt(parts[0]!, 10)\n const cpu = parseFloat(parts[1]!)\n const rssKb = parseInt(parts[2]!, 10)\n if (isNaN(pid) || isNaN(cpu) || isNaN(rssKb)) continue\n result.set(pid, {\n cpu: Math.round(cpu * 10) / 10,\n memory: rssKb * 1024, // KB → bytes\n })\n }\n return result\n}\n\n/**\n * Get CPU% and memory RSS for one or more PIDs.\n * Returns a map of pid → stats. Missing/dead PIDs are silently omitted.\n */\nexport async function getPidStats(pids: number | readonly number[]): Promise<ReadonlyMap<number, PidStats>> {\n const pidArray = typeof pids === 'number' ? [pids] : [...pids]\n if (pidArray.length === 0) return new Map()\n\n try {\n const stdout = await execPsForPids(pidArray)\n return parsePsOutput(stdout)\n } catch {\n return new Map()\n }\n}\n\n/** Get CPU% and memory RSS for a single PID. Returns null if dead. */\nexport async function getSinglePidStats(pid: number): Promise<PidStats | null> {\n const stats = await getPidStats([pid])\n return stats.get(pid) ?? null\n}\n","import { existsSync, accessSync, constants } from 'node:fs'\nimport { join, resolve, dirname, isAbsolute } from 'node:path'\n\nexport interface IStorageBackend {\n /** Backend type identifier */\n readonly type: string\n /** Base path of this backend */\n readonly basePath: string\n /** Resolve a subpath to an absolute path */\n resolve(subpath: string): string\n /**\n * Check whether the backend is usable: either the base directory\n * already exists and is writable, OR we can create it on first\n * write (i.e. the nearest existing ancestor is writable).\n */\n isAvailable(): boolean\n /** No-op for lazy backends. Kept for API compatibility. */\n initialize(): Promise<void>\n}\n\n/**\n * Filesystem storage backend — lazy by design.\n *\n * `initialize()` does NOT create the base directory eagerly. Instead,\n * consumers that write via `FilesystemStorageProvider` (and other write\n * helpers in storage-manager.ts) run `fs.mkdir(dirname(filePath), { recursive: true })`\n * right before every `writeFile`, so the directory tree appears on demand.\n *\n * The previous behaviour eagerly mkdir'd every location declared in\n * `StorageLocationManager.initializeDefaults()` — six directories (`db`,\n * `media`, `recordings`, `models`, `cache`, `logs`) got created at boot\n * even if the installation had no cameras, no recording addon, no\n * analytics addon, etc. That meant every fresh install looked like it\n * was producing data when it had nothing to write. Laziness fixes that:\n * a directory only exists once an addon decides to put a file there.\n */\nexport class FsStorageBackend implements IStorageBackend {\n readonly type = 'local'\n readonly basePath: string\n\n constructor(basePath: string) {\n this.basePath = resolve(basePath)\n }\n\n resolve(subpath: string): string {\n if (isAbsolute(subpath)) return subpath\n return join(this.basePath, subpath)\n }\n\n isAvailable(): boolean {\n // If the base dir already exists, check write permission directly.\n // Otherwise walk up to the first existing ancestor (guaranteed to\n // terminate at the filesystem root) and check it is writable — we\n // can then mkdir the missing segments on first write.\n try {\n if (existsSync(this.basePath)) {\n accessSync(this.basePath, constants.W_OK)\n return true\n }\n let parent = dirname(this.basePath)\n while (parent && parent !== dirname(parent)) {\n if (existsSync(parent)) {\n accessSync(parent, constants.W_OK)\n return true\n }\n parent = dirname(parent)\n }\n return false\n } catch {\n return false\n }\n }\n\n async initialize(): Promise<void> {\n // No-op: base directory is created lazily on first write. See the\n // class docstring for the rationale.\n }\n}\n","import { join, isAbsolute } from 'node:path'\nimport { FsStorageBackend, type IStorageBackend } from './fs-storage-backend.js'\n\nexport type StorageLocationName = 'data' | 'media' | 'recordings' | 'models' | 'cache' | 'logs'\n\nexport class StorageLocationManager {\n private readonly backends: Map<StorageLocationName, IStorageBackend> = new Map()\n private readonly dataPath: string\n\n constructor(dataPath: string) {\n this.dataPath = dataPath\n }\n\n /** Initialize all locations with default paths */\n async initializeDefaults(): Promise<void> {\n const defaults: Record<StorageLocationName, string> = {\n data: join(this.dataPath, 'db'),\n media: join(this.dataPath, 'media'),\n recordings: join(this.dataPath, 'recordings'),\n models: join(this.dataPath, 'models'),\n cache: '/tmp/camstack-cache',\n logs: join(this.dataPath, 'logs'),\n }\n\n for (const [name, path] of Object.entries(defaults)) {\n const backend = new FsStorageBackend(path)\n await backend.initialize()\n this.backends.set(name as StorageLocationName, backend)\n }\n }\n\n /** Override a specific location's backend path */\n async setLocationPath(name: StorageLocationName, basePath: string): Promise<void> {\n const resolved = isAbsolute(basePath) ? basePath : join(this.dataPath, basePath)\n const backend = new FsStorageBackend(resolved)\n await backend.initialize()\n this.backends.set(name, backend)\n }\n\n /** Get the backend for a location */\n getBackend(name: StorageLocationName): IStorageBackend {\n const backend = this.backends.get(name)\n if (!backend) throw new Error(`Storage location \"${name}\" not initialized`)\n return backend\n }\n\n /** Resolve a path within a location */\n resolve(location: StorageLocationName, subpath: string): string {\n return this.getBackend(location).resolve(subpath)\n }\n\n /** Check if all locations are available */\n getStatus(): Array<{ name: StorageLocationName; available: boolean; path: string }> {\n return Array.from(this.backends.entries()).map(([name, backend]) => ({\n name,\n available: backend.isAvailable(),\n path: backend.basePath,\n }))\n }\n\n /** All location names */\n getLocationNames(): StorageLocationName[] {\n return Array.from(this.backends.keys())\n }\n}\n","// Infrastructure utilities live in `@camstack/types/node` since 2026-05\n// (lifted from `@camstack/core` to break the kernel ↔ core dependency\n// cycle, then moved off the root types entry so browser bundlers don't\n// traverse `node:fs`). Re-exported here for backward compatibility with\n// existing consumers (`@camstack/server`, addon dynamic imports).\nexport {\n ensureBinary,\n downloadBinary,\n findInPath,\n getPlatformInfo,\n buildBinaryPath,\n ensureFfmpeg,\n getFfmpegDownloadUrl,\n ensurePython,\n installPythonPackages,\n installPythonRequirements,\n getPythonDownloadUrl,\n PYTHON_VERSION,\n} from '@camstack/types/node'\nexport type { PlatformInfo } from '@camstack/types/node'\nexport { EventBus } from './events/event-bus.js'\nexport {\n downloadModel,\n downloadFile,\n fetchJson,\n ensureModel,\n getModelFilePath,\n isModelDownloaded,\n deleteModelFromDisk,\n} from './download/model-downloader.js'\nexport type { DownloadProgressCallback } from './download/model-downloader.js'\nexport { ModelDownloadService } from './download/model-download-service.js'\n// AddonDepsManager moved to @camstack/kernel so addons can consume it via\n// `ctx.deps` without importing `@camstack/core` directly (the lint rule\n// `no-restricted-imports` blocks that boundary).\nexport { PythonEnvManager } from './python/python-env-manager.js'\nexport type { ValidationIssue, ValidationResult } from './pipeline/pipeline-validator.js'\nexport { PipelineValidator } from './pipeline/pipeline-validator.js'\nexport { PipelineRunner } from './pipeline/pipeline-runner.js'\nexport { EngineManagerResolver } from './pipeline/engine-manager-resolver.js'\n\n// Process resource monitoring (kept — used by native-metrics and addon-registry)\nexport { getSinglePidStats, getPidStats } from './process/resource-monitor.js'\nexport type { PidStats } from './process/resource-monitor.js'\n\n// Network quality tracking\nexport { NetworkQualityTracker } from './network/network-quality.js'\nexport type {\n StreamNetworkStats,\n ClientNetworkStats,\n DeviceNetworkStats,\n INetworkQualityTracker,\n} from './network/network-quality.js'\n\n// REPL engine\nexport { ReplEngine } from './repl/repl-engine.js'\nexport type {\n ReplScope,\n ReplSessionContext,\n ReplResult,\n IReplEngine,\n IReplContextProvider,\n} from './repl/interfaces.js'\n\n\n// Builtin providers — default implementations that register through CapabilityRegistry\n// and CAN be replaced by external addons.\nexport { SettingsStore } from './builtins/sqlite-storage/index.js'\nexport { CORE_TABLE_DDL, addonTableToDdl } from './builtins/sqlite-storage/index.js'\nexport type { AddonTableSchema } from './builtins/sqlite-storage/index.js'\nexport { FilesystemStorageProvider } from './builtins/sqlite-storage/index.js'\nexport { FilesystemStorageAddon } from './builtins/sqlite-storage/index.js'\nexport { SqliteSettingsBackend } from './builtins/sqlite-storage/index.js'\nexport { SqliteSettingsAddon } from './builtins/sqlite-storage/index.js'\nexport { DeviceStore } from './builtins/sqlite-storage/index.js'\nexport type { DeviceRow } from './builtins/sqlite-storage/index.js'\nexport { ConfigStore } from './builtins/sqlite-storage/index.js'\nexport { WinstonLoggingAddon } from './builtins/winston-logging/index.js'\nexport { WinstonDestination } from './builtins/winston-logging/index.js'\nexport { ConsoleLoggingAddon } from './builtins/console-logging/index.js'\nexport { ConsoleDestination } from './builtins/console-logging/index.js'\nexport { HubForwarderAddon } from './builtins/hub-forwarder/index.js'\nexport { HubForwarderDestination } from './builtins/hub-forwarder/index.js'\nexport { LocalBackupAddon } from './builtins/local-backup/index.js'\nexport { LocalBackupService } from './builtins/local-backup/index.js'\nexport type { BackupManifest, BackupConfig } from './builtins/local-backup/index.js'\nexport { default as NativeMetricsAddon } from './builtins/native-metrics/native-metrics.addon.js'\nexport { AlertCenterAddon } from './builtins/alerts/index.js'\nexport { NativeMetricsProvider } from './builtins/native-metrics/native-metrics-provider.js'\nexport { SystemConfigAddon } from './builtins/system-config/index.js'\nexport { LocalAuthAddon } from './builtins/local-auth/index.js'\nexport { DeviceManagerAddon } from './builtins/device-manager/index.js'\n// Lifecycle\nexport { LifecycleStateMachine } from './lifecycle/lifecycle-state-machine.js'\nexport type {\n ElementState,\n ElementStatus,\n} from './lifecycle/lifecycle-state-machine.js'\n\n// Feature\nexport { FeatureManager } from './feature/feature-manager.js'\nexport type {\n FeatureManifest,\n FeatureFlag,\n FeatureConfigReader,\n} from './feature/feature-manager.js'\n\n// Events (system-level event bus with ring buffer)\nexport { SystemEventBus } from './events/system-event-bus.js'\nexport type {\n SystemEvent,\n EventSource,\n EventFilter,\n} from './events/system-event-bus.js'\n\n// Logging\nexport { LogManager } from './logging/log-manager.js'\nexport type { ILogDestination } from './logging/log-manager.js'\nexport { LogRingBuffer } from './logging/log-ring-buffer.js'\nexport type { LogEntry, LogFilter, LogLevel } from './logging/log-ring-buffer.js'\nexport { ScopedLogger } from './logging/scoped-logger.js'\nexport type { IScopedLogger } from './logging/scoped-logger.js'\nexport { formatLogLine } from './logging/formatter.js'\n\n\n// Storage\nexport { StorageManager } from './storage/storage-manager.js'\nexport type {\n IStorageProvider as ICoreStorageProvider,\n IStorageLocation,\n IStructuredStorage,\n IFileStorage,\n QueryFilter,\n StorageRecord,\n} from './storage/storage-manager.js'\nexport { StorageLocationManager } from './storage/storage-location-manager.js'\nexport type { StorageLocationName } from './storage/storage-location-manager.js'\nexport { FsStorageBackend } from './storage/fs-storage-backend.js'\nexport type { IStorageBackend } from './storage/fs-storage-backend.js'\n\n// Auth\nexport { AuthManager } from './auth/auth-manager.js'\nexport type { UserRole, TokenPayload, AuthConfigReader } from './auth/auth-manager.js'\nexport { ApiKeyManager } from './auth/api-key-manager.js'\nexport type { ApiKeyRecord, ApiKeyStorageAccess } from './auth/api-key-manager.js'\nexport { UserManager } from './auth/user-manager.js'\nexport type { UserRecord, UserStorageAccess, UserConfigReader } from './auth/user-manager.js'\nexport { ScopedTokenManager } from './auth/scoped-token-manager.js'\n\n// Notification\nexport { NotificationService } from './notification/notification-service.js'\nexport { ToastService } from './notification/toast-service.js'\nexport type { Unsubscribe } from './notification/toast-service.js'\n\n// Addon routes\nexport { AddonRouteRegistry } from './addon-routes/addon-route-registry.js'\n\n\n// TLS\nexport * from './tls/index.js'\n\n// Addon API Factory\nexport { AddonApiFactory } from './addon/addon-api-factory.js'\nexport type { DirectCallerOptions } from './addon/addon-api-factory.js'\n\n// Platform scoring moved to @camstack/addon-platform-probe-native (exposed\n// as the per-node `platform-probe` capability). Inference addons consume\n// `ctx.api.platformProbe.*`; no direct imports from core any more.\n\n// Integration & Device Registry\nexport { IntegrationRegistry } from './builtins/sqlite-storage/integration-registry.js'\n\n","type EventCallback<T = unknown> = (data: T) => void\n\nexport class EventBus {\n private listeners = new Map<string, Set<EventCallback>>()\n\n on<T = unknown>(event: string, callback: EventCallback<T>): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set())\n const set = this.listeners.get(event)!\n set.add(callback as EventCallback)\n return () => set.delete(callback as EventCallback)\n }\n\n emit<T = unknown>(event: string, data: T): void {\n const set = this.listeners.get(event)\n if (!set) return\n for (const cb of set) {\n try { cb(data) } catch { /* don't let one listener break others */ }\n }\n }\n\n once<T = unknown>(event: string, callback: EventCallback<T>): () => void {\n const unsub = this.on<T>(event, (data) => {\n unsub()\n callback(data)\n })\n return unsub\n }\n\n removeAllListeners(event?: string): void {\n if (event) this.listeners.delete(event)\n else this.listeners.clear()\n }\n\n listenerCount(event: string): number {\n return this.listeners.get(event)?.size ?? 0\n }\n}\n","import type { ModelCatalogEntry, ModelDownloadOptions, ModelDownloadResult, ModelFormat } from '@camstack/types'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { createHash } from 'node:crypto'\n\n/** Build fetch headers, including HF auth token for huggingface.co URLs */\nfunction buildHeaders(url: string): Record<string, string> {\n const headers: Record<string, string> = { 'User-Agent': 'CamStack/1.0' }\n const hfToken = process.env['HF_TOKEN'] ?? process.env['HUGGING_FACE_HUB_TOKEN']\n if (hfToken && url.includes('huggingface.co')) {\n headers['Authorization'] = `Bearer ${hfToken}`\n }\n return headers\n}\n\n/**\n * Download a single file from a URL to a destination path.\n * Uses native fetch() (Node 22+) which handles redirects natively.\n * Streams to disk with optional progress callback.\n * Returns the destination path. Skips download if file already exists.\n */\nexport async function downloadFile(\n url: string,\n destPath: string,\n onProgress?: (downloaded: number, total: number) => void,\n): Promise<string> {\n if (fs.existsSync(destPath)) return destPath\n\n fs.mkdirSync(path.dirname(destPath), { recursive: true })\n\n // Atomic download: write to .downloading tmp, rename on success\n const tmpPath = destPath + '.downloading'\n\n try {\n const response = await fetch(url, {\n redirect: 'follow',\n headers: buildHeaders(url),\n })\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} downloading ${url}`)\n }\n if (!response.body) {\n throw new Error(`No response body from ${url}`)\n }\n\n const total = parseInt(response.headers.get('content-length') ?? '0', 10)\n let downloaded = 0\n\n const fileStream = fs.createWriteStream(tmpPath)\n const reader = response.body.getReader()\n\n try {\n for (;;) {\n const { done, value } = await reader.read() as { done: boolean; value?: Uint8Array }\n if (done || !value) break\n fileStream.write(value)\n downloaded += value.length\n onProgress?.(downloaded, total)\n }\n } finally {\n fileStream.end()\n await new Promise<void>((resolve, reject) => {\n fileStream.on('finish', resolve)\n fileStream.on('error', reject)\n })\n }\n\n fs.renameSync(tmpPath, destPath)\n return destPath\n } catch (err) {\n // Clean up partial download\n try { fs.unlinkSync(tmpPath) } catch { /* ignore */ }\n throw err\n }\n}\n\n/**\n * Fetch JSON from a URL using native fetch().\n */\nexport async function fetchJson(url: string): Promise<unknown> {\n const response = await fetch(url, {\n redirect: 'follow',\n headers: buildHeaders(url),\n })\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} fetching ${url}`)\n }\n return response.json()\n}\n\n/**\n * Download a model with fallback URLs and optional SHA256 verification.\n * Legacy API preserved for backward compatibility -- delegates to downloadFile().\n */\nexport async function downloadModel(options: ModelDownloadOptions): Promise<ModelDownloadResult> {\n const { url, fallbackUrls = [], destDir, filename, expectedSha256, onProgress } = options\n\n const fname = filename ?? url.split('/').pop() ?? 'model.bin'\n const destPath = path.join(destDir, fname)\n\n // Check cache\n if (fs.existsSync(destPath)) {\n return { filePath: destPath, downloadedBytes: 0, fromCache: true }\n }\n\n fs.mkdirSync(destDir, { recursive: true })\n\n const urls = [url, ...fallbackUrls]\n let lastError: Error | null = null\n\n for (const tryUrl of urls) {\n try {\n await downloadFile(tryUrl, destPath, onProgress)\n\n // Verify SHA256 if provided\n if (expectedSha256) {\n const hash = await computeSha256(destPath)\n if (hash !== expectedSha256) {\n fs.unlinkSync(destPath)\n throw new Error(`SHA256 mismatch: expected ${expectedSha256}, got ${hash}`)\n }\n }\n\n const stat = fs.statSync(destPath)\n return { filePath: destPath, downloadedBytes: stat.size, fromCache: false }\n } catch (e) {\n lastError = e as Error\n if (fs.existsSync(destPath)) fs.unlinkSync(destPath)\n }\n }\n\n throw lastError ?? new Error(`Failed to download model from ${url}`)\n}\n\nasync function computeSha256(filePath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const hash = createHash('sha256')\n const stream = fs.createReadStream(filePath)\n stream.on('data', (chunk) => hash.update(chunk))\n stream.on('end', () => resolve(hash.digest('hex')))\n stream.on('error', reject)\n })\n}\n\n// ---------------------------------------------------------------------------\n// ModelCatalogEntry-based helpers\n// ---------------------------------------------------------------------------\n//\n// These are the standalone counterparts to `ModelDownloadService.ensure()`\n// for callers that don't need a class-based catalog and just want to\n// resolve a single `ModelCatalogEntry` against `modelsDir`. Detection\n// pipeline previously kept its own copy of this logic\n// (`addon-detection-pipeline/src/engine/model-downloader.ts`); merging\n// them here lets every addon (detection, audio-analyzer, embedding-\n// encoder, …) share one source of truth.\n\n/** Progress callback: (downloadedBytes, totalBytes | undefined) */\nexport type DownloadProgressCallback = (downloaded: number, total: number | undefined) => void\n\n/**\n * Download every file in a HuggingFace directory bundle (e.g.,\n * `.mlpackage` / OpenVINO IR pair) atomically. `knownFiles` lists the\n * relative paths inside the directory; the function fetches each from\n * `${url}/${file}` and renames the staging directory only on full\n * success. Mirrors `ModelDownloadService.downloadDirectory` but\n * exposed as a standalone for catalog-less callers.\n */\nasync function downloadDirectory(\n url: string,\n destDir: string,\n knownFiles: readonly string[] | undefined,\n onProgress?: DownloadProgressCallback,\n): Promise<void> {\n const match = url.match(/huggingface\\.co\\/([^/]+\\/[^/]+)\\/resolve\\/main\\/(.+)/)\n if (!match) throw new Error(`Cannot parse HuggingFace URL: ${url}`)\n const [, repo, dirPath] = match\n\n const files = (knownFiles ?? []).map(f => ({\n relativePath: f,\n fileUrl: `https://huggingface.co/${repo}/resolve/main/${dirPath}/${f}`,\n }))\n if (files.length === 0) {\n throw new Error(`Directory bundle requires explicit \\`files\\` list (got none for ${url})`)\n }\n\n const tmpDir = destDir + '.downloading'\n fs.rmSync(tmpDir, { recursive: true, force: true })\n fs.mkdirSync(tmpDir, { recursive: true })\n\n let totalDownloaded = 0\n try {\n for (const file of files) {\n const destPath = path.join(tmpDir, file.relativePath)\n fs.mkdirSync(path.dirname(destPath), { recursive: true })\n await downloadFile(file.fileUrl, destPath, (downloaded, _total) => {\n onProgress?.(totalDownloaded + downloaded, undefined)\n })\n totalDownloaded += fs.statSync(destPath).size\n }\n fs.rmSync(destDir, { recursive: true, force: true })\n fs.renameSync(tmpDir, destDir)\n } catch (err) {\n fs.rmSync(tmpDir, { recursive: true, force: true })\n throw err\n }\n}\n\n/**\n * Resolve a `ModelCatalogEntry` against `modelsDir`: download model file\n * (or directory bundle) + extra files (labels JSON, charset dict, …),\n * skip if already on disk. Returns the local model path.\n */\nexport async function ensureModel(\n modelsDir: string,\n entry: ModelCatalogEntry,\n format: ModelFormat,\n onProgress?: DownloadProgressCallback,\n): Promise<string> {\n const formatEntry = entry.formats[format]\n if (!formatEntry) {\n throw new Error(\n `Model \"${entry.id}\" has no ${format} format. Available: ${Object.keys(entry.formats).join(', ')}`,\n )\n }\n\n // Extras (labels, dicts) — independent of format.\n if (entry.extraFiles) {\n for (const extra of entry.extraFiles) {\n await downloadFile(extra.url, path.join(modelsDir, extra.filename))\n }\n }\n\n const filename = formatEntry.url.split('/').pop() ?? `${entry.id}.${format}`\n const modelPath = path.join(modelsDir, filename)\n\n if (fs.existsSync(modelPath)) {\n if (formatEntry.isDirectory && !fs.existsSync(path.join(modelPath, 'Manifest.json'))) {\n // Stale half-downloaded mlpackage — wipe and re-fetch.\n fs.rmSync(modelPath, { recursive: true, force: true })\n } else {\n return modelPath\n }\n }\n\n fs.mkdirSync(modelsDir, { recursive: true })\n\n if (formatEntry.isDirectory) {\n await downloadDirectory(formatEntry.url, modelPath, formatEntry.files, onProgress)\n } else {\n await downloadFile(formatEntry.url, modelPath, (downloaded, total) =>\n onProgress?.(downloaded, total === 0 ? undefined : total),\n )\n }\n\n return modelPath\n}\n\n/** Compute the on-disk path for a given model + format, even when not yet downloaded. */\nexport function getModelFilePath(\n modelsDir: string,\n entry: ModelCatalogEntry,\n format: ModelFormat,\n): string | null {\n const formatEntry = entry.formats[format]\n if (!formatEntry) return null\n const filename = formatEntry.url.split('/').pop() ?? `${entry.id}.${format}`\n return path.join(modelsDir, filename)\n}\n\n/** True iff the model file (or `Manifest.json` for directory bundles) exists and is non-empty. */\nexport function isModelDownloaded(\n modelsDir: string,\n entry: ModelCatalogEntry,\n format: ModelFormat,\n): boolean {\n const formatEntry = entry.formats[format]\n if (!formatEntry) return false\n const modelPath = getModelFilePath(modelsDir, entry, format)\n if (!modelPath || !fs.existsSync(modelPath)) return false\n if (formatEntry.isDirectory) return fs.existsSync(path.join(modelPath, 'Manifest.json'))\n return fs.statSync(modelPath).size > 0\n}\n\n/** Remove the on-disk model file/directory. Returns true if something was deleted. */\nexport function deleteModelFromDisk(\n modelsDir: string,\n entry: ModelCatalogEntry,\n format: ModelFormat,\n): boolean {\n const modelPath = getModelFilePath(modelsDir, entry, format)\n if (!modelPath || !fs.existsSync(modelPath)) return false\n const formatEntry = entry.formats[format]\n if (formatEntry?.isDirectory) {\n fs.rmSync(modelPath, { recursive: true, force: true })\n } else {\n fs.unlinkSync(modelPath)\n }\n return true\n}\n","import type { ModelCatalogEntry, ModelFormat, IAddonModelManager } from '@camstack/types'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { downloadFile, fetchJson } from './model-downloader.js'\n\n/**\n * Unified model download service.\n *\n * Handles downloading model files and extra files (labels, dicts) from a\n * catalog of ModelCatalogEntry items. Supports single-file models and\n * directory bundles (e.g., .mlpackage for CoreML).\n *\n * Addons use this via `context.models.ensure(modelId, format)`.\n */\nexport class ModelDownloadService implements IAddonModelManager {\n private readonly catalog: ReadonlyMap<string, ModelCatalogEntry>\n\n constructor(\n private readonly modelsDir: string,\n catalog: readonly ModelCatalogEntry[],\n private readonly onProgress?: (modelId: string, downloaded: number, total: number) => void,\n ) {\n const map = new Map<string, ModelCatalogEntry>()\n for (const entry of catalog) {\n map.set(entry.id, entry)\n }\n this.catalog = map\n }\n\n /**\n * Ensure a model (and its extra files) is downloaded.\n * Returns the local filesystem path to the model file/directory.\n */\n async ensure(modelId: string, format?: ModelFormat): Promise<string> {\n const entry = this.catalog.get(modelId)\n if (!entry) {\n throw new Error(`ModelDownloadService: unknown model \"${modelId}\"`)\n }\n\n // Resolve format: use provided or pick first available\n const selectedFormat = format ?? this.pickDefaultFormat(entry)\n const formatEntry = entry.formats[selectedFormat]\n if (!formatEntry) {\n throw new Error(\n `ModelDownloadService: model \"${modelId}\" has no ${selectedFormat} format`,\n )\n }\n\n // Download extra files first (labels JSON, dict.txt, etc.)\n await this.ensureExtraFiles(modelId)\n\n // Derive local path from URL\n const modelPath = this.modelFilePath(entry, selectedFormat)\n\n if (fs.existsSync(modelPath)) {\n // Validate directory bundles have required Manifest.json\n if (formatEntry.isDirectory) {\n if (!fs.existsSync(path.join(modelPath, 'Manifest.json'))) {\n fs.rmSync(modelPath, { recursive: true, force: true })\n } else {\n return modelPath\n }\n } else {\n return modelPath\n }\n }\n\n fs.mkdirSync(this.modelsDir, { recursive: true })\n\n if (formatEntry.isDirectory) {\n await this.downloadDirectory(\n formatEntry.url,\n modelPath,\n formatEntry.files,\n modelId,\n )\n } else {\n await downloadFile(\n formatEntry.url,\n modelPath,\n this.onProgress\n ? (downloaded, total) => this.onProgress!(modelId, downloaded, total)\n : undefined,\n )\n }\n\n return modelPath\n }\n\n /**\n * Ensure extra files for a model are downloaded.\n * Returns the local paths of all extra files.\n */\n async ensureExtraFiles(modelId: string): Promise<readonly string[]> {\n const entry = this.catalog.get(modelId)\n if (!entry) {\n throw new Error(`ModelDownloadService: unknown model \"${modelId}\"`)\n }\n\n const extras = entry.extraFiles\n if (!extras || extras.length === 0) return []\n\n const paths: string[] = []\n for (const extra of extras) {\n const destPath = path.join(this.modelsDir, extra.filename)\n await downloadFile(extra.url, destPath)\n paths.push(destPath)\n }\n return paths\n }\n\n /** Absolute path to the shared models directory. */\n getModelsDir(): string {\n return this.modelsDir\n }\n\n /** Check if a model file is already present on disk. */\n isDownloaded(modelId: string, format?: ModelFormat): boolean {\n const entry = this.catalog.get(modelId)\n if (!entry) return false\n\n const selectedFormat = format ?? this.pickDefaultFormat(entry)\n const formatEntry = entry.formats[selectedFormat]\n if (!formatEntry) return false\n\n const modelPath = this.modelFilePath(entry, selectedFormat)\n if (!fs.existsSync(modelPath)) return false\n\n // Validate directory bundles\n if (formatEntry.isDirectory) {\n return fs.existsSync(path.join(modelPath, 'Manifest.json'))\n }\n\n return fs.statSync(modelPath).size > 0\n }\n\n /** Get the catalog entry for a model by ID. */\n getEntry(modelId: string): ModelCatalogEntry | undefined {\n return this.catalog.get(modelId)\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private pickDefaultFormat(entry: ModelCatalogEntry): ModelFormat {\n // Prefer onnx, then others in order\n const priority: ModelFormat[] = ['onnx', 'coreml', 'openvino', 'tflite', 'pt']\n for (const fmt of priority) {\n if (entry.formats[fmt]) return fmt\n }\n // Fallback: first available format\n const first = Object.keys(entry.formats)[0] as ModelFormat | undefined\n if (first) return first\n throw new Error(`ModelDownloadService: model \"${entry.id}\" has no formats`)\n }\n\n private modelFilePath(entry: ModelCatalogEntry, format: ModelFormat): string {\n const formatEntry = entry.formats[format]\n if (!formatEntry) {\n throw new Error(`Model ${entry.id} has no ${format} format`)\n }\n const urlParts = formatEntry.url.split('/')\n const filename = urlParts[urlParts.length - 1] ?? `${entry.id}.${format}`\n return path.join(this.modelsDir, filename)\n }\n\n /**\n * Download a directory bundle (e.g., .mlpackage) from HuggingFace.\n * ATOMIC: downloads to temp dir, renames only on complete success.\n */\n private async downloadDirectory(\n url: string,\n destDir: string,\n knownFiles?: readonly string[],\n _modelId?: string,\n ): Promise<void> {\n const match = url.match(/huggingface\\.co\\/([^/]+\\/[^/]+)\\/resolve\\/main\\/(.+)/)\n if (!match) throw new Error(`Cannot parse HuggingFace URL: ${url}`)\n\n const [, repo, dirPath] = match\n\n let filesToDownload: Array<{ relativePath: string; fileUrl: string }>\n\n if (knownFiles && knownFiles.length > 0) {\n filesToDownload = knownFiles.map(f => ({\n relativePath: f,\n fileUrl: `https://huggingface.co/${repo}/resolve/main/${dirPath}/${f}`,\n }))\n } else {\n const hfFiles = await this.listHfFiles(repo!, dirPath!)\n if (hfFiles.length === 0) {\n throw new Error(`No files found in HuggingFace directory: ${dirPath}`)\n }\n filesToDownload = hfFiles.map(f => ({\n relativePath: f.path.substring(dirPath!.length + 1),\n fileUrl: `https://huggingface.co/${repo}/resolve/main/${f.path}`,\n }))\n }\n\n const tmpDir = destDir + '.downloading'\n fs.rmSync(tmpDir, { recursive: true, force: true })\n fs.mkdirSync(tmpDir, { recursive: true })\n\n try {\n for (const file of filesToDownload) {\n const destPath = path.join(tmpDir, file.relativePath)\n fs.mkdirSync(path.dirname(destPath), { recursive: true })\n await downloadFile(file.fileUrl, destPath)\n }\n\n fs.rmSync(destDir, { recursive: true, force: true })\n fs.renameSync(tmpDir, destDir)\n } catch (err) {\n fs.rmSync(tmpDir, { recursive: true, force: true })\n throw err\n }\n }\n\n /** Recursively list all files in a HuggingFace directory via API. */\n private async listHfFiles(\n repo: string,\n dirPath: string,\n ): Promise<Array<{ path: string; size: number }>> {\n const apiUrl = `https://huggingface.co/api/models/${repo}/tree/main/${dirPath}`\n const entries = (await fetchJson(apiUrl)) as ReadonlyArray<{\n readonly type: string\n readonly path: string\n readonly size?: number\n readonly lfs?: { readonly size: number }\n }>\n const files: Array<{ path: string; size: number }> = []\n\n for (const entry of entries) {\n if (entry.type === 'file') {\n files.push({ path: entry.path, size: entry.size ?? entry.lfs?.size ?? 0 })\n } else if (entry.type === 'directory') {\n const subFiles = await this.listHfFiles(repo, entry.path)\n files.push(...subFiles)\n }\n }\n\n return files\n }\n}\n","import type { IPythonEnvironment, PythonProbeResult, PythonEnvReady } from '@camstack/types'\nimport { execFile, spawn } from 'node:child_process'\nimport type { ChildProcess } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\n\nconst execFileAsync = promisify(execFile)\n\nexport class PythonEnvManager implements IPythonEnvironment {\n private venvPath: string\n private cachedProbe: PythonProbeResult | null = null\n\n constructor(dataDir: string) {\n this.venvPath = path.join(dataDir, '.venv')\n }\n\n async probe(): Promise<PythonProbeResult> {\n if (this.cachedProbe) return this.cachedProbe\n\n // Try python3, then python\n for (const cmd of ['python3', 'python']) {\n try {\n const { stdout } = await execFileAsync(cmd, ['--version'])\n const version = stdout.trim().replace('Python ', '')\n const major = parseInt(version.split('.')[0] ?? '0', 10)\n const minor = parseInt(version.split('.')[1] ?? '0', 10)\n\n if (major < 3 || (major === 3 && minor < 10)) continue\n\n // Get path\n const { stdout: pathOut } = await execFileAsync(cmd, ['-c', 'import sys; print(sys.executable)'])\n\n this.cachedProbe = {\n available: true,\n version,\n path: pathOut.trim(),\n }\n return this.cachedProbe\n } catch { continue }\n }\n\n this.cachedProbe = { available: false }\n return this.cachedProbe\n }\n\n async ensure(options: { packages: readonly string[] }): Promise<PythonEnvReady> {\n const probe = await this.probe()\n if (!probe.available || !probe.path) {\n throw new Error('Python 3.10+ is required but not found on this system')\n }\n\n // Create venv if needed\n if (!fs.existsSync(path.join(this.venvPath, 'bin', 'python'))) {\n await execFileAsync(probe.path, ['-m', 'venv', this.venvPath])\n }\n\n const venvPython = path.join(this.venvPath, 'bin', 'python')\n\n // Install packages\n if (options.packages.length > 0) {\n await execFileAsync(venvPython, ['-m', 'pip', 'install', '-q', ...options.packages])\n }\n\n return {\n pythonPath: venvPython,\n venvPath: this.venvPath,\n spawn: (script: string, args: readonly string[]) => {\n return spawn(venvPython, [script, ...args])\n },\n }\n }\n\n spawn(script: string, args: readonly string[]): ChildProcess {\n const venvPython = path.join(this.venvPath, 'bin', 'python')\n if (!fs.existsSync(venvPython)) {\n throw new Error('Python venv not initialized. Call ensure() first.')\n }\n return spawn(venvPython, [script, ...args])\n }\n}\n","import type { PipelineConfig, PipelineNode, ValidationIssue, ValidationResult } from '@camstack/types'\n\nexport type { ValidationIssue, ValidationResult }\n\n/**\n * Check if a pipeline step is available in the system.\n * Implementations should check the capability registry for `pipeline-step:{stepId}`.\n */\nexport type StepExistsFn = (stepId: string) => boolean\n\nexport class PipelineValidator {\n constructor(private readonly stepExists: StepExistsFn) {}\n\n validate(config: PipelineConfig): ValidationResult {\n const errors: ValidationIssue[] = []\n const warnings: ValidationIssue[] = []\n\n for (const node of config.video) {\n this.validateNode(node, errors, warnings)\n }\n\n if (config.audio) {\n this.validateNode(config.audio, errors, warnings)\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n }\n }\n\n private validateNode(\n node: PipelineNode,\n errors: ValidationIssue[],\n warnings: ValidationIssue[],\n ): void {\n if (!this.stepExists(node.addon)) {\n errors.push({\n step: node.step,\n addon: node.addon,\n message: `Step \"${node.addon}\" has no provider — the addon that provided it may have been removed`,\n severity: 'error',\n })\n return\n }\n\n if (node.children) {\n for (const child of node.children) {\n this.validateNode(child, errors, warnings)\n }\n }\n }\n}\n","import type {\n FrameInput,\n CropInput,\n PipelineConfig,\n PipelineNode,\n PipelineResult,\n StepResult,\n SpatialDetection,\n PipelineSlot,\n IAddonResolver,\n InferenceOutput,\n} from '@camstack/types'\nimport { randomUUID } from 'node:crypto'\nimport { errMsg } from '@camstack/types'\n\nexport class PipelineRunner {\n constructor(\n private readonly addonResolver: IAddonResolver,\n ) {}\n\n async run(frame: FrameInput, config: PipelineConfig): Promise<PipelineResult> {\n const startTime = performance.now()\n const results: StepResult[] = []\n const timings: Record<string, number> = {}\n\n // Execute video pipeline root nodes\n for (const rootNode of config.video) {\n await this.executeNode(rootNode, frame, null, results, timings)\n }\n\n // Execute audio node if present (independent)\n if (config.audio) {\n await this.executeNode(config.audio, frame, null, results, timings)\n }\n\n return {\n results,\n totalMs: performance.now() - startTime,\n timings,\n frameTimestamp: frame.timestamp,\n }\n }\n private async executeNode(\n node: PipelineNode,\n frame: FrameInput,\n parentDetection: { det: SpatialDetection; resultId: string } | null,\n results: StepResult[],\n timings: Record<string, number>,\n ): Promise<void> {\n const resultId = randomUUID()\n const stepStart = performance.now()\n\n try {\n // Resolve addon caller via the resolver\n const effectiveConfig = { ...node.configOverride }\n const caller = await this.addonResolver.resolve(node.addon, effectiveConfig)\n\n // Unified interface: always call process() with the appropriate input.\n // - Root nodes: FrameInput (full frame)\n // - Child nodes: CropInput (region from parent detection)\n // The addon determines output type (detections/crops/classifications/mask)\n // based on its slot — the runner doesn't need to know.\n let output: InferenceOutput\n\n if (parentDetection) {\n const cropInput: CropInput = {\n frame,\n roi: parentDetection.det.bbox,\n parentDetection: parentDetection.det,\n }\n output = await caller.process(cropInput)\n } else {\n output = await caller.process(frame)\n }\n\n const stepMs = performance.now() - stepStart\n\n // Determine slot type from output shape\n const slot: PipelineSlot =\n 'detections' in output ? 'detector' :\n 'crops' in output ? 'cropper' :\n 'classifier'\n\n const stepResult: StepResult = {\n addon: node.addon,\n slot,\n output,\n parentResultId: parentDetection?.resultId,\n resultId,\n inferenceMs: output.inferenceMs,\n preprocessMs: 0,\n totalMs: stepMs,\n }\n results.push(stepResult)\n timings[node.step] = stepMs\n\n // Process children\n if (node.children?.length) {\n const detections: readonly SpatialDetection[] =\n 'detections' in output ? output.detections :\n 'crops' in output ? output.crops :\n []\n\n // For each detection, find children with matching inputClasses and execute\n await this.executeChildren(node.children, frame, detections, resultId, results, timings)\n }\n } catch (error: unknown) {\n const stepMs = performance.now() - stepStart\n const message = errMsg(error)\n results.push({\n addon: node.addon,\n slot: 'detector',\n output: { detections: [], inferenceMs: 0, modelId: '' },\n parentResultId: parentDetection?.resultId,\n resultId,\n inferenceMs: 0,\n preprocessMs: 0,\n totalMs: stepMs,\n error: {\n code: 'ADDON_ERROR',\n message,\n childrenSkipped: true,\n },\n })\n }\n }\n\n private async executeChildren(\n children: readonly PipelineNode[],\n frame: FrameInput,\n parentDetections: readonly SpatialDetection[],\n parentResultId: string,\n results: StepResult[],\n timings: Record<string, number>,\n ): Promise<void> {\n // For each parent detection, run all matching children in parallel\n const promises: Promise<void>[] = []\n\n for (const detection of parentDetections) {\n // Skip detections with degenerate bounding boxes\n if (detection.bbox.w < 1 || detection.bbox.h < 1) continue\n\n for (const child of children) {\n // TODO: Check inputClasses matching from addon manifest\n // For now, run all children on all detections (caller configures tree correctly)\n promises.push(\n this.executeNode(child, frame, { det: detection, resultId: parentResultId }, results, timings),\n )\n }\n }\n\n await Promise.allSettled(promises)\n }\n}\n","import type {\n IAddonResolver,\n IAddonCaller,\n IEngineManager,\n InferenceOutput,\n FrameInput,\n CropInput,\n} from '@camstack/types'\n\n/**\n * Adapter that wraps an IEngineManager + addonConfigs as an IAddonResolver.\n *\n * Used for backwards compatibility — the in-process AddonEngineManager\n * still uses the old getOrCreateEngine(addonId, globalConfig, override) API.\n * This adapter bridges it to the new resolve(addonId, config) interface.\n */\nexport class EngineManagerResolver implements IAddonResolver {\n constructor(\n private readonly engineManager: IEngineManager,\n private readonly addonConfigs: Map<string, Record<string, unknown>>,\n ) {}\n\n async resolve(addonId: string, config: Record<string, unknown>): Promise<IAddonCaller> {\n const globalConfig = this.addonConfigs.get(addonId) ?? {}\n const engine = await this.engineManager.getOrCreateEngine(addonId, globalConfig, config)\n\n return {\n process: async (input: FrameInput | CropInput): Promise<InferenceOutput> => {\n return engine.process(input as FrameInput)\n },\n }\n }\n\n async shutdownAll(): Promise<void> {\n await this.engineManager.shutdownAll()\n }\n}\n","import type {\n StreamNetworkStats,\n ClientNetworkStats,\n DeviceNetworkStats,\n INetworkQualityTracker,\n} from '@camstack/types'\n\nexport type {\n StreamNetworkStats,\n ClientNetworkStats,\n DeviceNetworkStats,\n INetworkQualityTracker,\n}\n\ninterface MutableStreamStats {\n nominalBitrateKbps: number\n samples: number[]\n peakBitrateKbps: number\n packetLossSamples: number[]\n lastUpdated: number\n}\n\nexport class NetworkQualityTracker implements INetworkQualityTracker {\n private readonly devices = new Map<number, {\n streams: Map<string, MutableStreamStats>\n client: (ClientNetworkStats & { lastUpdated: number }) | null\n }>()\n\n private static readonly MAX_SAMPLES = 30 // ~5 min at 10s reporting interval\n\n reportStreamStats(deviceId: number, streamId: string, bitrateKbps: number, packetLoss?: number): void {\n const device = this.getOrCreateDevice(deviceId)\n let stream = device.streams.get(streamId)\n if (!stream) {\n stream = { nominalBitrateKbps: bitrateKbps, samples: [], peakBitrateKbps: 0, packetLossSamples: [], lastUpdated: 0 }\n device.streams.set(streamId, stream)\n }\n\n stream.samples.push(bitrateKbps)\n if (stream.samples.length > NetworkQualityTracker.MAX_SAMPLES) stream.samples.shift()\n\n stream.peakBitrateKbps = Math.max(stream.peakBitrateKbps, bitrateKbps)\n\n if (packetLoss !== undefined) {\n stream.packetLossSamples.push(packetLoss)\n if (stream.packetLossSamples.length > NetworkQualityTracker.MAX_SAMPLES) stream.packetLossSamples.shift()\n }\n\n stream.lastUpdated = Date.now()\n }\n\n reportClientStats(deviceId: number, stats: Omit<ClientNetworkStats, 'lastUpdated'>): void {\n const device = this.getOrCreateDevice(deviceId)\n device.client = { ...stats, lastUpdated: Date.now() }\n }\n\n getDeviceStats(deviceId: number): DeviceNetworkStats | null {\n const device = this.devices.get(deviceId)\n if (!device) return null\n\n const streams: Record<string, StreamNetworkStats> = {}\n for (const [streamId, s] of device.streams) {\n const avg = (arr: number[]) => arr.length === 0 ? 0 : arr.reduce((a, b) => a + b, 0) / arr.length\n streams[streamId] = {\n nominalBitrateKbps: s.nominalBitrateKbps,\n observedBitrateKbps: Math.round(avg(s.samples)),\n peakBitrateKbps: s.peakBitrateKbps,\n packetLossPercent: Math.round(avg(s.packetLossSamples) * 10) / 10,\n lastUpdated: s.lastUpdated,\n }\n }\n\n return { deviceId, streams, client: device.client ?? undefined }\n }\n\n getAllStats(): readonly DeviceNetworkStats[] {\n const results: DeviceNetworkStats[] = []\n for (const deviceId of this.devices.keys()) {\n const stats = this.getDeviceStats(deviceId)\n if (stats) results.push(stats)\n }\n return results\n }\n\n private getOrCreateDevice(deviceId: number) {\n let device = this.devices.get(deviceId)\n if (!device) {\n device = { streams: new Map(), client: null }\n this.devices.set(deviceId, device)\n }\n return device\n }\n}\n","import * as vm from 'node:vm'\nimport * as util from 'node:util'\nimport type {\n IReplEngine,\n IReplContextProvider,\n ReplSessionContext,\n ReplResult,\n} from './interfaces.js'\n\nconst EXECUTION_TIMEOUT_MS = 5000\nconst COMPLETION_TIMEOUT_MS = 1000\n\nexport class ReplEngine implements IReplEngine {\n constructor(\n private readonly contextProvider: IReplContextProvider,\n ) {}\n\n async execute(code: string, context: ReplSessionContext): Promise<ReplResult> {\n const start = Date.now()\n const sandbox = await this.buildSandbox(context)\n\n try {\n const vmContext = vm.createContext(sandbox)\n const script = new vm.Script(code)\n let result: unknown = script.runInContext(vmContext, { timeout: EXECUTION_TIMEOUT_MS })\n\n // If result is a Promise, await it with timeout\n if (result && typeof result === 'object' && 'then' in result && typeof (result as { then: unknown }).then === 'function') {\n result = await Promise.race([\n result as Promise<unknown>,\n new Promise((_, reject) =>\n setTimeout(() => reject(new Error('Async timeout (5s)')), EXECUTION_TIMEOUT_MS),\n ),\n ])\n }\n\n const duration = Date.now() - start\n\n if (result === undefined) {\n return { output: 'undefined', type: 'void', duration }\n }\n\n return {\n output: util.inspect(result, {\n depth: 4,\n colors: false,\n maxArrayLength: 50,\n maxStringLength: 1000,\n }),\n type: 'value',\n duration,\n }\n } catch (err: unknown) {\n // Errors thrown inside vm contexts may not be instanceof Error\n // because they use a different Error constructor from the sandbox\n const message =\n err instanceof Error\n ? err.message\n : typeof err === 'object' && err !== null && 'message' in err\n ? String((err as { message: unknown }).message)\n : String(err)\n return {\n output: message,\n type: 'error',\n duration: Date.now() - start,\n }\n }\n }\n\n async getCompletions(partial: string, context: ReplSessionContext): Promise<string[]> {\n const sandbox = await this.buildSandbox(context)\n const keys = Object.keys(sandbox)\n\n if (!partial) return keys\n\n const lastDot = partial.lastIndexOf('.')\n if (lastDot === -1) {\n return keys.filter(k => k.startsWith(partial))\n }\n\n // Object property completion: \"device.get\" -> look up device, return matching keys\n const objPath = partial.substring(0, lastDot)\n const propPrefix = partial.substring(lastDot + 1)\n\n try {\n const vmContext = vm.createContext(sandbox)\n const obj: unknown = vm.runInContext(objPath, vmContext, { timeout: COMPLETION_TIMEOUT_MS })\n if (obj && typeof obj === 'object') {\n const proto: unknown = Object.getPrototypeOf(obj)\n const objKeys = Object.getOwnPropertyNames(obj)\n .concat(Object.getOwnPropertyNames(proto ?? {}))\n .filter(k => k.startsWith(propPrefix))\n return [...new Set(objKeys)].map(k => `${objPath}.${k}`)\n }\n } catch {\n // Ignore errors during completion\n }\n\n return []\n }\n\n private async buildSandbox(context: ReplSessionContext): Promise<Record<string, unknown>> {\n const base: Record<string, unknown> = {\n console: {\n log: (...args: unknown[]) => util.inspect(args),\n warn: (...args: unknown[]) => util.inspect(args),\n },\n JSON,\n Math,\n Date,\n Array,\n Object,\n String,\n Number,\n Boolean,\n Map,\n Set,\n Promise,\n Buffer,\n // Blocked globals\n setTimeout: undefined,\n setInterval: undefined,\n fetch: undefined,\n require: undefined,\n process: undefined,\n // Merge user-provided variables\n ...context.variables,\n }\n\n switch (context.scope.type) {\n case 'system':\n return { ...base, ...(await this.contextProvider.getSystemSandbox()) }\n\n case 'device':\n return { ...base, ...(await this.contextProvider.getDeviceSandbox(context.scope.deviceId!)) }\n\n case 'provider':\n return { ...base, ...(await this.contextProvider.getProviderSandbox(context.scope.providerId!)) }\n\n case 'addon':\n return { ...base, ...(await this.contextProvider.getAddonSandbox(context.scope.addonId!)) }\n\n default:\n return base\n }\n }\n}\n","// FilesystemStorageProvider lives in `@camstack/types/node` since 2026-05\n// (kernel ↔ core cycle break). Re-export for backward compat.\nexport { FilesystemStorageProvider } from '@camstack/types/node'\nexport { FilesystemStorageAddon } from './filesystem-storage.addon.js'\nexport { SqliteSettingsBackend } from './sqlite-settings-backend.js'\nexport { SqliteSettingsAddon } from './sqlite-settings.addon.js'\nexport { SettingsStore } from './settings-store.js'\nexport { CORE_TABLE_DDL, addonTableToDdl } from './sql-schema.js'\nexport type { AddonTableSchema } from './sql-schema.js'\nexport { DeviceStore } from './device-store.js'\nexport type { DeviceRow } from './device-store.js'\nexport { ConfigStore } from './config-store.js'\n\n// Default export for AddonLoader\nexport { FilesystemStorageAddon as default } from './filesystem-storage.addon.js'\n","import type {\n StorageLocationType,\n ProviderRegistration,\n} from '@camstack/types'\nimport { BaseAddon, storageCapability } from '@camstack/types'\nimport { FilesystemStorageProvider } from '@camstack/types/node'\n\ninterface FilesystemStorageConfig {\n readonly rootPath: string\n}\n\n/**\n * Filesystem Storage addon — provides local disk storage for all location types.\n * Capability: 'storage' (collection)\n */\nexport class FilesystemStorageAddon extends BaseAddon<FilesystemStorageConfig> {\n private provider: FilesystemStorageProvider | null = null\n\n constructor() {\n super({ rootPath: 'camstack-data' })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const rootPath = (this.ctx.addonConfig as Record<string, unknown>).rootPath as string | undefined ?? this.config.rootPath\n\n const overrides: Partial<Record<StorageLocationType, string>> = {}\n const addonCfg = this.ctx.addonConfig as Record<string, unknown>\n for (const key of Object.keys(addonCfg)) {\n if (key.startsWith('override.')) {\n const loc = key.slice('override.'.length) as StorageLocationType\n overrides[loc] = addonCfg[key] as string\n }\n }\n\n this.provider = new FilesystemStorageProvider(rootPath, overrides)\n this.ctx.logger.info('Filesystem storage initialized', { meta: { rootPath: this.provider.getRootPath() } })\n return [{ capability: storageCapability, provider: this.provider }]\n }\n\n protected async onShutdown(): Promise<void> {\n this.provider = null\n }\n\n getProvider(): FilesystemStorageProvider | null {\n return this.provider\n }\n}\n\nexport default FilesystemStorageAddon\n","import Database from 'better-sqlite3'\nimport { randomUUID } from 'node:crypto'\nimport type {\n ISettingsBackend,\n SettingsRecord,\n TableSchema,\n TableQueryOptions,\n SettingsGetInput,\n SettingsSetInput,\n SettingsQueryInput,\n SettingsInsertInput,\n SettingsUpdateInput,\n SettingsDeleteInput,\n SettingsCountInput,\n SettingsIsEmptyInput,\n CollectionColumn,\n CollectionIndex,\n} from '@camstack/types'\nimport { asJsonObject, parseJsonUnknown } from '@camstack/types'\n\nfunction parseRowData(raw: string): Record<string, unknown> {\n return asJsonObject(parseJsonUnknown(raw)) ?? {}\n}\n\n/**\n * SQLite implementation of ISettingsBackend.\n *\n * Every collection is structured: declared at boot (canonical KV\n * collections) or via `declareCollection` (typed schemas like\n * `pipeline-analytics:tracks`). The legacy auto-create-on-first-access\n * path was removed — see commit history for the migration. Operations\n * on undeclared collections throw at runtime so callers fail fast.\n *\n * WAL mode for concurrent reads.\n */\nexport class SqliteSettingsBackend implements ISettingsBackend {\n private db: Database.Database | null = null\n private readonly structuredTables = new Set<string>()\n /** Map from scoped collection name → set of column names (non-id) that\n * the structured schema owns. Routes set/get/insert/update/query to\n * typed columns. Every collection MUST be declared here before use. */\n private readonly declaredCollections = new Map<string, { readonly primaryKey: string; readonly columns: ReadonlySet<string> }>()\n private readonly runtimeDefaults: Record<string, unknown>\n\n /**\n * Canonical key/value collections — declared with a `(id TEXT PK,\n * data TEXT NOT NULL)` schema at boot so existing JSON-blob rows\n * keep working through the structured path. Generates SQL identical\n * to the previous legacy path; only the routing is unified.\n */\n private static readonly CANONICAL_KV_COLLECTIONS: readonly string[] = [\n 'system-settings',\n 'addon-settings',\n 'addon-device-settings',\n 'addon-devices',\n 'device-runtime-state',\n 'sections',\n 'provider-settings',\n 'device-settings',\n 'alerts',\n ]\n\n // Domain schemas (auth, analytics events, …) live in the addons that\n // own them — same pattern as `pipeline-analytics` (`event-store.ts`,\n // `track-store.ts`, `media-store.ts`) and `local-auth` (`auth-schema.ts`).\n // The backend exposes `declareCollection` and stays out of domain\n // knowledge.\n\n constructor(private readonly dbPath: string, runtimeDefaults?: Record<string, unknown>) {\n this.runtimeDefaults = runtimeDefaults ?? {}\n }\n\n async initialize(): Promise<void> {\n // Ensure parent directory exists\n const dir = this.dbPath.substring(0, this.dbPath.lastIndexOf('/'))\n if (dir) {\n const fs = await import('node:fs')\n fs.mkdirSync(dir, { recursive: true })\n }\n this.db = new Database(this.dbPath)\n this.db.pragma('journal_mode = WAL')\n this.db.pragma('foreign_keys = ON')\n\n // Declare canonical KV collections so set/get/insert/update/query\n // reach the structured path uniformly. Schema is the same shape\n // legacy created on demand — `(id TEXT PK, data TEXT NOT NULL)` —\n // so existing rows continue to work with no migration.\n for (const collection of SqliteSettingsBackend.CANONICAL_KV_COLLECTIONS) {\n await this.ensureTable(collection, {\n columns: [\n { name: 'id', type: 'TEXT', primaryKey: true, notNull: true },\n { name: 'data', type: 'TEXT', notNull: true },\n ],\n })\n this.declaredCollections.set(collection, {\n primaryKey: 'id',\n columns: new Set(['data']),\n })\n }\n\n // Seed system-settings on first boot\n const isEmpty = await this.isEmpty({ collection: 'system-settings' })\n if (isEmpty) {\n await this.seedDefaults()\n }\n }\n\n private requireDeclared(scoped: string): { readonly primaryKey: string; readonly columns: ReadonlySet<string> } {\n const decl = this.declaredCollections.get(scoped)\n if (!decl) {\n throw new Error(`SqliteSettingsBackend: collection \"${scoped}\" is not declared. Call declareCollection() first or add it to CANONICAL_KV_COLLECTIONS.`)\n }\n return decl\n }\n\n async shutdown(): Promise<void> {\n this.db?.close()\n this.db = null\n }\n\n // ---------------------------------------------------------------------------\n // ISettingsBackend implementation\n // ---------------------------------------------------------------------------\n\n async get({ namespace, collection, key }: SettingsGetInput): Promise<unknown> {\n const scoped = this.scopedName(namespace, collection)\n const decl = this.requireDeclared(scoped)\n // Canonical KV collections store the value as a single `data`\n // JSON-blob column; their declared columns are exactly `['data']`\n // so we read it back, parse, and return. Structured collections\n // (multi-column) return the row map untouched.\n const cols = [`\"${decl.primaryKey}\"`, ...[...decl.columns].map(c => `\"${c}\"`)].join(', ')\n const row = this.getDb()\n .prepare<[string], Record<string, unknown>>(`SELECT ${cols} FROM \"${scoped}\" WHERE \"${decl.primaryKey}\" = ?`)\n .get(key)\n if (!row) return undefined\n if (decl.columns.size === 1 && decl.columns.has('data')) {\n const raw = row['data']\n return typeof raw === 'string' ? JSON.parse(raw) : raw\n }\n const data: Record<string, unknown> = {}\n for (const c of decl.columns) {\n const v = row[c]\n if (typeof v === 'string' && (v.startsWith('{') || v.startsWith('['))) {\n try { data[c] = JSON.parse(v) } catch { data[c] = v }\n } else {\n data[c] = v ?? null\n }\n }\n return data\n }\n\n async set({ namespace, collection, key, value }: SettingsSetInput): Promise<void> {\n const scoped = this.scopedName(namespace, collection)\n const decl = this.requireDeclared(scoped)\n // Build the column row. KV-shape collections (`['data']`) store\n // `value` as a JSON blob in `data`; structured collections\n // destructure `value` into its declared columns.\n const row: Record<string, unknown> = { [decl.primaryKey]: key }\n if (decl.columns.size === 1 && decl.columns.has('data')) {\n row['data'] = JSON.stringify(value)\n } else {\n const valueObj = (value !== null && typeof value === 'object' ? value : {}) as Record<string, unknown>\n for (const [k, v] of Object.entries(valueObj)) {\n if (decl.columns.has(k)) row[k] = this.serializeColumnValue(v)\n }\n }\n const keys = Object.keys(row)\n const cols = keys.map(k => `\"${k}\"`).join(', ')\n const placeholders = keys.map(() => '?').join(', ')\n const updates = keys\n .filter(k => k !== decl.primaryKey)\n .map(k => `\"${k}\" = excluded.\"${k}\"`)\n .join(', ')\n const values = keys.map(k => row[k])\n const sql = updates.length > 0\n ? `INSERT INTO \"${scoped}\" (${cols}) VALUES (${placeholders}) ON CONFLICT(\"${decl.primaryKey}\") DO UPDATE SET ${updates}`\n : `INSERT INTO \"${scoped}\" (${cols}) VALUES (${placeholders}) ON CONFLICT(\"${decl.primaryKey}\") DO NOTHING`\n this.getDb().prepare(sql).run(...values)\n }\n\n async query<T extends object = Record<string, unknown>>(\n { namespace, collection, filter }: SettingsQueryInput,\n ): Promise<readonly SettingsRecord<T>[]> {\n const scoped = this.scopedName(namespace, collection)\n const decl = this.requireDeclared(scoped)\n return this.queryDeclared<T>(scoped, decl, filter)\n }\n\n async insert<T extends object = Record<string, unknown>>({ namespace, collection, record }: SettingsInsertInput<T>): Promise<void> {\n const scoped = this.scopedName(namespace, collection)\n const decl = this.requireDeclared(scoped)\n const id = record.id || randomUUID()\n const row: Record<string, unknown> = { [decl.primaryKey]: id }\n if (decl.columns.size === 1 && decl.columns.has('data')) {\n row['data'] = JSON.stringify(record.data)\n } else {\n for (const [k, v] of Object.entries(record.data)) {\n if (decl.columns.has(k)) row[k] = this.serializeColumnValue(v)\n }\n }\n await this.tableInsert(scoped, row)\n }\n\n async update({ namespace, collection, id, data }: SettingsUpdateInput): Promise<void> {\n const scoped = this.scopedName(namespace, collection)\n const decl = this.requireDeclared(scoped)\n const updates: Record<string, unknown> = {}\n if (decl.columns.size === 1 && decl.columns.has('data')) {\n updates['data'] = JSON.stringify(data)\n } else {\n for (const [k, v] of Object.entries(data)) {\n if (decl.columns.has(k)) updates[k] = this.serializeColumnValue(v)\n }\n }\n if (Object.keys(updates).length > 0) {\n await this.tableUpdate(scoped, { [decl.primaryKey]: id }, updates)\n }\n }\n\n async delete({ namespace, collection, key }: SettingsDeleteInput): Promise<void> {\n const scoped = this.scopedName(namespace, collection)\n const decl = this.requireDeclared(scoped)\n await this.tableDelete(scoped, { [decl.primaryKey]: key })\n }\n\n async count({ namespace, collection, filter }: SettingsCountInput): Promise<number> {\n const scoped = this.scopedName(namespace, collection)\n const decl = this.requireDeclared(scoped)\n const isKvShape = decl.columns.size === 1 && decl.columns.has('data')\n const isColumn = (f: string): boolean => f === decl.primaryKey || decl.columns.has(f)\n const fieldExpr = (f: string): string => {\n if (isColumn(f)) return `\"${f}\"`\n if (isKvShape) return `json_extract(\"data\", '$.${f}')`\n return ''\n }\n let sql = `SELECT COUNT(*) AS cnt FROM \"${scoped}\"`\n const params: unknown[] = []\n if (filter?.where) {\n const clauses: string[] = []\n for (const [field, value] of Object.entries(filter.where)) {\n const expr = fieldExpr(field)\n if (!expr) continue\n clauses.push(`${expr} = ?`)\n params.push(this.serializeColumnValue(value))\n }\n if (clauses.length > 0) sql += ` WHERE ${clauses.join(' AND ')}`\n }\n const row = this.getDb()\n .prepare<unknown[], { cnt: number }>(sql)\n .get(...params)\n return row?.cnt ?? 0\n }\n\n async isEmpty({ namespace, collection }: SettingsIsEmptyInput): Promise<boolean> {\n const scoped = this.scopedName(namespace, collection)\n this.requireDeclared(scoped)\n return (await this.tableCount(scoped)) === 0\n }\n\n private async queryDeclared<T extends object = Record<string, unknown>>(\n table: string,\n decl: { readonly primaryKey: string; readonly columns: ReadonlySet<string> },\n filter: import('@camstack/types').QueryFilter | undefined,\n ): Promise<readonly SettingsRecord<T>[]> {\n // KV-shape detection: a single `data` JSON-blob column. Canonical\n // collections (users, alerts, api-keys, …) and the catalogue of\n // \"legacy\" collections fall in this branch — the structured per-\n // column path is reserved for explicitly declared schemas.\n const isKvShape = decl.columns.size === 1 && decl.columns.has('data')\n const cols = [`\"${decl.primaryKey}\"`, ...[...decl.columns].map(c => `\"${c}\"`)].join(', ')\n let sql = `SELECT ${cols} FROM \"${table}\"`\n const params: unknown[] = []\n const whereClauses: string[] = []\n\n const isColumn = (f: string): boolean => f === decl.primaryKey || decl.columns.has(f)\n /**\n * SQL expression for `field` on this table.\n * - real column → `\"field\"`\n * - KV blob field (e.g. `username` inside `data`) → `json_extract`\n * - structured table + non-column → empty string (filter dropped,\n * matches legacy structured-table behaviour)\n */\n const fieldExpr = (f: string): string => {\n if (isColumn(f)) return `\"${f}\"`\n if (isKvShape) return `json_extract(\"data\", '$.${f}')`\n return ''\n }\n\n if (filter?.where) {\n for (const [field, value] of Object.entries(filter.where)) {\n const expr = fieldExpr(field)\n if (!expr) continue\n whereClauses.push(`${expr} = ?`)\n params.push(this.serializeColumnValue(value))\n }\n }\n if (filter?.whereIn) {\n for (const [field, values] of Object.entries(filter.whereIn)) {\n const expr = fieldExpr(field)\n if (!expr) continue\n const placeholders = values.map(() => '?').join(', ')\n whereClauses.push(`${expr} IN (${placeholders})`)\n for (const v of values) params.push(this.serializeColumnValue(v))\n }\n }\n if (filter?.whereBetween) {\n for (const [field, [low, high]] of Object.entries(filter.whereBetween)) {\n const expr = fieldExpr(field)\n if (!expr) continue\n whereClauses.push(`${expr} BETWEEN ? AND ?`)\n params.push(this.serializeColumnValue(low), this.serializeColumnValue(high))\n }\n }\n if (whereClauses.length > 0) sql += ` WHERE ${whereClauses.join(' AND ')}`\n\n if (filter?.orderBy) {\n const expr = fieldExpr(filter.orderBy.field)\n if (expr) {\n const dir = filter.orderBy.direction === 'desc' ? 'DESC' : 'ASC'\n sql += ` ORDER BY ${expr} ${dir}`\n }\n }\n if (filter?.limit !== undefined) { sql += ` LIMIT ?`; params.push(filter.limit) }\n if (filter?.offset !== undefined) { sql += ` OFFSET ?`; params.push(filter.offset) }\n\n const rows = this.getDb()\n .prepare<unknown[], Record<string, unknown>>(sql)\n .all(...params)\n return rows.map(r => {\n const id = String(r[decl.primaryKey] ?? '')\n // KV-shape: unwrap the JSON blob so consumers receive\n // `{ id, data: <parsedJSON> }` directly. Without this every caller\n // in the auth chain (UserManager, ScopedTokenManager, …) gets a\n // double-wrapped record (`{ data: { data: <real> } }`) and the\n // schema parse throws on undefined fields.\n if (isKvShape) {\n const v = r['data']\n if (typeof v === 'string' && (v.startsWith('{') || v.startsWith('['))) {\n try {\n return { id, data: JSON.parse(v) as T }\n } catch {\n return { id, data: { value: v } as unknown as T }\n }\n }\n return { id, data: (v == null ? {} : { value: v }) as T }\n }\n // Structured tables: reassemble the record from typed columns and\n // include the primary key field so callers (e.g. `UserRecordSchema.parse`)\n // see the same shape they originally inserted.\n const data: Record<string, unknown> = { [decl.primaryKey]: r[decl.primaryKey] ?? null }\n for (const c of decl.columns) {\n // Auto-deserialize JSON strings back into objects. Heuristic:\n // values starting with `{` or `[` are attempted as JSON.parse,\n // fallback to the raw string on parse failure. This preserves\n // primitive column types (TEXT/INTEGER/REAL) as-is.\n const v = r[c]\n if (typeof v === 'string' && (v.startsWith('{') || v.startsWith('['))) {\n try { data[c] = JSON.parse(v) } catch { data[c] = v }\n } else {\n data[c] = v ?? null\n }\n }\n return { id, data: data as T }\n })\n }\n\n // ---------------------------------------------------------------------------\n // Legacy SettingsStore compatibility (used by ConfigManager.setSettingsStore)\n // ---------------------------------------------------------------------------\n\n /** Get a system setting by dot-notation key */\n getSystem(key: string): unknown {\n this.requireDeclared('system-settings')\n const row = this.getDb()\n .prepare<[string], { data: string }>('SELECT data FROM \"system-settings\" WHERE id = ?')\n .get(key)\n if (!row) return undefined\n return JSON.parse(row.data)\n }\n\n /** Set a system setting */\n setSystem(key: string, value: unknown): void {\n this.requireDeclared('system-settings')\n this.getDb()\n .prepare('INSERT INTO \"system-settings\" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data')\n .run(key, JSON.stringify(value))\n }\n\n /** Get all system settings as flat key-value */\n getAllSystem(): Record<string, unknown> {\n this.requireDeclared('system-settings')\n const rows = this.getDb()\n .prepare<[], { id: string; data: string }>('SELECT id, data FROM \"system-settings\"')\n .all()\n return Object.fromEntries(rows.map(r => [r.id, JSON.parse(r.data)]))\n }\n\n /** Get all settings for an addon */\n getAllAddon(addonId: string): Record<string, unknown> {\n this.requireDeclared('addon-settings')\n const rows = this.getDb()\n .prepare<[string], { id: string; data: string }>('SELECT id, data FROM \"addon-settings\" WHERE json_extract(data, \\'$.addonId\\') = ?')\n .all(addonId)\n if (rows.length === 0) return {}\n // addon-settings stores all keys for an addon as separate rows with id\n // = \"addonId.key\" and data = `{ addonId, key, value }`. Detect the\n // wrapper shape explicitly: a corrupted legacy row that lacks the\n // `value` field would otherwise be returned as the wrapper itself\n // (the previous `parsed.value ?? parsed` fallback masked the bug as a\n // valid value, breaking downstream type-narrowed reads like\n // `pipelineDefaults`). Skip those rows entirely so the caller sees\n // them as missing.\n const result: Record<string, unknown> = {}\n for (const row of rows) {\n const parsed = parseRowData(row.data)\n const key = row.id.startsWith(`${addonId}.`) ? row.id.slice(addonId.length + 1) : row.id\n const isWrapper = parsed !== null\n && typeof parsed === 'object'\n && 'addonId' in parsed\n && 'key' in (parsed as Record<string, unknown>)\n if (isWrapper) {\n const wrapper = parsed as { readonly addonId: string; readonly key: string; readonly value?: unknown }\n if ('value' in wrapper) {\n result[key] = wrapper.value\n }\n // else: corrupted wrapper-without-value — skip\n } else {\n result[key] = parsed\n }\n }\n return result\n }\n\n /** Bulk-set all settings for an addon */\n setAllAddon(addonId: string, config: Record<string, unknown>): void {\n this.requireDeclared('addon-settings')\n const db = this.getDb()\n const deleteStmt = db.prepare('DELETE FROM \"addon-settings\" WHERE id LIKE ? || \\'%\\'')\n const insertStmt = db.prepare('INSERT INTO \"addon-settings\" (id, data) VALUES (?, ?)')\n db.transaction(() => {\n deleteStmt.run(`${addonId}.`)\n for (const [key, value] of Object.entries(config)) {\n // Skip undefined values: the JSON wrapper `{addonId, key, value}`\n // serializes as `{addonId, key}` when value is undefined, which\n // round-trips as a corrupted \"wrapper without value\" row.\n if (value === undefined) continue\n insertStmt.run(`${addonId}.${key}`, JSON.stringify({ addonId, key, value }))\n }\n })()\n }\n\n /** Get all settings for a provider */\n getAllProvider(providerId: string): Record<string, unknown> {\n return this.getAllScoped('provider-settings', providerId)\n }\n\n /** Set a provider setting */\n setProvider(providerId: string, key: string, value: unknown): void {\n this.setScopedKey('provider-settings', providerId, key, value)\n }\n\n /** Get all settings for a device */\n getAllDevice(deviceId: string): Record<string, unknown> {\n return this.getAllScoped('device-settings', deviceId)\n }\n\n /** Set a device setting */\n setDevice(deviceId: string, key: string, value: unknown): void {\n this.setScopedKey('device-settings', deviceId, key, value)\n }\n\n // ── Addon-device settings (per-device overrides of an addon's config) ──\n //\n // Storage key format: \"<addonId>:<deviceId>.<field>\" inside the\n // \"addon-device-settings\" collection. Uses the same JSON-blob layout\n // as the other scoped collections so no schema change is required.\n\n getAddonDevice(addonId: string, deviceId: string): Record<string, unknown> {\n return this.getAllScoped('addon-device-settings', `${addonId}:${deviceId}`)\n }\n\n setAddonDevice(addonId: string, deviceId: string, values: Record<string, unknown>): void {\n this.requireDeclared('addon-device-settings')\n const db = this.getDb()\n const prefix = `${addonId}:${deviceId}.`\n const deleteStmt = db.prepare(`DELETE FROM \"addon-device-settings\" WHERE id LIKE ? || '%'`)\n const insertStmt = db.prepare(\n `INSERT INTO \"addon-device-settings\" (id, data) VALUES (?, ?)\n ON CONFLICT(id) DO UPDATE SET data = excluded.data`,\n )\n db.transaction(() => {\n deleteStmt.run(prefix)\n for (const [key, value] of Object.entries(values)) {\n insertStmt.run(\n `${prefix}${key}`,\n JSON.stringify({ addonId, deviceId, key, value }),\n )\n }\n })()\n }\n\n clearAddonDevice(addonId: string, deviceId: string): void {\n this.requireDeclared('addon-device-settings')\n const prefix = `${addonId}:${deviceId}.`\n this.getDb()\n .prepare(`DELETE FROM \"addon-device-settings\" WHERE id LIKE ? || '%'`)\n .run(prefix)\n }\n\n /** Seed system-settings with runtime defaults (first boot) */\n private async seedDefaults(): Promise<void> {\n this.requireDeclared('system-settings')\n const insert = this.getDb().prepare(\n 'INSERT OR IGNORE INTO \"system-settings\" (id, data) VALUES (?, ?)',\n )\n this.getDb().transaction(() => {\n for (const [key, value] of Object.entries(this.runtimeDefaults)) {\n insert.run(key, JSON.stringify(value))\n }\n })()\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Expose the raw better-sqlite3 Database instance for components that\n * need direct SQL access (e.g. DeviceStore, ConfigStore).\n * Returns null if the backend has not been initialized yet.\n */\n getDatabase(): Database.Database | null {\n return this.db\n }\n\n private getDb(): Database.Database {\n if (!this.db) throw new Error('SqliteSettingsBackend not initialized — call initialize() first')\n return this.db\n }\n\n private getAllScoped(collection: string, scopeId: string): Record<string, unknown> {\n this.requireDeclared(collection)\n const rows = this.getDb()\n .prepare<[string], { id: string; data: string }>(`SELECT id, data FROM \"${collection}\" WHERE id LIKE ? || '.%'`)\n .all(scopeId)\n const result: Record<string, unknown> = {}\n for (const row of rows) {\n const key = row.id.slice(scopeId.length + 1)\n const parsed = parseRowData(row.data)\n result[key] = parsed.value ?? parsed\n }\n return result\n }\n\n private setScopedKey(collection: string, scopeId: string, key: string, value: unknown): void {\n this.requireDeclared(collection)\n this.getDb()\n .prepare(`INSERT INTO \"${collection}\" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data`)\n .run(`${scopeId}.${key}`, JSON.stringify({ scopeId, key, value }))\n }\n\n // ── Declared collections (typed SQL tables behind the generic cap) ──\n\n private scopedName(namespace: string | undefined, collection: string): string {\n return namespace ? `${namespace}:${collection}` : collection\n }\n\n async declareCollection(input: {\n namespace?: string\n collection: string\n columns: readonly CollectionColumn[]\n indexes?: readonly CollectionIndex[]\n }): Promise<void> {\n const table = this.scopedName(input.namespace, input.collection)\n if (this.declaredCollections.has(table)) return\n\n // Ensure id column is explicit — every declared collection needs a\n // primary key that maps to the cap's record.id.\n const hasId = input.columns.some(c => c.primaryKey === true)\n const columns = hasId\n ? input.columns\n : [{ name: 'id', type: 'TEXT' as const, primaryKey: true, notNull: true }, ...input.columns]\n\n // Translate to the TableSchema shape ensureTable expects.\n const schema: TableSchema = {\n columns: columns.map(c => ({\n name: c.name,\n // SQLite treats JSON as TEXT; we serialize object values on write\n // and parse on read.\n type: c.type === 'JSON' ? 'TEXT' : c.type,\n ...(c.primaryKey !== undefined ? { primaryKey: c.primaryKey } : {}),\n ...(c.notNull !== undefined ? { notNull: c.notNull } : {}),\n ...(c.unique !== undefined ? { unique: c.unique } : {}),\n })),\n ...(input.indexes ? { indexes: input.indexes.map(i => ({\n name: i.name,\n columns: i.columns,\n ...(i.unique !== undefined ? { unique: i.unique } : {}),\n })) } : {}),\n }\n await this.ensureTable(table, schema)\n\n const pkCol = columns.find(c => c.primaryKey === true)\n const primaryKey = pkCol ? pkCol.name : 'id'\n const columnNames = new Set(columns.filter(c => c.name !== primaryKey).map(c => c.name))\n this.declaredCollections.set(table, { primaryKey, columns: columnNames })\n }\n\n /** Serialise per-column values for SQL binding: objects → JSON, booleans → 0/1. */\n private serializeColumnValue(v: unknown): unknown {\n if (v === null || v === undefined) return v ?? null\n if (typeof v === 'boolean') return v ? 1 : 0\n if (typeof v === 'object') return JSON.stringify(v)\n return v\n }\n\n // ── Structured table operations ────────────────────────────────────\n\n async ensureTable(table: string, schema: TableSchema): Promise<void> {\n if (this.structuredTables.has(table)) return\n\n const colDefs = schema.columns.map(col => {\n const parts = [`\"${col.name}\" ${col.type}`]\n if (col.primaryKey) parts.push('PRIMARY KEY')\n if (col.notNull) parts.push('NOT NULL')\n if (col.unique) parts.push('UNIQUE')\n if (col.defaultValue !== undefined) {\n parts.push(`DEFAULT ${typeof col.defaultValue === 'string' ? `'${col.defaultValue}'` : col.defaultValue === null ? 'NULL' : String(col.defaultValue)}`)\n }\n return parts.join(' ')\n })\n\n // Drop a pre-existing legacy `(id, data)` shape when the caller\n // is now declaring a structured schema. Without this, an earlier\n // `ensureTable(table)` call (no schema → legacy KV table) wins\n // because `CREATE TABLE IF NOT EXISTS` is a no-op when the table\n // is already there with a different shape, and every subsequent\n // typed query throws \"no such column: deviceId\" / \"...id\".\n // Destructive — the caller (analytics tracks/events/media) is the\n // only consumer of the table, so the operator only sees a one-time\n // wipe of yet-unmigrated observability rings.\n type ColInfoRow = { name: string }\n const existingCols = this.getDb()\n .prepare(`PRAGMA table_info(\"${table}\")`)\n .all() as ColInfoRow[]\n if (existingCols.length > 0) {\n const existingNames = new Set(existingCols.map(c => c.name))\n const declaredNames = new Set(schema.columns.map(c => c.name))\n const missingDeclared = schema.columns.some(c => !existingNames.has(c.name))\n const isLegacyKv =\n existingCols.length <= 2 &&\n existingNames.has('data') &&\n !declaredNames.has('data')\n if (isLegacyKv || missingDeclared) {\n try { this.getDb().exec(`DROP TABLE \"${table}\"`) } catch { /* best-effort */ }\n }\n }\n\n this.getDb().exec(`CREATE TABLE IF NOT EXISTS \"${table}\" (${colDefs.join(', ')})`)\n\n if (schema.indexes) {\n for (const idx of schema.indexes) {\n const unique = idx.unique ? 'UNIQUE ' : ''\n const cols = idx.columns.map(c => `\"${c}\"`).join(', ')\n this.getDb().exec(`CREATE ${unique}INDEX IF NOT EXISTS \"${idx.name}\" ON \"${table}\" (${cols})`)\n }\n }\n\n this.structuredTables.add(table)\n }\n\n async tableInsert(table: string, row: Record<string, unknown>): Promise<void> {\n const keys = Object.keys(row)\n const cols = keys.map(k => `\"${k}\"`).join(', ')\n const placeholders = keys.map(() => '?').join(', ')\n const values = keys.map(k => {\n const v = row[k]\n return typeof v === 'object' && v !== null ? JSON.stringify(v) : v\n })\n this.getDb().prepare(`INSERT INTO \"${table}\" (${cols}) VALUES (${placeholders})`).run(...values)\n }\n\n async tableUpdate(table: string, filter: Record<string, unknown>, updates: Record<string, unknown>): Promise<number> {\n const setClauses: string[] = []\n const setValues: unknown[] = []\n for (const [k, v] of Object.entries(updates)) {\n setClauses.push(`\"${k}\" = ?`)\n setValues.push(typeof v === 'object' && v !== null ? JSON.stringify(v) : v)\n }\n\n const { whereSql, whereValues } = this.buildWhere(filter)\n const result = this.getDb()\n .prepare(`UPDATE \"${table}\" SET ${setClauses.join(', ')}${whereSql}`)\n .run(...setValues, ...whereValues)\n return result.changes\n }\n\n async tableDelete(table: string, filter: Record<string, unknown>): Promise<number> {\n const { whereSql, whereValues } = this.buildWhere(filter)\n const result = this.getDb().prepare(`DELETE FROM \"${table}\"${whereSql}`).run(...whereValues)\n return result.changes\n }\n\n async tableQuery(table: string, options?: TableQueryOptions): Promise<readonly Record<string, unknown>[]> {\n let sql = `SELECT * FROM \"${table}\"`\n const values: unknown[] = []\n\n if (options?.where) {\n const { whereSql, whereValues } = this.buildWhere(options.where)\n sql += whereSql\n values.push(...whereValues)\n }\n\n if (options?.orderBy) {\n sql += ` ORDER BY \"${options.orderBy.field}\" ${options.orderBy.direction === 'desc' ? 'DESC' : 'ASC'}`\n }\n\n if (options?.limit !== undefined) {\n sql += ` LIMIT ?`\n values.push(options.limit)\n }\n\n if (options?.offset !== undefined) {\n sql += ` OFFSET ?`\n values.push(options.offset)\n }\n\n const rows = this.getDb().prepare(sql).all(...values)\n return rows.flatMap((r) => asJsonObject(r) ? [asJsonObject(r)!] : [])\n }\n\n async tableGet(table: string, filter: Record<string, unknown>): Promise<Record<string, unknown> | null> {\n const { whereSql, whereValues } = this.buildWhere(filter)\n const row = this.getDb().prepare(`SELECT * FROM \"${table}\"${whereSql} LIMIT 1`).get(...whereValues)\n return asJsonObject(row)\n }\n\n async tableCount(table: string, filter?: Record<string, unknown>): Promise<number> {\n let sql = `SELECT COUNT(*) as count FROM \"${table}\"`\n const values: unknown[] = []\n\n if (filter) {\n const { whereSql, whereValues } = this.buildWhere(filter)\n sql += whereSql\n values.push(...whereValues)\n }\n\n const row = asJsonObject(this.getDb().prepare(sql).get(...values))\n return typeof row?.count === 'number' ? row.count : 0\n }\n\n private buildWhere(filter: Record<string, unknown>): { whereSql: string; whereValues: unknown[] } {\n const conditions: string[] = []\n const values: unknown[] = []\n for (const [k, v] of Object.entries(filter)) {\n conditions.push(`\"${k}\" = ?`)\n values.push(typeof v === 'object' && v !== null ? JSON.stringify(v) : v)\n }\n const whereSql = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : ''\n return { whereSql, whereValues: values }\n }\n}\n\nexport default SqliteSettingsBackend\n","import type { ProviderRegistration } from '@camstack/types'\nimport { BaseAddon, RUNTIME_DEFAULTS, errMsg, settingsStoreCapability } from '@camstack/types'\nimport { SqliteSettingsBackend } from './sqlite-settings-backend.js'\n\n/**\n * SQLite Settings addon — provides persistent settings storage.\n * Capability: 'settings-store' (singleton)\n */\nexport class SqliteSettingsAddon extends BaseAddon {\n private backend: SqliteSettingsBackend | null = null\n\n constructor() { super({}) }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const addonId = this.ctx.id.replace('addon:', '')\n let pathSource = 'fallback (hardcoded)'\n const dbPath = await this.ctx.api.storage.resolve.query({ location: 'addons-data', relativePath: `${addonId}/camstack.db` })\n .then((p: string) => { pathSource = 'storage capability (addons-data)'; return p })\n .catch(() => {\n if (this.ctx.dataDir) { pathSource = 'dataDir'; return `${this.ctx.dataDir}/camstack.db` }\n return 'camstack-data/addons-data/sqlite-settings/camstack.db'\n })\n\n let dbExists = false\n try {\n const fs = await import('node:fs')\n dbExists = fs.existsSync(dbPath)\n } catch (err) { this.ctx.logger.warn('Failed to check DB file existence', { meta: { error: errMsg(err) } }) }\n\n this.ctx.logger.info('DB path resolved', { meta: { pathSource, dbPath } })\n this.ctx.logger.info('DB file status', { meta: { dbExists } })\n\n this.backend = new SqliteSettingsBackend(dbPath, { ...RUNTIME_DEFAULTS })\n await this.backend.initialize()\n this.ctx.logger.info('Initialized successfully')\n return [{ capability: settingsStoreCapability, provider: this.backend }]\n }\n\n protected async onShutdown(): Promise<void> {\n await this.backend?.shutdown()\n }\n\n getBackend(): SqliteSettingsBackend | null {\n return this.backend\n }\n}\n\nexport default SqliteSettingsAddon\n","import Database from 'better-sqlite3'\nimport { CORE_TABLE_DDL, CORE_TABLE_MIGRATIONS } from './sql-schema.js'\nimport { RUNTIME_DEFAULTS } from '@camstack/types'\n\n/**\n * Thin wrapper over better-sqlite3 that manages the four settings tables:\n * system_settings, addon_settings, provider_settings, device_settings.\n *\n * All values are stored as JSON text and deserialized on read.\n */\nexport class SettingsStore {\n private readonly db: Database.Database\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath)\n this.db.pragma('journal_mode = WAL')\n this.db.pragma('foreign_keys = ON')\n this.initTables()\n }\n\n // ---------------------------------------------------------------------------\n // System settings\n // ---------------------------------------------------------------------------\n\n getSystem(key: string): unknown {\n const row = this.db\n .prepare<[string], { value: string }>('SELECT value FROM system_settings WHERE key = ?')\n .get(key)\n if (row === undefined) return undefined\n return JSON.parse(row.value)\n }\n\n setSystem(key: string, value: unknown): void {\n this.db\n .prepare(\n `INSERT INTO system_settings (key, value, updated_at) VALUES (?, json(?), unixepoch())\n ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,\n )\n .run(key, JSON.stringify(value))\n }\n\n getAllSystem(): Record<string, unknown> {\n const rows = this.db\n .prepare<[], { key: string; value: string }>('SELECT key, value FROM system_settings')\n .all()\n return Object.fromEntries(rows.map(r => [r.key, JSON.parse(r.value)]))\n }\n\n // ---------------------------------------------------------------------------\n // Addon settings\n // ---------------------------------------------------------------------------\n\n getAddon(addonId: string, key: string): unknown {\n const row = this.db\n .prepare<[string, string], { value: string }>(\n 'SELECT value FROM addon_settings WHERE addon_id = ? AND key = ?',\n )\n .get(addonId, key)\n if (row === undefined) return undefined\n return JSON.parse(row.value)\n }\n\n setAddon(addonId: string, key: string, value: unknown): void {\n this.db\n .prepare(\n `INSERT INTO addon_settings (addon_id, key, value, updated_at) VALUES (?, ?, json(?), unixepoch())\n ON CONFLICT(addon_id, key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,\n )\n .run(addonId, key, JSON.stringify(value))\n }\n\n getAllAddon(addonId: string): Record<string, unknown> {\n const rows = this.db\n .prepare<[string], { key: string; value: string }>(\n 'SELECT key, value FROM addon_settings WHERE addon_id = ?',\n )\n .all(addonId)\n return Object.fromEntries(rows.map(r => [r.key, JSON.parse(r.value)]))\n }\n\n /** Bulk-replace all keys for an addon (within a transaction). */\n setAllAddon(addonId: string, config: Record<string, unknown>): void {\n const deleteStmt = this.db.prepare('DELETE FROM addon_settings WHERE addon_id = ?')\n const insertStmt = this.db.prepare(\n `INSERT INTO addon_settings (addon_id, key, value, updated_at) VALUES (?, ?, json(?), unixepoch())`,\n )\n this.db.transaction(() => {\n deleteStmt.run(addonId)\n for (const [key, value] of Object.entries(config)) {\n insertStmt.run(addonId, key, JSON.stringify(value))\n }\n })()\n }\n\n // ---------------------------------------------------------------------------\n // Provider settings\n // ---------------------------------------------------------------------------\n\n getProvider(providerId: string, key: string): unknown {\n const row = this.db\n .prepare<[string, string], { value: string }>(\n 'SELECT value FROM provider_settings WHERE provider_id = ? AND key = ?',\n )\n .get(providerId, key)\n if (row === undefined) return undefined\n return JSON.parse(row.value)\n }\n\n setProvider(providerId: string, key: string, value: unknown): void {\n this.db\n .prepare(\n `INSERT INTO provider_settings (provider_id, key, value, updated_at) VALUES (?, ?, json(?), unixepoch())\n ON CONFLICT(provider_id, key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,\n )\n .run(providerId, key, JSON.stringify(value))\n }\n\n getAllProvider(providerId: string): Record<string, unknown> {\n const rows = this.db\n .prepare<[string], { key: string; value: string }>(\n 'SELECT key, value FROM provider_settings WHERE provider_id = ?',\n )\n .all(providerId)\n return Object.fromEntries(rows.map(r => [r.key, JSON.parse(r.value)]))\n }\n\n // ---------------------------------------------------------------------------\n // Device settings\n // ---------------------------------------------------------------------------\n\n getDevice(deviceId: string, key: string): unknown {\n const row = this.db\n .prepare<[string, string], { value: string }>(\n 'SELECT value FROM device_settings WHERE device_id = ? AND key = ?',\n )\n .get(deviceId, key)\n if (row === undefined) return undefined\n return JSON.parse(row.value)\n }\n\n setDevice(deviceId: string, key: string, value: unknown): void {\n this.db\n .prepare(\n `INSERT INTO device_settings (device_id, key, value, updated_at) VALUES (?, ?, json(?), unixepoch())\n ON CONFLICT(device_id, key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,\n )\n .run(deviceId, key, JSON.stringify(value))\n }\n\n getAllDevice(deviceId: string): Record<string, unknown> {\n const rows = this.db\n .prepare<[string], { key: string; value: string }>(\n 'SELECT key, value FROM device_settings WHERE device_id = ?',\n )\n .all(deviceId)\n return Object.fromEntries(rows.map(r => [r.key, JSON.parse(r.value)]))\n }\n\n // ---------------------------------------------------------------------------\n // Addon-device settings (per-device overrides of an addon's config)\n //\n // Implements the third level of the resolution chain used by the\n // multi-level settings system:\n // schema default -> addon_settings (global) -> addon_device_settings\n // ---------------------------------------------------------------------------\n\n getAddonDevice(addonId: string, deviceId: string): Record<string, unknown> {\n const rows = this.db\n .prepare<[string, string], { key: string; value: string }>(\n 'SELECT key, value FROM addon_device_settings WHERE addon_id = ? AND device_id = ?',\n )\n .all(addonId, deviceId)\n return Object.fromEntries(rows.map(r => [r.key, JSON.parse(r.value)]))\n }\n\n /**\n * Bulk-replace all per-device overrides for (addonId, deviceId) in a\n * single transaction. Empty input clears the override set — caller\n * should use `clearAddonDevice` for explicit resets.\n */\n setAddonDevice(addonId: string, deviceId: string, values: Record<string, unknown>): void {\n const deleteStmt = this.db.prepare(\n 'DELETE FROM addon_device_settings WHERE addon_id = ? AND device_id = ?',\n )\n const insertStmt = this.db.prepare(\n `INSERT INTO addon_device_settings (addon_id, device_id, key, value, updated_at)\n VALUES (?, ?, ?, json(?), unixepoch())`,\n )\n this.db.transaction(() => {\n deleteStmt.run(addonId, deviceId)\n for (const [key, value] of Object.entries(values)) {\n insertStmt.run(addonId, deviceId, key, JSON.stringify(value))\n }\n })()\n }\n\n clearAddonDevice(addonId: string, deviceId: string): void {\n this.db\n .prepare('DELETE FROM addon_device_settings WHERE addon_id = ? AND device_id = ?')\n .run(addonId, deviceId)\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /** Close the SQLite connection (call on shutdown). */\n close(): void {\n this.db.close()\n }\n\n /** Check if system_settings is empty (used for first-boot seeding). */\n isSystemSettingsEmpty(): boolean {\n const row = this.db\n .prepare<[], { cnt: number }>('SELECT COUNT(*) AS cnt FROM system_settings')\n .get()\n return (row?.cnt ?? 0) === 0\n }\n\n /** Seed system_settings with RUNTIME_DEFAULTS (only on first boot). */\n seedDefaults(): void {\n const insert = this.db.prepare(\n `INSERT OR IGNORE INTO system_settings (key, value, updated_at) VALUES (?, json(?), unixepoch())`,\n )\n this.db.transaction(() => {\n for (const [key, value] of Object.entries(RUNTIME_DEFAULTS)) {\n insert.run(key, JSON.stringify(value))\n }\n })()\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private initTables(): void {\n this.db.transaction(() => {\n for (const stmt of CORE_TABLE_DDL) {\n this.db.prepare(stmt).run()\n }\n // Idempotent additive column migrations. Each ALTER statement may\n // fail on installs where the column already exists (fresh\n // installs, or a previous boot ran the same migration). We\n // swallow those specific errors and re-throw anything else —\n // a genuine schema failure should still crash startup.\n for (const stmt of CORE_TABLE_MIGRATIONS) {\n try {\n this.db.prepare(stmt).run()\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (msg.includes('duplicate column name') || msg.includes('no such table')) continue\n throw err\n }\n }\n })()\n }\n}\n","/** Core table DDL statements -- executed on first boot */\nexport const CORE_TABLE_DDL: readonly string[] = [\n // Settings tables\n `CREATE TABLE IF NOT EXISTS system_settings (\n key TEXT PRIMARY KEY,\n value JSON NOT NULL,\n updated_at INTEGER NOT NULL DEFAULT (unixepoch())\n )`,\n `CREATE TABLE IF NOT EXISTS addon_settings (\n addon_id TEXT NOT NULL,\n key TEXT NOT NULL,\n value JSON NOT NULL,\n updated_at INTEGER NOT NULL DEFAULT (unixepoch()),\n PRIMARY KEY (addon_id, key)\n )`,\n `CREATE TABLE IF NOT EXISTS provider_settings (\n provider_id TEXT NOT NULL,\n key TEXT NOT NULL,\n value JSON NOT NULL,\n updated_at INTEGER NOT NULL DEFAULT (unixepoch()),\n PRIMARY KEY (provider_id, key)\n )`,\n `CREATE TABLE IF NOT EXISTS device_settings (\n device_id TEXT NOT NULL,\n key TEXT NOT NULL,\n value JSON NOT NULL,\n updated_at INTEGER NOT NULL DEFAULT (unixepoch()),\n PRIMARY KEY (device_id, key)\n )`,\n /**\n * Per-device overrides of an addon's settings (scope: 'device' fields).\n * Resolution chain: schema default -> addon_settings (global) -> this.\n */\n `CREATE TABLE IF NOT EXISTS addon_device_settings (\n addon_id TEXT NOT NULL,\n device_id TEXT NOT NULL,\n key TEXT NOT NULL,\n value JSON NOT NULL,\n updated_at INTEGER NOT NULL DEFAULT (unixepoch()),\n PRIMARY KEY (addon_id, device_id, key)\n )`,\n\n // P12b sweep: removed static DDL for `detection_events`, `audio_levels`,\n // `track_trails` — these were consumed exclusively by the old\n // analytics sub-addon (deleted) and its analysis-data-persistence cap.\n // addon-pipeline-analytics now owns all detection/audio/track tables\n // via `declareCollection` (pipeline-analytics:motion-events,\n // :object-events, :audio-events, :tracks, :media).\n\n // Device registry\n `CREATE TABLE IF NOT EXISTS devices (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n addon_id TEXT NOT NULL,\n stable_id TEXT NOT NULL,\n type TEXT NOT NULL,\n name TEXT NOT NULL,\n parent_stable_id TEXT,\n role TEXT,\n enabled INTEGER DEFAULT 1,\n created_at TEXT DEFAULT (datetime('now')),\n UNIQUE(addon_id, stable_id)\n)`,\n `CREATE INDEX IF NOT EXISTS idx_devices_addon ON devices(addon_id)`,\n `CREATE INDEX IF NOT EXISTS idx_devices_parent ON devices(addon_id, parent_stable_id)`,\n\n // Addon / device config store\n // stable_id IS NULL -> addon-global row (one per addon_id)\n // stable_id IS NOT NULL -> per-device row (one per addon_id + stable_id pair)\n // Two partial unique indexes enforce the constraint because SQLite does not\n // support expressions inside UNIQUE(...) declarations.\n `CREATE TABLE IF NOT EXISTS addon_config (\n addon_id TEXT NOT NULL,\n stable_id TEXT,\n data TEXT NOT NULL DEFAULT '{}',\n updated_at TEXT DEFAULT (datetime('now'))\n)`,\n `CREATE UNIQUE INDEX IF NOT EXISTS idx_addon_config_global ON addon_config(addon_id) WHERE stable_id IS NULL`,\n `CREATE UNIQUE INDEX IF NOT EXISTS idx_addon_config_device ON addon_config(addon_id, stable_id) WHERE stable_id IS NOT NULL`,\n `CREATE INDEX IF NOT EXISTS idx_addon_config_addon ON addon_config(addon_id)`,\n]\n\n/**\n * Idempotent ALTER statements run after `CORE_TABLE_DDL`. Each entry\n * may fail on installs where the column already exists — the runner\n * catches \"duplicate column name\" / \"no such table\" errors and moves\n * on. Order matters: migrations stack in chronological order.\n *\n * Pattern when adding a new column:\n * 1. Add the column to the matching `CREATE TABLE` above so fresh\n * installs get it by default.\n * 2. Append an `ALTER TABLE ... ADD COLUMN ...` here so existing\n * installs get it on next boot.\n */\nexport const CORE_TABLE_MIGRATIONS: readonly string[] = [\n // 2026-04 — DeviceRole support: optional role hint per device, used by\n // admin UI to pick icons/widgets for accessory children (siren,\n // floodlight, PIR, chime, doorbell, …). Nullable; existing rows stay.\n `ALTER TABLE devices ADD COLUMN role TEXT`,\n]\n\n/** Addon table schema declaration */\nexport interface AddonTableSchema {\n readonly name: string\n readonly columns: ReadonlyArray<{\n readonly name: string\n readonly type: 'TEXT' | 'INTEGER' | 'REAL' | 'JSON'\n readonly primaryKey?: boolean\n readonly notNull?: boolean\n }>\n readonly indexes?: ReadonlyArray<{\n readonly name: string\n readonly columns: readonly string[]\n readonly unique?: boolean\n }>\n}\n\n/** Generate CREATE TABLE DDL from addon schema */\nexport function addonTableToDdl(schema: AddonTableSchema): string[] {\n const pks = schema.columns.filter(c => c.primaryKey).map(c => c.name)\n const colDefs = schema.columns.map(c => {\n const parts = [c.name, c.type]\n if (c.notNull) parts.push('NOT NULL')\n return parts.join(' ')\n })\n\n let ddl = `CREATE TABLE IF NOT EXISTS ${schema.name} (\\n ${colDefs.join(',\\n ')}`\n if (pks.length > 0) {\n ddl += `,\\n PRIMARY KEY (${pks.join(', ')})`\n }\n ddl += '\\n)'\n\n const stmts = [ddl]\n for (const idx of schema.indexes ?? []) {\n const unique = idx.unique ? 'UNIQUE ' : ''\n stmts.push(`CREATE ${unique}INDEX IF NOT EXISTS ${idx.name} ON ${schema.name}(${idx.columns.join(', ')})`)\n }\n return stmts\n}\n","import type Database from 'better-sqlite3'\n\nexport interface DeviceRow {\n readonly stableId: string\n readonly type: string\n readonly name: string\n readonly parentStableId: string | null\n readonly enabled: boolean\n}\n\ninterface InsertInput {\n readonly stableId: string\n readonly type: string\n readonly name: string\n readonly parentStableId: string | null\n}\n\nexport class DeviceStore {\n constructor(private readonly db: Database.Database) {}\n\n insert(addonId: string, device: InsertInput): void {\n this.db\n .prepare(\n `INSERT INTO devices (addon_id, stable_id, type, name, parent_stable_id) VALUES (?, ?, ?, ?, ?)`,\n )\n .run(addonId, device.stableId, device.type, device.name, device.parentStableId)\n }\n\n listByAddon(addonId: string): readonly DeviceRow[] {\n return this.db\n .prepare(\n `SELECT stable_id as stableId, type, name, parent_stable_id as parentStableId, enabled FROM devices WHERE addon_id = ?`,\n )\n .all(addonId) as DeviceRow[]\n }\n\n listChildren(addonId: string, parentStableId: string): readonly DeviceRow[] {\n return this.db\n .prepare(\n `SELECT stable_id as stableId, type, name, parent_stable_id as parentStableId, enabled FROM devices WHERE addon_id = ? AND parent_stable_id = ?`,\n )\n .all(addonId, parentStableId) as DeviceRow[]\n }\n\n remove(addonId: string, stableId: string): void {\n this.db.prepare(`DELETE FROM devices WHERE addon_id = ? AND stable_id = ?`).run(addonId, stableId)\n }\n}\n","import type Database from 'better-sqlite3'\n\nexport class ConfigStore {\n constructor(private readonly db: Database.Database) {}\n\n save(addonId: string, stableId: string | null, data: Record<string, unknown>): void {\n // Two partial unique indexes enforce uniqueness (one for null, one for non-null stable_id).\n // SQLite resolves ON CONFLICT to the matching partial index automatically.\n if (stableId === null) {\n this.db\n .prepare(\n `INSERT INTO addon_config (addon_id, stable_id, data, updated_at)\n VALUES (?, NULL, ?, datetime('now'))\n ON CONFLICT(addon_id) WHERE stable_id IS NULL\n DO UPDATE SET data = excluded.data, updated_at = excluded.updated_at`,\n )\n .run(addonId, JSON.stringify(data))\n } else {\n this.db\n .prepare(\n `INSERT INTO addon_config (addon_id, stable_id, data, updated_at)\n VALUES (?, ?, ?, datetime('now'))\n ON CONFLICT(addon_id, stable_id) WHERE stable_id IS NOT NULL\n DO UPDATE SET data = excluded.data, updated_at = excluded.updated_at`,\n )\n .run(addonId, stableId, JSON.stringify(data))\n }\n }\n\n load(addonId: string, stableId: string | null): Record<string, unknown> {\n const row = stableId === null\n ? (this.db\n .prepare(`SELECT data FROM addon_config WHERE addon_id = ? AND stable_id IS NULL`)\n .get(addonId) as { data: string } | undefined)\n : (this.db\n .prepare(`SELECT data FROM addon_config WHERE addon_id = ? AND stable_id = ?`)\n .get(addonId, stableId) as { data: string } | undefined)\n\n return row ? (JSON.parse(row.data) as Record<string, unknown>) : {}\n }\n\n remove(addonId: string, stableId: string | null): void {\n if (stableId === null) {\n this.db.prepare(`DELETE FROM addon_config WHERE addon_id = ? AND stable_id IS NULL`).run(addonId)\n } else {\n this.db.prepare(`DELETE FROM addon_config WHERE addon_id = ? AND stable_id = ?`).run(addonId, stableId)\n }\n }\n}\n","import type { ProviderRegistration } from '@camstack/types'\nimport { BaseAddon, logDestinationCapability } from '@camstack/types'\nimport { WinstonDestination } from './winston-destination.js'\n\ninterface WinstonConfig {\n readonly level: string\n readonly retentionDays: number\n}\n\n/**\n * Winston logging addon — rotated log files + console output.\n * Settings appear under Cluster → NodeDetail → Settings.\n */\nexport class WinstonLoggingAddon extends BaseAddon<WinstonConfig> {\n private destination: WinstonDestination | null = null\n\n constructor() {\n super({ level: 'info', retentionDays: 30 })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const logsDir = await this.ctx.api.storage.resolve.query({ location: 'logs', relativePath: '' })\n .catch(() => 'camstack-data/logs')\n this.destination = new WinstonDestination()\n await this.destination.initialize({ ...this.config, logsDir })\n this.ctx.logger.info('Winston logging initialized')\n return [{ capability: logDestinationCapability, provider: this.destination }]\n }\n\n protected async onShutdown(): Promise<void> {\n await this.destination?.shutdown()\n }\n\n getDestination(): WinstonDestination {\n if (!this.destination) throw new Error('Winston not initialized')\n return this.destination\n }\n\n protected globalSettingsSchema() {\n return this.schema({\n sections: [\n {\n id: 'winston-logging',\n title: 'Logging',\n description: 'Global log verbosity + retention for rotated log files on this node.',\n columns: 2,\n fields: [\n this.field({\n type: 'select',\n key: 'level',\n label: 'Log Level',\n default: 'info',\n options: [\n { value: 'debug', label: 'Debug' },\n { value: 'info', label: 'Info' },\n { value: 'warn', label: 'Warn' },\n { value: 'error', label: 'Error' },\n ],\n }),\n this.field({\n type: 'number',\n key: 'retentionDays',\n label: 'Retention (days)',\n description: 'Number of days to keep rotated log files before deletion',\n min: 1,\n max: 365,\n step: 1,\n default: 30,\n unit: 'days',\n }),\n ],\n },\n ],\n })\n }\n}\n","import * as winston from 'winston'\nimport DailyRotateFile from 'winston-daily-rotate-file'\nimport * as path from 'node:path'\nimport type { ILogDestination, LogEntry, LogFilter } from '@camstack/types'\nimport { formatLogLine } from '../../logging/formatter.js'\n\ninterface WinstonConfig {\n readonly level: string\n readonly retentionDays: number\n /** Resolved absolute path to the logs directory (replaces the old dataPath field). */\n readonly logsDir: string\n}\n\n/**\n * Rotated-file log destination. Console output goes through the shared\n * `formatLogLine` so every console sink (Winston, ConsoleDestination,\n * HubForwarderDestination) emits identical lines. File output keeps a\n * structured JSON shape so log tooling can query tags/meta.\n */\nexport class WinstonDestination implements ILogDestination {\n private logger: winston.Logger | null = null\n\n async initialize(config?: WinstonConfig): Promise<void> {\n const {\n level = 'info',\n retentionDays = 30,\n logsDir = path.join('camstack-data', 'logs'),\n } = config ?? {}\n\n // Console: canonical single-line formatter — `_rendered` already\n // carries level-based ANSI colour codes (see `formatLogLine` in\n // `@camstack/core/logging/formatter.ts`). Using Winston's colorize\n // here would just decorate unused `info.level` and leave the\n // rendered line uncoloured.\n const consoleFormat = winston.format.printf((info) => {\n const rendered = (info as unknown as { _rendered?: string })._rendered\n return typeof rendered === 'string' ? rendered : String(info.message)\n })\n\n // File: structured JSON. Strip `_rendered` first — it carries ANSI\n // escape codes intended for the terminal and has no place in a\n // rotated-file store used for ops queries.\n const stripRendered = winston.format((info) => {\n delete (info as Record<string, unknown>)['_rendered']\n return info\n })\n const fileFormat = winston.format.combine(\n winston.format.timestamp(),\n stripRendered(),\n winston.format.json(),\n )\n\n // File-only winston. Stdout is owned by `ConsoleDestination`\n // (the `console-logging` builtin addon) — adding a Winston console\n // transport here would re-render every log line a second time on\n // the hub terminal, which is the historic cause of the duplicate\n // output operators have been seeing. The `consoleFormat` printf\n // above stays wired in so a future opt-in transport can use it\n // without re-deriving the layout.\n void consoleFormat\n this.logger = winston.createLogger({\n level,\n transports: [\n new DailyRotateFile({\n dirname: logsDir,\n filename: 'camstack-%DATE%.log',\n datePattern: 'YYYY-MM-DD',\n maxFiles: `${retentionDays}d`,\n format: fileFormat,\n }),\n ],\n })\n }\n\n write(entry: LogEntry): void {\n if (!this.logger) return\n\n // Moleculer JSON serialization converts Date → string; normalize back\n const ts = entry.timestamp instanceof Date\n ? entry.timestamp.toISOString()\n : String(entry.timestamp)\n // Render once with colours for the console transport; file transport\n // strips `_rendered` via the format chain above so disk stays plain.\n const rendered = formatLogLine(entry, { colorize: true })\n\n this.logger.log({\n level: entry.level,\n message: entry.message,\n _rendered: rendered,\n timestamp: ts,\n scope: entry.scope,\n ...(entry.tags ? { tags: entry.tags } : {}),\n ...(entry.meta ? { meta: entry.meta } : {}),\n })\n }\n\n async query(_filter: LogFilter): Promise<readonly LogEntry[]> {\n // File-based log querying is not implemented; use structured storage for log queries\n return []\n }\n\n async shutdown(): Promise<void> {\n if (!this.logger) return\n\n await new Promise<void>((resolve) => {\n this.logger!.on('finish', resolve)\n this.logger!.end()\n })\n this.logger = null\n }\n}\n","/**\n * Canonical single-line formatter for every `LogEntry` that reaches a\n * console transport — hub-side `WinstonDestination` +\n * `ConsoleDestination`, agent-side `HubForwarderDestination`. One\n * definition so the three paths can't drift.\n *\n * Layout mirrors NestJS `ConsoleLogger` output:\n *\n * [Nest] 54994 - 04/20/2026, 12:45:53 AM LOG [InstanceLoader] TrpcModule dependencies initialized +0ms\n *\n * Mapping for camstack — cluster-aware:\n * - `[Nest]` (brand bracket) → `[<agent>/<addonId>]` so operators see\n * at a glance which node emitted the line\n * (matches the cluster topology)\n * - `54994` (pid) → `process.pid`\n * - `<timestamp>` → `M/D/YYYY, H:MM:SS AM`\n * - `LOG` / `WARN` / `ERROR` → `entry.level` upper-cased, colour per level\n * - `[InstanceLoader]` (ctx) → `[<device>]` — shown only when a device\n * tag is present; omitted otherwise\n * - `<message>` → `entry.message`\n * - trailing `+Nms` → we don't compute timing yet; omitted\n *\n * Rendered examples:\n * [hub/winston-logging] 71184 - 04/20/2026, 12:45:53 AM INFO Winston logging initialized\n * [hub/provider-rtsp] 71184 - 04/20/2026, 12:46:01 AM WARN [salone] probe failed {err=\"timeout\"}\n * [dev-agent-0/detection] 12345 - 04/20/2026, 12:47:15 AM ERROR [cortile] no detector {codec=av1}\n */\nimport type { LogEntry, LogTags } from '@camstack/types'\n\n// Emit ANSI colour codes when the runtime supports them. Heuristic\n// follows npm ecosystem convention so log-consumers can override:\n// - `NO_COLOR` env present → OFF (https://no-color.org/)\n// - `FORCE_COLOR=0` → OFF\n// - `FORCE_COLOR` truthy (1/2/3/true) → ON (forces even when piped)\n// - stdout.isTTY → ON\n// - else → OFF\n// Rationale: running via `concurrently` / `npm run dev` often pipes\n// stdout and strips `isTTY`, making colours disappear. Dev sets\n// `FORCE_COLOR=1` in the shell to opt back in; CI / file-piping\n// pipelines set `NO_COLOR=1` to strip.\n//\n// Destinations that always render for console (ConsoleDestination,\n// HubForwarderDestination) pass `colorize: true` explicitly — still\n// gated by NO_COLOR. File sinks (Winston JSON) pass `colorize: false`\n// so log files stay plain text regardless of the shell environment.\nconst USE_COLOR = (() => {\n try {\n if (typeof process === 'undefined') return false\n const env = process.env ?? {}\n if (env['NO_COLOR']) return false\n const force = env['FORCE_COLOR']\n if (force !== undefined) return force !== '' && force !== '0' && force !== 'false'\n return Boolean((process.stdout as { isTTY?: boolean })?.isTTY)\n } catch { return false }\n})()\n\n/** True when `NO_COLOR` is set — destinations that force colour on still honour this. */\nconst NO_COLOR = (() => {\n try { return Boolean(process?.env?.['NO_COLOR']) } catch { return false }\n})()\n\nconst RESET = '\\x1b[0m'\nconst ANSI = {\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n red: '\\x1b[31m',\n cyan: '\\x1b[36m',\n gray: '\\x1b[90m',\n} as const\n\nconst COLOR_BY_LEVEL: Readonly<Record<string, string>> = {\n debug: ANSI.gray,\n info: ANSI.green,\n warn: ANSI.yellow,\n error: ANSI.red,\n}\n\nfunction paint(color: string, text: string, enabled: boolean): string {\n return enabled ? `${color}${text}${RESET}` : text\n}\n\nfunction colorizeLevel(level: string, text: string, enabled: boolean): string {\n if (!enabled) return text\n const code = COLOR_BY_LEVEL[level]\n return code ? `${code}${text}${RESET}` : text\n}\n\n/** Right-pad `value` to exactly `width` characters. */\nfunction padRight(value: string, width: number): string {\n if (value.length >= width) return value.slice(0, width)\n return value + ' '.repeat(width - value.length)\n}\n\n/** Derive the agent — the top-level cluster node, never the forked-worker suffix. */\nfunction resolveAgent(tags: LogTags | undefined): string | null {\n const agentId = tags?.agentId\n if (typeof agentId === 'string' && agentId.length > 0) return agentId\n const nodeId = tags?.nodeId\n if (typeof nodeId === 'string' && nodeId.length > 0) {\n return nodeId.includes('/') ? nodeId.split('/')[0]! : nodeId\n }\n return null\n}\n\n/** Derive the addon — `tags.addonId` first; `system` when the tag is missing\n * (scope is no longer a fallback — it's a sub-component label, not identity). */\nfunction resolveAddon(entry: Pick<LogEntry, 'tags'>): string {\n const addonId = entry.tags?.addonId\n if (typeof addonId === 'string' && addonId.length > 0) return addonId\n return 'system'\n}\n\n/** Device name (or `#id` fallback) — used inside the context bracket when present. */\nfunction resolveDevice(tags: LogTags | undefined): string | null {\n const name = tags?.deviceName\n if (typeof name === 'string' && name.length > 0) return name\n const id = tags?.deviceId\n if (typeof id === 'number' && Number.isFinite(id)) return `#${id}`\n return null\n}\n\n/**\n * Build the brand bracket content — `<agent>/<addonId>`. Agent is\n * always shown (even `hub`) so operators never have to guess which\n * node emitted a line. Falls back to `?/<addon>` when tags don't\n * carry an agent id (pre-boot logs, test harnesses).\n */\nfunction buildBrand(entry: Pick<LogEntry, 'tags'>): string {\n const agent = resolveAgent(entry.tags) ?? '?'\n const addon = resolveAddon(entry)\n return `${agent}/${addon}`\n}\n\n/**\n * Build the optional device-context bracket. Returns `null` when the\n * line doesn't carry a device tag — renders as just the brand + message\n * without the second bracket. With a device tag: `salone` / `#42`.\n */\nfunction buildDeviceContext(entry: Pick<LogEntry, 'tags'>): string | null {\n return resolveDevice(entry.tags)\n}\n\n/**\n * NestJS-style locale timestamp: `M/D/YYYY, H:MM:SS AM`. Built with\n * `toLocaleString('en-US')` to match the default NestJS format that\n * operators are used to from Nest boot output.\n */\nfunction formatTimestamp(value: unknown): string {\n const date = value instanceof Date ? value : new Date(typeof value === 'string' ? value : Date.now())\n return date.toLocaleString('en-US', {\n month: 'numeric',\n day: 'numeric',\n year: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n second: '2-digit',\n hour12: true,\n })\n}\n\n/** Compact `{key=value key=\"with space\"}` rendering of an arbitrary object. Empty → ''. */\nfunction formatMeta(meta: Record<string, unknown> | undefined): string {\n if (!meta) return ''\n const keys = Object.keys(meta)\n if (keys.length === 0) return ''\n const parts: string[] = []\n for (const key of keys) {\n const value = meta[key]\n parts.push(`${key}=${formatMetaValue(value)}`)\n }\n return `{${parts.join(' ')}}`\n}\n\nfunction formatMetaValue(value: unknown): string {\n if (value === null) return 'null'\n if (value === undefined) return 'undefined'\n if (typeof value === 'string') {\n return /\\s|\"/.test(value) ? JSON.stringify(value) : value\n }\n if (typeof value === 'number' || typeof value === 'boolean') return String(value)\n if (value instanceof Error) return JSON.stringify(value.message)\n try { return JSON.stringify(value) } catch { return String(value) }\n}\n\n/** Cached renderer PID — fallback when the entry doesn't carry its own `tags.pid`. */\nconst PID = typeof process !== 'undefined' && typeof process.pid === 'number' ? String(process.pid) : '?'\n\n/** Options for `formatLogLine`. */\nexport interface FormatLogLineOptions {\n /**\n * Emit ANSI colour codes. When omitted, falls back to the shell-env\n * heuristic (`NO_COLOR`/`FORCE_COLOR`/`isTTY`). Destinations that\n * always target a console (ConsoleDestination, HubForwarderDestination)\n * pass `true`; file sinks (Winston JSON) pass `false` so logs on disk\n * stay plain text regardless of the shell env.\n *\n * `NO_COLOR=1` in the environment still wins — consumer opt-in beats\n * producer opt-in, matching the https://no-color.org/ convention.\n */\n readonly colorize?: boolean\n}\n\n/**\n * Render a `LogEntry` as one complete console line — no trailing newline.\n * Caller appends `\\n` (file sinks) or relies on `console.log` (stdout sink).\n *\n * PID column prefers `entry.tags.pid` when set (so forked-worker entries\n * carry the worker's OS pid even when the hub renders them), falling back\n * to the renderer's own `process.pid`.\n *\n * Colours (when enabled) follow the NestJS convention: the level token\n * AND the message body share the level colour (green/yellow/red/gray for\n * info/warn/error/debug). Brand, device context, scope and meta keep\n * their fixed hues so the structural fields stay visually distinct from\n * the message content.\n */\nexport function formatLogLine(entry: LogEntry, options?: FormatLogLineOptions): string {\n const wantsColor = options?.colorize ?? USE_COLOR\n const colorize = wantsColor && !NO_COLOR\n const levelColor = COLOR_BY_LEVEL[entry.level]\n\n const brand = paint(ANSI.green, `[${buildBrand(entry)}]`, colorize)\n const entryPid = entry.tags?.pid\n const pid = typeof entryPid === 'number' ? String(entryPid) : PID\n const timestamp = formatTimestamp(entry.timestamp)\n // Right-pad level to 5 chars (matches NestJS) so the context/message\n // column aligns across different levels without fixed-width hacks\n // on the surrounding fields.\n const level = colorizeLevel(entry.level, padRight(entry.level.toUpperCase(), 5), colorize)\n const device = buildDeviceContext(entry)\n const ctxPart = device ? ' ' + paint(ANSI.yellow, `[${device}]`, colorize) : ''\n const scope = typeof entry.scope === 'string' && entry.scope.length > 0 ? entry.scope : null\n const scopePart = scope ? ' ' + paint(ANSI.cyan, `(${scope})`, colorize) : ''\n const metaText = formatMeta(entry.meta)\n const metaPart = metaText ? ' ' + paint(ANSI.gray, metaText, colorize) : ''\n // NestJS layout: `[<agent>/<addon>] <pid> - <timestamp> <LEVEL> [<device>] (<scope>) <message>`\n // Message body is tinted by level colour so `error`/`warn` stand out at a glance.\n const message = colorize && levelColor\n ? `${levelColor}${entry.message}${RESET}`\n : entry.message\n return `${brand} ${pid} - ${timestamp} ${level}${ctxPart}${scopePart} ${message}${metaPart}`\n}\n","import type { ProviderRegistration } from '@camstack/types'\nimport { BaseAddon, logDestinationCapability } from '@camstack/types'\nimport { ConsoleDestination } from './console-destination.js'\n\ninterface ConsoleConfig {\n readonly level: 'debug' | 'info' | 'warn' | 'error'\n}\n\n/**\n * Console logging addon — zero-dependency stdout/stderr sink that\n * produces the same canonical line format as the Winston built-in.\n * Registers as a `log-destination` capability provider so the shared\n * LogManager fans every entry to both sinks when both are active.\n *\n * Settings live under Cluster → NodeDetail → Settings alongside the\n * Winston addon. Disable one without disabling the other — the\n * LogManager keeps working as long as at least one destination is\n * registered.\n */\nexport class ConsoleLoggingAddon extends BaseAddon<ConsoleConfig> {\n private destination: ConsoleDestination | null = null\n\n constructor() {\n super({ level: 'info' })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n this.destination = new ConsoleDestination()\n await this.destination.initialize({ level: this.config.level })\n this.ctx.logger.info('Console logging initialized')\n return [{ capability: logDestinationCapability, provider: this.destination }]\n }\n\n protected async onShutdown(): Promise<void> {\n await this.destination?.shutdown()\n }\n\n getDestination(): ConsoleDestination {\n if (!this.destination) throw new Error('Console logging not initialized')\n return this.destination\n }\n\n protected globalSettingsSchema() {\n return this.schema({\n sections: [\n {\n id: 'console-logging',\n title: 'Console Logging',\n description: 'Minimum log level to emit on stdout/stderr. Independent from the rotated-file (Winston) destination.',\n columns: 2,\n fields: [\n this.field({\n type: 'select',\n key: 'level',\n label: 'Log Level',\n default: 'info',\n options: [\n { value: 'debug', label: 'Debug' },\n { value: 'info', label: 'Info' },\n { value: 'warn', label: 'Warn' },\n { value: 'error', label: 'Error' },\n ],\n }),\n ],\n },\n ],\n })\n }\n}\n","/**\n * Zero-dependency log destination that writes every entry to stdout /\n * stderr via the shared `formatLogLine` formatter. Same surface as\n * `WinstonDestination` (full `ILogDestination` contract) but without\n * the rotating-file transport — ideal fallback when the Winston addon\n * is disabled or unavailable (e.g. bare-bones agents, tests).\n */\nimport type { ILogDestination, LogEntry, LogFilter } from '@camstack/types'\nimport { formatLogLine } from '../../logging/formatter.js'\n\ninterface ConsoleConfig {\n /** Minimum log level to emit. Entries below this level are dropped. */\n readonly level?: 'debug' | 'info' | 'warn' | 'error'\n}\n\nconst LEVEL_RANK: Readonly<Record<string, number>> = {\n debug: 0, info: 1, warn: 2, error: 3,\n}\n\nexport class ConsoleDestination implements ILogDestination {\n private minLevel = 0\n\n async initialize(config?: ConsoleConfig): Promise<void> {\n this.minLevel = LEVEL_RANK[config?.level ?? 'info'] ?? 1\n }\n\n write(entry: LogEntry): void {\n const rank = LEVEL_RANK[entry.level] ?? 1\n if (rank < this.minLevel) return\n // Always request ANSI colours for the console sink. The formatter still\n // respects `NO_COLOR` so operators can opt out globally.\n const line = formatLogLine(entry, { colorize: true })\n if (entry.level === 'error') console.error(line)\n else if (entry.level === 'warn') console.warn(line)\n else console.log(line)\n }\n\n async query(_filter: LogFilter): Promise<readonly LogEntry[]> {\n // Console has no persistence — queries are served by other destinations.\n return []\n }\n\n async shutdown(): Promise<void> {\n // Nothing to flush — stdout/stderr are process-owned.\n }\n}\n","import type { ProviderRegistration } from '@camstack/types'\nimport { BaseAddon, logDestinationCapability } from '@camstack/types'\nimport { HubForwarderDestination } from './hub-forwarder-destination.js'\n\n/**\n * Agent-only addon that provides the `log-destination` capability.\n * Writes all logs to the console and forwards to the hub via Moleculer when\n * reachable. The broker is read from `ctx.kernel.cluster?.broker`; outbound\n * log replay on hub-connect is handled internally by the destination.\n */\nexport class HubForwarderAddon extends BaseAddon {\n private destination: HubForwarderDestination | null = null\n\n constructor() { super({}) }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n this.destination = new HubForwarderDestination()\n await this.destination.initialize()\n // Status messages (discovery, disconnect) go through ctx.logger so they\n // appear in the structured log stream, not raw stdout.\n this.destination.setStatusLogger(this.ctx.logger)\n\n // Self-wire the broker when the kernel exposes one (agent + hub processes).\n // In-process unit tests may omit it — logs still go to the console.\n const broker = this.ctx.kernel.cluster?.broker\n if (broker) {\n this.destination.connectBroker(broker)\n } else {\n this.ctx.logger.warn('cluster.broker not available — hub forwarding disabled, console only')\n }\n\n this.ctx.logger.info('Hub forwarder log destination registered')\n return [{ capability: logDestinationCapability, provider: this.destination }]\n }\n\n getDestination(): HubForwarderDestination | null {\n return this.destination\n }\n\n protected async onShutdown(): Promise<void> {\n await this.destination?.shutdown()\n this.destination = null\n }\n}\n","import type { IClusterBroker, ILogDestination, IScopedLogger, LogEntry, LogFilter } from '@camstack/types'\nimport { formatLogLine } from '../../logging/formatter.js'\n\nconst DEFAULT_OUTBOUND_BUFFER_SIZE = 500\n\n/**\n * Log destination for agent mode.\n *\n * - Writes to console ONLY when hub is not yet reachable (cold-start\n * fallback). Forked-worker agents share stdout with their parent\n * hub, so logging to local console AND forwarding to hub's\n * `log-receiver` would print the entry twice on the hub terminal.\n * Once the hub is discovered, local console output stops and the\n * hub's own ConsoleDestination owns the render.\n * - When a Moleculer broker is connected and the hub node is reachable,\n * forwards every log entry to the hub via `log-receiver.ingest`.\n * - Entries written before the hub is reachable are buffered internally\n * (ring-buffered to `DEFAULT_OUTBOUND_BUFFER_SIZE`) and flushed on connect,\n * so boot-time logs still reach the hub without any external replay trigger.\n */\nexport class HubForwarderDestination implements ILogDestination {\n private broker: IClusterBroker | null = null\n private hubConnected = false\n private readonly outboundBuffer: LogEntry[] = []\n private statusLogger: IScopedLogger | null = null\n\n async initialize(): Promise<void> {\n // Console destination is always active — no setup needed.\n }\n\n /**\n * Provide a logger for the destination's own status messages\n * (discovery, disconnect, reconnect). Routed through the agent's\n * LogManager but never through this same destination — the owning\n * addon must hand in a logger that does NOT route back here, or\n * status writes will recurse.\n */\n setStatusLogger(logger: IScopedLogger): void {\n this.statusLogger = logger\n }\n\n private status(level: 'info' | 'warn', msg: string): void {\n if (this.statusLogger) {\n if (level === 'warn') this.statusLogger.warn(msg)\n else this.statusLogger.info(msg)\n return\n }\n // Cold-start fallback: status logger not yet wired.\n if (level === 'warn') console.warn(`[hub-forwarder] ${msg}`)\n else console.log(`[hub-forwarder] ${msg}`)\n }\n\n /**\n * Attach the Moleculer broker so hub forwarding can start.\n * Called by the owning addon from `onInitialize(ctx)` with\n * `ctx.kernel.cluster?.broker`.\n */\n connectBroker(broker: IClusterBroker): void {\n this.broker = broker\n\n // Wait for `log-receiver` service (no timeout — waits until available).\n // The service is registered on the hub after app.init(), so it may\n // appear after node discovery. This is fully event-driven.\n broker.waitForServices('log-receiver')\n .then(() => {\n this.hubConnected = true\n this.status('info', 'log-receiver discovered — log forwarding active')\n this.flushOutbound()\n })\n .catch(() => { /* broker stopped before discovery */ })\n\n broker.localBus.on('$node.disconnected', ({ node }) => {\n if (node.id === 'hub') {\n this.hubConnected = false\n this.status('info', 'Hub disconnected — log forwarding paused')\n // Re-wait for reconnect\n broker.waitForServices('log-receiver')\n .then(() => {\n this.hubConnected = true\n this.status('info', 'Hub reconnected — log forwarding resumed')\n this.flushOutbound()\n })\n .catch(() => { /* broker stopped */ })\n }\n })\n }\n\n write(entry: LogEntry): void {\n // 1. Forward to hub when connected, otherwise buffer for flush-on-connect.\n if (this.hubConnected && this.broker) {\n this.forward(entry)\n return\n }\n this.bufferOutbound(entry)\n\n // 2. Local console output ONLY as a cold-start fallback. Forked-worker\n // stdout is already piped to the hub's terminal; once the hub\n // ingests our forwarded entry it renders it there. Printing\n // locally would show the same line twice.\n const line = formatLogLine(entry, { colorize: true })\n if (entry.level === 'error') console.error(line)\n else if (entry.level === 'warn') console.warn(line)\n else console.log(line)\n }\n\n async query(_filter: LogFilter): Promise<readonly LogEntry[]> {\n // Agent does not support log queries — hub holds the queryable store.\n return []\n }\n\n async shutdown(): Promise<void> {\n this.hubConnected = false\n this.broker = null\n this.outboundBuffer.length = 0\n }\n\n private bufferOutbound(entry: LogEntry): void {\n this.outboundBuffer.push(entry)\n // Ring-buffer: drop oldest entries once we're past the cap so the\n // outbound buffer never grows without bound.\n if (this.outboundBuffer.length > DEFAULT_OUTBOUND_BUFFER_SIZE) {\n this.outboundBuffer.splice(0, this.outboundBuffer.length - DEFAULT_OUTBOUND_BUFFER_SIZE)\n }\n }\n\n private flushOutbound(): void {\n if (!this.broker || !this.hubConnected) return\n const pending = this.outboundBuffer.splice(0, this.outboundBuffer.length)\n for (const entry of pending) {\n this.forward(entry)\n }\n }\n\n private forward(entry: LogEntry): void {\n if (!this.broker) return\n this.broker.call('log-receiver.ingest', {\n level: entry.level,\n message: entry.message,\n addonId: entry.tags?.addonId ?? 'agent',\n nodeId: entry.tags?.nodeId ?? this.broker.nodeID,\n ...(entry.scope !== undefined ? { scope: entry.scope } : {}),\n ...(entry.tags ? { tags: entry.tags } : {}),\n ...(entry.meta ? { meta: entry.meta } : {}),\n }).catch(() => {\n // Hub unreachable — silently drop. Will resume on reconnect.\n })\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { EventCategory } from '@camstack/types'\nimport type { IScopedLogger, IEventBus, BackupManifest } from '@camstack/types'\n\nexport type { BackupManifest }\n\nexport interface BackupConfig {\n readonly backupDir: string\n readonly retentionCount: number\n}\n\nexport class LocalBackupService {\n private manifests: BackupManifest[] = []\n\n constructor(\n private readonly config: BackupConfig,\n private readonly logger: IScopedLogger,\n private readonly eventBus: IEventBus,\n ) {}\n\n /** Create a backup of specified locations */\n async backup(options?: {\n locations?: string[]\n label?: string\n }): Promise<BackupManifest> {\n const id = randomUUID()\n const timestamp = Date.now()\n const locations = options?.locations ?? ['config', 'events', 'logs']\n\n this.logger.info('Starting backup', { meta: { backupId: id, locations } })\n\n const manifest: BackupManifest = {\n id,\n timestamp,\n label: options?.label,\n locations,\n sizeMB: 0,\n path: `${this.config.backupDir}/${id}`,\n }\n\n const updated = [...this.manifests, manifest]\n this.manifests = updated\n\n await this.pruneOldBackups()\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'local-backup' },\n category: EventCategory.BackupCompleted,\n data: { backupId: id, locations: [...locations], sizeMB: manifest.sizeMB },\n })\n\n this.logger.info('Backup completed', { meta: { backupId: id } })\n return manifest\n }\n\n /** Restore from a backup */\n async restore(backupId: string): Promise<void> {\n const manifest = this.manifests.find((m) => m.id === backupId)\n if (!manifest) throw new Error(`Backup ${backupId} not found`)\n\n this.logger.info('Restoring from backup', { meta: { backupId } })\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'local-backup' },\n category: EventCategory.BackupRestored,\n data: { backupId },\n })\n }\n\n /** List all backups sorted by timestamp descending */\n list(): readonly BackupManifest[] {\n return [...this.manifests].sort((a, b) => b.timestamp - a.timestamp)\n }\n\n /** Delete a specific backup */\n async delete(backupId: string): Promise<void> {\n this.manifests = this.manifests.filter((m) => m.id !== backupId)\n }\n\n private async pruneOldBackups(): Promise<void> {\n const sorted = [...this.manifests].sort((a, b) => a.timestamp - b.timestamp)\n\n while (sorted.length > this.config.retentionCount) {\n const oldest = sorted.shift()\n if (oldest) {\n this.logger.info('Pruning old backup', { meta: { backupId: oldest.id } })\n this.manifests = this.manifests.filter((m) => m.id !== oldest.id)\n }\n }\n }\n}\n","import * as path from 'node:path'\nimport type { ProviderRegistration } from '@camstack/types'\nimport { BaseAddon, backupCapability } from '@camstack/types'\nimport { LocalBackupService } from './local-backup.js'\nimport type { BackupConfig } from './local-backup.js'\n\ninterface LocalBackupAddonConfig {\n readonly retentionCount: number\n}\n\n/**\n * Local backup addon — snapshot-based backup/restore of camstack data.\n * Settings appear under Cluster → NodeDetail → Settings.\n */\nexport class LocalBackupAddon extends BaseAddon<LocalBackupAddonConfig> {\n private service: LocalBackupService | null = null\n\n constructor() {\n super({ retentionCount: 7 })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const backupConfig: BackupConfig = {\n backupDir: path.join(\n await this.ctx.api.storage.resolve.query({ location: 'data', relativePath: '' }).catch(() => 'camstack-data'),\n 'backups',\n ),\n retentionCount: this.config.retentionCount,\n }\n this.service = new LocalBackupService(backupConfig, this.ctx.logger, this.ctx.eventBus)\n const backupProvider = {\n trigger: (input?: { locations?: string[]; label?: string }) => this.service!.backup(input),\n list: () => this.service!.list(),\n restore: (input: { backupId: string }) => this.service!.restore(input.backupId),\n delete: (input: { backupId: string }) => this.service!.delete(input.backupId),\n }\n this.ctx.logger.info('Local Backup initialized')\n return [{ capability: backupCapability, provider: backupProvider }]\n }\n\n protected async onShutdown(): Promise<void> {\n this.service = null\n }\n\n getService(): LocalBackupService {\n if (!this.service) throw new Error('Local Backup not initialized')\n return this.service\n }\n\n protected globalSettingsSchema() {\n return this.schema({\n sections: [{\n id: 'backup-retention',\n title: 'Backup Retention',\n description: 'How many local backup snapshots to keep on disk.',\n columns: 1,\n fields: [\n this.field({\n type: 'number',\n key: 'retentionCount',\n label: 'Retention Count',\n description: 'Number of backup snapshots to keep before deleting the oldest',\n min: 1, max: 100, step: 1, default: 7,\n }),\n ],\n }],\n })\n }\n}\n","import type {\n AddonInstance,\n IMetricsProvider,\n KillProcessInput,\n KillProcessResult,\n NodeProcess,\n ProviderRegistration,\n} from '@camstack/types'\nimport { BaseAddon, EventCategory, createEvent, metricsProviderCapability } from '@camstack/types'\nimport { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { NativeMetricsProvider } from './native-metrics-provider.js'\n\nconst execFileAsync = promisify(execFile)\n\n/**\n * Regex matching camstack-related command lines. We surface anything with\n * an obvious camstack fingerprint so operators can spot stray inference\n * pools, leaked tsx watchers, and zombie node workers in the Cluster →\n * Agent → Processes tab.\n *\n * Patterns mirror `scripts/hunt-zombies.sh` — keep them in sync when\n * adding a new long-lived subprocess.\n */\nconst CAMSTACK_CMD_RE = /(camstack|tsx\\s+watch\\s.*launcher\\.ts|packages\\/agent\\/dist\\/cli\\.js|inference_pool\\.py|bench-(inference-pool|nodeav)|node .*\\/packages\\/)/\n\n/**\n * Boundary patterns: ancestry walks that pass through a process whose\n * command line matches one of these are considered to be inside an\n * \"intentional camstack tree\". Anything reachable by walking up the\n * pid tree from such a boundary is `system` — not a ghost.\n *\n * The boundaries are:\n * - `tsx watch .../launcher.ts` — hub launcher (npm run dev:server)\n * - `node .../packages/agent/dist/cli.js` — agent CLI (dev-cluster, npm run dev:agent)\n * - `concurrently` — dev-cluster orchestrator that runs hub + admin-ui + agents\n * - `npm exec ` / `npm-cli.js` — npm wrappers driving the above\n * - `vite` — admin-ui dev server (sibling of hub under concurrently)\n *\n * The classification logic (`classifyByAncestry`) walks each candidate\n * pid up to ppid=1; if any ancestor matches this regex, the candidate\n * is `system`. Reaching ppid=1 without crossing a boundary = `ghost`.\n */\nconst SUPERVISOR_BOUNDARY_RE = /(tsx\\s+watch\\s.*launcher\\.ts|packages\\/agent\\/dist\\/cli\\.js|\\.bin\\/concurrently|\\/concurrently\\/dist|\\bnpm-cli\\.js\\b|npm exec |\\.bin\\/vite|\\/vite\\/bin\\/vite\\.js|node_modules\\/\\.bin\\/(vite|concurrently|tsup|rollup|esbuild|tsx)(\\s|$))/\n\ninterface NativeMetricsConfig {\n readonly samplingIntervalMs: number\n}\n\n/**\n * Cadence for the per-node metric snapshot bus events. ~5 s matches\n * the existing UI polling cadence (ProcessesTab, ProcessResources)\n * and stays within the sampling interval so consumers always see a\n * fresh-from-OS payload.\n */\nconst METRICS_SNAPSHOT_INTERVAL_MS = 5_000\n/**\n * Force a metrics-snapshot emit at least every 60s even when the\n * coarsened payload looks unchanged. Without this an idle node\n * (steady CPU within ±5%, no process churn) goes silent on the\n * bus and the UI's \"node alive\" chip can stale out.\n */\nconst METRICS_SNAPSHOT_HEARTBEAT_MS = 60_000\n\n/**\n * Coarsen CPU/mem percentages to integer buckets before deduping.\n * Without this every 5s tick differs by ±0.3% and the equality check\n * always fails, so the snapshot fans out unconditionally.\n */\nfunction coarsenResourcesSnapshot(snapshot: unknown): string {\n if (!snapshot || typeof snapshot !== 'object') return JSON.stringify(snapshot)\n // Walk the object and round any value that looks like a percent.\n const round = (v: unknown): unknown => {\n if (typeof v === 'number') {\n // CPU% / mem% / disk% all sit in 0..100. Bucket to nearest 5%.\n // Anything outside (uptime, byte counts) gets rounded to 100k\n // so byte deltas under that don't fire emits.\n if (v >= 0 && v <= 100) return Math.round(v / 5) * 5\n return Math.round(v / 100_000) * 100_000\n }\n if (Array.isArray(v)) return v.map(round)\n if (v && typeof v === 'object') {\n const out: Record<string, unknown> = {}\n for (const [k, val] of Object.entries(v as Record<string, unknown>)) {\n out[k] = round(val)\n }\n return out\n }\n return v\n }\n return JSON.stringify(round(snapshot))\n}\n\n/**\n * Coarsen a process list before deduping — pid, addonId, state +\n * bucketed cpu%. Drops cmdline / cwd / start time / uptime which\n * change every tick on a process that's just running. The result\n * is \"process X has the same role and roughly the same load\" =\n * skip emit.\n */\nfunction coarsenProcessList(processes: readonly unknown[]): string {\n const summary = processes\n .filter((p): p is Record<string, unknown> => !!p && typeof p === 'object')\n .map((p) => {\n const pid = p['pid']\n const addonId = p['addonId']\n const state = p['state']\n const cpu = typeof p['cpuPercent'] === 'number' ? Math.round((p['cpuPercent'] as number) / 5) * 5 : null\n const mem = typeof p['memoryRss'] === 'number' ? Math.round((p['memoryRss'] as number) / (50 * 1024 * 1024)) : null\n return [pid, addonId, state, cpu, mem]\n })\n return JSON.stringify(summary)\n}\n\n// Shape of the ProcessInfo returned by the kernel `$process.list` Moleculer action.\n// Not imported from @camstack/kernel — core cannot depend on kernel. Keep the shape\n// minimal + narrow the state field at the boundary.\ninterface KernelProcessInfo {\n readonly pid: number\n readonly nodeId: string\n readonly addonId: string\n readonly state: string\n readonly cpuPercent: number\n readonly memoryRss: number\n readonly uptimeSeconds: number\n}\n\ntype WorkerState = 'starting' | 'running' | 'stopping' | 'stopped' | 'crashed'\n\nfunction narrowWorkerState(state: string): WorkerState {\n switch (state) {\n case 'starting':\n case 'running':\n case 'stopping':\n case 'stopped':\n case 'crashed':\n return state\n default:\n return 'running'\n }\n}\n\n/**\n * Native metrics — CPU, memory, disk usage sampling.\n * Settings appear under Cluster → NodeDetail → Settings.\n */\nexport default class NativeMetricsAddon extends BaseAddon<NativeMetricsConfig> {\n private provider: NativeMetricsProvider | null = null\n private startedAtMs: number = Date.now()\n private snapshotTimer: ReturnType<typeof setInterval> | null = null\n /**\n * Snapshot-equality cache for the resources + processes emit.\n * Stores the coarsened JSON and timestamp; a tick where the\n * coarsened payload matches the cache (and the heartbeat hasn't\n * elapsed) is skipped.\n */\n private lastResourcesEmit: { coarse: string; emittedAt: number } | null = null\n private lastProcessesEmit: { coarse: string; emittedAt: number } | null = null\n\n constructor() {\n super({ samplingIntervalMs: 5000 })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const provider = new NativeMetricsProvider()\n provider.setDiagnostics({\n warn: (message, meta) => this.ctx.logger.warn(message, { meta: meta ?? {} }),\n })\n provider.startSampling(this.config.samplingIntervalMs)\n this.provider = provider\n this.startedAtMs = Date.now()\n this.ctx.logger.info('Native metrics provider started', { meta: { intervalMs: this.config.samplingIntervalMs } })\n\n const composed: IMetricsProvider = {\n collectSnapshot: () => provider.collectSnapshot(),\n getCached: () => provider.getCached(),\n getCurrent: () => provider.getCurrent(),\n getDiskSpace: (params) => provider.getDiskSpace(params),\n getGpuInfo: () => provider.getGpuInfo(),\n getCpuTemperature: () => provider.getCpuTemperature(),\n getProcessStats: (params) => provider.getProcessStats(params),\n listAddonInstances: () => this.listAddonInstances(),\n getAddonStats: (params) => this.getAddonStats(params.addonId),\n listNodeProcesses: () => this.listNodeProcesses(),\n killProcess: (params) => this.killProcess(params),\n }\n\n // Periodic snapshot emission — UI dashboards subscribe to these\n // categories instead of polling `getCached` /\n // `listNodeProcesses`. One full SystemResourceSnapshot + one\n // NodeProcess[] per node per tick.\n this.snapshotTimer = setInterval(\n () => this.emitMetricsSnapshots(),\n METRICS_SNAPSHOT_INTERVAL_MS,\n )\n\n return [{ capability: metricsProviderCapability, provider: composed }]\n }\n\n protected async onShutdown(): Promise<void> {\n if (this.snapshotTimer) {\n clearInterval(this.snapshotTimer)\n this.snapshotTimer = null\n }\n this.provider?.stopSampling()\n this.provider = null\n }\n\n /**\n * Emit one `metrics.node-resources-snapshot` + one\n * `metrics.node-processes-snapshot` for this node. UI consumers\n * subscribe and read state directly from the payload.\n */\n private async emitMetricsSnapshots(): Promise<void> {\n const provider = this.provider\n const eventBus = this.ctx.eventBus\n if (!provider || !eventBus) return\n const rawNodeId = this.ctx.kernel.localNodeId ?? this.ctx.id\n const nodeId = rawNodeId.includes('/') ? rawNodeId.split('/')[0]! : rawNodeId\n const timestamp = Date.now()\n\n // Resources snapshot — uses the cached sample (the provider's\n // background sampler already runs at samplingIntervalMs).\n try {\n const cached = await provider.getCached()\n const snapshot = cached ?? (await provider.collectSnapshot())\n const coarse = coarsenResourcesSnapshot(snapshot)\n const prev = this.lastResourcesEmit\n const heartbeatDue = !prev || timestamp - prev.emittedAt >= METRICS_SNAPSHOT_HEARTBEAT_MS\n if (!prev || prev.coarse !== coarse || heartbeatDue) {\n this.lastResourcesEmit = { coarse, emittedAt: timestamp }\n eventBus.emit(createEvent(\n EventCategory.MetricsNodeResourcesSnapshot,\n { type: 'node', id: nodeId, nodeId },\n { nodeId, snapshot, timestamp },\n ))\n }\n } catch {\n // Soft-fail: dashboards tolerate a missing tick.\n }\n\n // Process tree snapshot — heavier (`ps -eo`) but still well under\n // the snapshot interval. Skip on failure rather than block the\n // resources event above.\n try {\n const processes = await this.listNodeProcesses()\n const coarse = coarsenProcessList(processes)\n const prev = this.lastProcessesEmit\n const heartbeatDue = !prev || timestamp - prev.emittedAt >= METRICS_SNAPSHOT_HEARTBEAT_MS\n if (!prev || prev.coarse !== coarse || heartbeatDue) {\n this.lastProcessesEmit = { coarse, emittedAt: timestamp }\n eventBus.emit(createEvent(\n EventCategory.MetricsNodeProcessesSnapshot,\n { type: 'node', id: nodeId, nodeId },\n { nodeId, processes, timestamp },\n ))\n }\n } catch {\n // Soft-fail.\n }\n }\n\n protected async onConfigChanged(): Promise<void> {\n this.provider?.stopSampling()\n this.provider?.startSampling(this.config.samplingIntervalMs)\n }\n\n private async listWorkerInstances(): Promise<readonly KernelProcessInfo[]> {\n const broker = this.ctx.kernel.cluster?.broker\n if (!broker) return []\n try {\n return await broker.call<void, readonly KernelProcessInfo[]>('$process.list')\n } catch {\n // $process service not running on this node (workers, remote agents) —\n // a benign empty list.\n return []\n }\n }\n\n private async listAddonInstances() {\n const broker = this.ctx.kernel.cluster?.broker\n const hubNodeId = broker?.nodeID ?? 'hub'\n const uptimeSec = Math.max(0, Math.floor((Date.now() - this.startedAtMs) / 1000))\n const instances: AddonInstance[] = [{\n addonId: '$hub',\n nodeId: hubNodeId,\n role: 'hub',\n pid: process.pid,\n state: 'running',\n uptimeSec,\n }]\n const workers = await this.listWorkerInstances()\n for (const w of workers) {\n instances.push({\n addonId: w.addonId,\n nodeId: w.nodeId,\n role: 'worker',\n pid: w.pid,\n state: narrowWorkerState(w.state),\n uptimeSec: w.uptimeSeconds,\n })\n }\n return instances\n }\n\n private async getAddonStats(addonId: string) {\n const provider = this.provider\n if (!provider) return null\n if (addonId === '$hub') {\n const stats = await provider.getProcessStats({ pids: [process.pid] })\n return stats[0] ?? null\n }\n const workers = await this.listWorkerInstances()\n const target = workers.find((w) => w.addonId === addonId)\n if (!target) return null\n const stats = await provider.getProcessStats({ pids: [target.pid] })\n return stats[0] ?? null\n }\n\n /**\n * Walk the OS process table and classify each camstack-shaped process.\n *\n * Classification (ancestry-driven, NOT pattern-driven):\n * - root — the current node's own pid (`process.pid`).\n * - managed — pid is registered in the kernel's `$process.list`\n * (forked addon worker spawned by this hub).\n * - system — ancestry walk crosses a SUPERVISOR_BOUNDARY_RE match\n * (tsx-watch launcher, agent CLI, concurrently, vite,\n * npm exec wrapper). The process belongs to the dev\n * tree even if not in `$process.list`. NEVER killable.\n * - ghost — ancestry walk reaches `ppid=1` without crossing any\n * supervisor boundary AND the parent isn't visible in\n * `ps`. A truly orphaned camstack-shaped process. The\n * ONLY classification that's eligible for kill.\n *\n * Old pattern-only ghost detection produced false positives: every\n * monorepo-path process matched CAMSTACK_CMD_RE, ancestry walk\n * stopping at ppid=hub returned false-positive ghosts whenever a\n * concurrently sibling sat above hub. Ancestry-driven classification\n * fixes that.\n */\n private async listNodeProcesses(): Promise<readonly NodeProcess[]> {\n const ps = await this.runPs()\n if (ps.length === 0) return []\n\n const managedPids = new Map<number, { addonId: string; nodeId: string }>()\n const workers = await this.listWorkerInstances()\n for (const w of workers) {\n managedPids.set(w.pid, { addonId: w.addonId, nodeId: w.nodeId })\n }\n\n const hubNodeId = this.ctx.kernel.cluster?.broker?.nodeID ?? 'hub'\n const selfPid = process.pid\n\n // pid→{ppid, command} map for the ancestry walk. Indexes every visible\n // ps row regardless of CAMSTACK_CMD_RE match — we need command lines\n // for non-camstack ancestors (concurrently, npm exec) that act as\n // boundaries.\n const psIndex = new Map<number, { ppid: number; command: string }>()\n for (const p of ps) psIndex.set(p.pid, { ppid: p.ppid, command: p.command })\n\n /**\n * Walk ancestry from `pid` up to ppid=1 (or until we leave the ps\n * snapshot). Returns:\n * - 'system' — crossed a SUPERVISOR_BOUNDARY_RE ancestor\n * - 'ghost' — reached ppid=1 OR the parent isn't visible in ps\n * without crossing a boundary\n *\n * `selfPid` itself is treated as a boundary (this node's own root).\n */\n const classifyByAncestry = (startPid: number): 'system' | 'ghost' => {\n let cur = startPid\n for (let depth = 0; depth < 32; depth++) {\n const node = psIndex.get(cur)\n if (!node) return 'ghost' // parent left the scan — treat as orphan\n if (cur === selfPid) return 'system'\n if (SUPERVISOR_BOUNDARY_RE.test(node.command)) return 'system'\n if (node.ppid === 1) return 'ghost'\n if (node.ppid === selfPid) return 'system'\n cur = node.ppid\n }\n return 'system' // 32-deep ancestry = something weird, default safe\n }\n\n const out: NodeProcess[] = []\n for (const p of ps) {\n if (!CAMSTACK_CMD_RE.test(p.command)) continue\n const managed = managedPids.get(p.pid)\n let classification: NodeProcess['classification']\n if (p.pid === selfPid) {\n classification = 'root'\n } else if (managed) {\n classification = 'managed'\n } else {\n classification = classifyByAncestry(p.pid)\n }\n const orphaned = classification === 'ghost'\n\n out.push({\n pid: p.pid,\n ppid: p.ppid,\n pgid: p.pgid,\n classification,\n addonId: managed?.addonId ?? null,\n nodeId: managed?.nodeId ?? (p.pid === selfPid ? hubNodeId : null),\n command: p.command,\n cpuPercent: p.cpuPercent,\n memoryRssBytes: p.memoryRssBytes,\n uptimeSec: p.uptimeSec,\n orphaned,\n })\n }\n return out\n }\n\n /**\n * Send SIGTERM / SIGKILL to a pid. Refuses pids that don't appear in\n * `listNodeProcesses()` to prevent arbitrary system kills — a dedicated\n * admin-path for resurrected zombies, not a generic shell replacement.\n *\n * `root`-classified pids (the running launcher / agent CLI / hub itself)\n * are also refused: killing them tears down the whole node and the\n * operator's intent is almost always to nuke a leaked child, not the\n * supervisor that keeps the rest alive. Process restart goes through\n * the dedicated `$process.restart` action, not this kill API.\n */\n private async killProcess(input: KillProcessInput): Promise<KillProcessResult> {\n const visible = await this.listNodeProcesses()\n const match = visible.find((p) => p.pid === input.pid)\n if (!match) {\n return { success: false, reason: 'pid not in node process table' }\n }\n if (match.classification === 'root' || match.classification === 'system') {\n this.ctx.logger.warn('Refused to kill protected process', {\n meta: { pid: input.pid, classification: match.classification, addonId: match.addonId, command: match.command },\n })\n const reason = match.classification === 'root'\n ? 'cannot kill root (current node supervisor)'\n : 'cannot kill system (intentional dev-tree ancestor — vite, concurrently, npm, etc.)'\n return { success: false, reason }\n }\n const signal: 'SIGTERM' | 'SIGKILL' = input.force ? 'SIGKILL' : 'SIGTERM'\n try {\n process.kill(input.pid, signal)\n this.ctx.logger.info('Killed node process', { meta: { pid: input.pid, signal, classification: match.classification, addonId: match.addonId } })\n return { success: true, signal }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n return { success: false, reason: msg, signal }\n }\n }\n\n /** Raw `ps` scan returning every pid + command + resource stats. */\n private async runPs(): Promise<readonly {\n pid: number\n ppid: number\n pgid: number\n cpuPercent: number\n memoryRssBytes: number\n uptimeSec: number\n command: string\n }[]> {\n try {\n const { stdout } = await execFileAsync(\n 'ps',\n ['-eo', 'pid=,ppid=,pgid=,pcpu=,rss=,etime=,command='],\n { timeout: 5_000, maxBuffer: 8 * 1024 * 1024 },\n )\n const lines = stdout.split('\\n')\n const rows: {\n pid: number\n ppid: number\n pgid: number\n cpuPercent: number\n memoryRssBytes: number\n uptimeSec: number\n command: string\n }[] = []\n for (const line of lines) {\n const trimmed = line.trim()\n if (!trimmed) continue\n const match = trimmed.match(/^(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+([\\d.]+)\\s+(\\d+)\\s+(\\S+)\\s+(.+)$/)\n if (!match) continue\n const [, pidS, ppidS, pgidS, cpuS, rssS, etimeS, command] = match\n rows.push({\n pid: parseInt(pidS!, 10),\n ppid: parseInt(ppidS!, 10),\n pgid: parseInt(pgidS!, 10),\n cpuPercent: Math.round(parseFloat(cpuS!) * 10) / 10,\n memoryRssBytes: parseInt(rssS!, 10) * 1024,\n uptimeSec: parseEtime(etimeS!),\n command: command!,\n })\n }\n return rows\n } catch (err) {\n this.ctx.logger.warn('ps scan failed', { meta: { error: err instanceof Error ? err.message : String(err) } })\n return []\n }\n }\n\n protected globalSettingsSchema() {\n return this.schema({\n sections: [{\n id: 'native-metrics-settings',\n title: 'System Metrics',\n fields: [\n this.field({\n type: 'number',\n key: 'samplingIntervalMs',\n label: 'Sampling Interval',\n description: 'How often to collect system metrics',\n min: 1000,\n max: 60000,\n step: 1000,\n default: 5000,\n unit: 'ms',\n }),\n ],\n }],\n })\n }\n}\n\n/**\n * Parse `ps etime` format → seconds.\n *\n * Formats we handle:\n * `MM:SS` (< 1h)\n * `HH:MM:SS` (< 1d)\n * `DD-HH:MM:SS` (>= 1d)\n */\nfunction parseEtime(etime: string): number {\n const dashParts = etime.split('-')\n let days = 0\n let hms = etime\n if (dashParts.length === 2) {\n days = parseInt(dashParts[0]!, 10) || 0\n hms = dashParts[1]!\n }\n const parts = hms.split(':').map((p) => parseInt(p, 10) || 0)\n let hours = 0, minutes = 0, seconds = 0\n if (parts.length === 3) [hours, minutes, seconds] = parts as [number, number, number]\n else if (parts.length === 2) [minutes, seconds] = parts as [number, number]\n else if (parts.length === 1) [seconds] = parts as [number]\n return days * 86400 + hours * 3600 + minutes * 60 + seconds\n}\n","import * as os from 'node:os'\nimport * as fs from 'node:fs'\nimport { execFile, execFileSync } from 'node:child_process'\nimport type {\n SystemResourceSnapshot,\n CpuBreakdown,\n MemoryInfo,\n DiskSpaceInfo,\n DiskIoSnapshot,\n NetworkIoSnapshot,\n MetricsGpuInfo,\n ProcessResourceInfo,\n PressureInfo,\n PidResourceStats,\n} from '@camstack/types'\n\nconst IS_DARWIN = os.platform() === 'darwin'\nconst IS_LINUX = os.platform() === 'linux'\n\n// Node.js internal API — no public type declarations exist.\n// _getActiveHandles and _getActiveRequests are undocumented but stable across all LTS versions.\ninterface NodeProcessInternals {\n _getActiveHandles?: () => unknown[]\n _getActiveRequests?: () => unknown[]\n}\n\n// ===========================================================================\n// NativeMetricsProvider — implements the metrics-provider capability using\n// OS-level APIs. Zero external dependencies. Works on macOS and Linux.\n//\n// Lifecycle methods (startSampling/stopSampling) and the `id` field are\n// NOT part of the capability contract — they live on the class for addon\n// lifecycle use. Only the async methods declared on IMetricsProvider cross\n// the tRPC/Moleculer boundary.\n// ===========================================================================\n\ninterface SamplingDiagnostics {\n warn(message: string, meta?: Record<string, unknown>): void\n}\n\nexport class NativeMetricsProvider {\n readonly id = 'native'\n\n private cachedSnapshot: SystemResourceSnapshot | null = null\n private samplingTimer: ReturnType<typeof setInterval> | null = null\n private macMemTimer: ReturnType<typeof setInterval> | null = null\n private prevCpu: CpuTimes\n private diagnostics: SamplingDiagnostics | null = null\n private consecutiveSampleErrors = 0\n\n constructor() {\n this.prevCpu = aggregateCpuTimes()\n }\n\n /**\n * Optional diagnostics sink for sampling errors. The first failure and\n * every Nth failure thereafter are reported so a permanently-broken\n * collector doesn't spam logs but is still observable.\n */\n setDiagnostics(diag: SamplingDiagnostics): void {\n this.diagnostics = diag\n }\n\n // ─── Lifecycle (not on the cap contract) ────────────────────────────\n\n startSampling(intervalMs: number): void {\n // Seed macOS vm_stat cache immediately\n if (IS_DARWIN) {\n sampleMacMemory(this)\n this.macMemTimer = setInterval(() => sampleMacMemory(this), 5000)\n if (this.macMemTimer.unref) this.macMemTimer.unref()\n }\n\n // First sample immediately\n this.collectSnapshot()\n .then((s) => { this.cachedSnapshot = s; this.consecutiveSampleErrors = 0 })\n .catch((err: unknown) => this.reportSampleError(err))\n\n this.samplingTimer = setInterval(() => {\n this.collectSnapshot()\n .then((s) => { this.cachedSnapshot = s; this.consecutiveSampleErrors = 0 })\n .catch((err: unknown) => this.reportSampleError(err))\n }, intervalMs)\n if (this.samplingTimer.unref) this.samplingTimer.unref()\n }\n\n private reportSampleError(err: unknown): void {\n this.consecutiveSampleErrors++\n if (!this.diagnostics) return\n // First failure + every 60th sample (~1/min at 1s interval)\n const shouldLog = this.consecutiveSampleErrors === 1 || this.consecutiveSampleErrors % 60 === 0\n if (!shouldLog) return\n this.diagnostics.warn('metrics-provider sample failed', {\n consecutiveErrors: this.consecutiveSampleErrors,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n\n stopSampling(): void {\n if (this.samplingTimer) { clearInterval(this.samplingTimer); this.samplingTimer = null }\n if (this.macMemTimer) { clearInterval(this.macMemTimer); this.macMemTimer = null }\n }\n\n // ─── Cap contract — async methods ───────────────────────────────────\n\n async collectSnapshot(): Promise<SystemResourceSnapshot> {\n const cpu = this.sampleCpu()\n const memory = this.getMemoryInfo()\n const processInfo = getProcessResources()\n\n const [gpu, network, disk, cpuTemp] = await Promise.all([\n getGpuInfoInternal().catch(() => null),\n takeNetworkIoSnapshot(),\n takeDiskIoSnapshot(),\n getCpuTemperatureInternal().catch(() => null),\n ])\n\n const snapshot: SystemResourceSnapshot = {\n cpu,\n memory,\n gpu,\n network,\n disk,\n pressure: {\n cpu: getPressure('cpu'),\n memory: getPressure('memory'),\n io: getPressure('io'),\n },\n process: processInfo,\n cpuTemperature: cpuTemp,\n timestampMs: Date.now(),\n }\n\n this.cachedSnapshot = snapshot\n return snapshot\n }\n\n async getCached(): Promise<SystemResourceSnapshot | null> {\n return this.cachedSnapshot\n }\n\n async getCurrent(): Promise<{\n cpuPercent: number\n memoryPercent: number\n memoryUsedMB: number\n memoryTotalMB: number\n diskPercent?: number\n temperature?: number\n gpuPercent?: number\n gpuMemoryPercent?: number\n }> {\n const s = this.cachedSnapshot ?? await this.collectSnapshot()\n const mb = (bytes: number) => Math.round(bytes / 1024 / 1024)\n return {\n cpuPercent: s.cpu.total,\n memoryPercent: s.memory.percent,\n memoryUsedMB: mb(s.memory.usedBytes),\n memoryTotalMB: mb(s.memory.totalBytes),\n temperature: s.cpuTemperature ?? undefined,\n gpuPercent: s.gpu?.utilization,\n gpuMemoryPercent:\n s.gpu && s.gpu.memoryTotalBytes > 0\n ? Math.round((s.gpu.memoryUsedBytes / s.gpu.memoryTotalBytes) * 1000) / 10\n : undefined,\n }\n }\n\n async getDiskSpace(input: { dirPath: string }): Promise<DiskSpaceInfo> {\n return getDiskSpaceInternal(input.dirPath)\n }\n\n async getGpuInfo(): Promise<MetricsGpuInfo | null> {\n return getGpuInfoInternal()\n }\n\n async getCpuTemperature(): Promise<number | null> {\n return getCpuTemperatureInternal()\n }\n\n async getProcessStats(input: { pids: number[] }): Promise<PidResourceStats[]> {\n const { getPidStats } = await import('../../process/resource-monitor.js')\n const raw = await getPidStats(input.pids)\n const result: PidResourceStats[] = []\n for (const [pid, s] of raw) {\n result.push({ pid, cpu: s.cpu, memory: s.memory })\n }\n return result\n }\n\n // ─── Internal: CPU sampling ─────────────────────────────────────────\n\n private sampleCpu(): CpuBreakdown {\n const curr = aggregateCpuTimes()\n const prev = this.prevCpu\n this.prevCpu = curr\n\n const dUser = curr.user - prev.user\n const dNice = curr.nice - prev.nice\n const dSys = curr.sys - prev.sys\n const dIrq = curr.irq - prev.irq\n const dIdle = curr.idle - prev.idle\n const dTotal = dUser + dNice + dSys + dIrq + dIdle\n\n const pct = (v: number) => dTotal === 0 ? 0 : Math.round((v / dTotal) * 1000) / 10\n\n return {\n total: pct(dUser + dNice + dSys + dIrq),\n user: pct(dUser),\n system: pct(dSys),\n irq: pct(dIrq),\n nice: pct(dNice),\n loadAvg: os.loadavg() as [number, number, number],\n cores: os.cpus().length,\n }\n }\n\n // ─── Internal: Memory ───────────────────────────────────────────────\n\n /** Cached macOS memory (set by sampleMacMemory timer). */\n _cachedMacMem: MemoryInfo | null = null\n\n private getMemoryInfo(): MemoryInfo {\n const total = os.totalmem()\n if (total === 0) {\n return { percent: 0, totalBytes: 0, usedBytes: 0, availableBytes: 0, swapUsedBytes: 0, swapTotalBytes: 0 }\n }\n\n if (IS_DARWIN && this._cachedMacMem !== null) {\n return this._cachedMacMem\n }\n\n const free = os.freemem()\n const used = total - free\n let swapUsedBytes = 0\n let swapTotalBytes = 0\n\n if (IS_LINUX) {\n try {\n const meminfo = fs.readFileSync('/proc/meminfo', 'utf-8')\n const swapTotal = parseInt(meminfo.match(/SwapTotal:\\s+(\\d+)/)?.[1] ?? '0', 10) * 1024\n const swapFree = parseInt(meminfo.match(/SwapFree:\\s+(\\d+)/)?.[1] ?? '0', 10) * 1024\n swapTotalBytes = swapTotal\n swapUsedBytes = swapTotal - swapFree\n } catch { /* ignore */ }\n }\n\n return {\n percent: Math.round(((total - free) / total) * 1000) / 10,\n totalBytes: total,\n usedBytes: used,\n availableBytes: free,\n swapUsedBytes,\n swapTotalBytes,\n }\n }\n}\n\n// ===========================================================================\n// Internal helpers (module-private, no side effects at import time)\n// ===========================================================================\n\ninterface CpuTimes {\n user: number\n nice: number\n sys: number\n irq: number\n idle: number\n}\n\nfunction aggregateCpuTimes(): CpuTimes {\n const cpus = os.cpus()\n let user = 0, nice = 0, sys = 0, irq = 0, idle = 0\n for (const cpu of cpus) {\n user += cpu.times.user\n nice += cpu.times.nice\n sys += cpu.times.sys\n irq += cpu.times.irq\n idle += cpu.times.idle\n }\n return { user, nice, sys, irq, idle }\n}\n\n// ─── macOS vm_stat memory sampling ─────────────────────────────────────────\n\nfunction sampleMacMemory(provider: NativeMetricsProvider): void {\n try {\n const output = execFileSync('vm_stat', { timeout: 2000, encoding: 'utf-8' })\n const pageSize = 16384 // macOS ARM64\n const parse = (label: string): number => {\n const match = output.match(new RegExp(`${label}:\\\\s+(\\\\d+)`))\n return match ? parseInt(match[1]!, 10) * pageSize : 0\n }\n\n const free = parse('Pages free')\n const inactive = parse('Pages inactive')\n const purgeable = parse('Pages purgeable')\n const speculative = parse('Pages speculative')\n const available = free + inactive + purgeable + speculative\n const total = os.totalmem()\n const used = total - available\n\n let swapUsedBytes = 0\n let swapTotalBytes = 0\n try {\n const swapOut = execFileSync('sysctl', ['-n', 'vm.swapusage'], { timeout: 2000, encoding: 'utf-8' })\n const totalMatch = swapOut.match(/total\\s*=\\s*([\\d.]+)M/)\n const usedMatch = swapOut.match(/used\\s*=\\s*([\\d.]+)M/)\n if (totalMatch) swapTotalBytes = parseFloat(totalMatch[1]!) * 1024 * 1024\n if (usedMatch) swapUsedBytes = parseFloat(usedMatch[1]!) * 1024 * 1024\n } catch { /* ignore */ }\n\n provider._cachedMacMem = {\n percent: Math.round((used / total) * 1000) / 10,\n totalBytes: total,\n usedBytes: used,\n availableBytes: available,\n swapUsedBytes,\n swapTotalBytes,\n }\n } catch {\n provider._cachedMacMem = null\n }\n}\n\n// ─── Disk space ────────────────────────────────────────────────────────────\n\nfunction getDiskSpaceInternal(dirPath: string): Promise<DiskSpaceInfo> {\n return new Promise((resolve, reject) => {\n fs.statfs(dirPath, (err, stats) => {\n if (err) return reject(err)\n const totalBytes = stats.blocks * stats.bsize\n const availableBytes = stats.bavail * stats.bsize\n const usedBytes = totalBytes - (stats.bfree * stats.bsize)\n resolve({\n path: dirPath,\n totalBytes,\n usedBytes,\n availableBytes,\n percent: totalBytes > 0 ? Math.round((usedBytes / totalBytes) * 1000) / 10 : 0,\n })\n })\n })\n}\n\n// ─── Disk I/O ──────────────────────────────────────────────────────────────\n\nasync function takeDiskIoSnapshot(): Promise<DiskIoSnapshot> {\n const now = Date.now()\n\n if (IS_LINUX) {\n try {\n const data = fs.readFileSync('/proc/diskstats', 'utf-8')\n let readOps = 0, readBytes = 0, writeOps = 0, writeBytes = 0\n for (const line of data.split('\\n')) {\n const parts = line.trim().split(/\\s+/)\n if (parts.length < 14) continue\n const devName = parts[2]!\n if (/\\d+$/.test(devName) && !/^nvme\\d+n\\d+$/.test(devName)) continue\n readOps += parseInt(parts[3]!, 10) || 0\n readBytes += (parseInt(parts[5]!, 10) || 0) * 512\n writeOps += parseInt(parts[7]!, 10) || 0\n writeBytes += (parseInt(parts[9]!, 10) || 0) * 512\n }\n return { readBytes, writeBytes, readOps, writeOps, timestampMs: now }\n } catch { /* fallback */ }\n }\n\n return { readBytes: 0, writeBytes: 0, readOps: 0, writeOps: 0, timestampMs: now }\n}\n\n// ─── Network I/O ───────────────────────────────────────────────────────────\n\nasync function takeNetworkIoSnapshot(): Promise<NetworkIoSnapshot> {\n const now = Date.now()\n\n if (IS_LINUX) {\n try {\n const data = fs.readFileSync('/proc/net/dev', 'utf-8')\n let rxBytes = 0, txBytes = 0, rxPackets = 0, txPackets = 0, rxErrors = 0, txErrors = 0\n for (const line of data.split('\\n')) {\n const match = line.match(/^\\s*(\\w+):\\s+(.+)$/)\n if (!match) continue\n if (match[1] === 'lo') continue\n const cols = match[2]!.trim().split(/\\s+/)\n rxBytes += parseInt(cols[0]!, 10) || 0\n rxPackets += parseInt(cols[1]!, 10) || 0\n rxErrors += parseInt(cols[2]!, 10) || 0\n txBytes += parseInt(cols[8]!, 10) || 0\n txPackets += parseInt(cols[9]!, 10) || 0\n txErrors += parseInt(cols[10]!, 10) || 0\n }\n return { rxBytes, txBytes, rxPackets, txPackets, rxErrors, txErrors, timestampMs: now }\n } catch { /* fallback */ }\n }\n\n if (IS_DARWIN) {\n try {\n const stdout = await execAsync('netstat', ['-ib'])\n let rxBytes = 0, txBytes = 0, rxPackets = 0, txPackets = 0, rxErrors = 0, txErrors = 0\n for (const line of stdout.split('\\n')) {\n const parts = line.trim().split(/\\s+/)\n if (parts.length < 11) continue\n if (parts[0] === 'lo0' || parts[0] === 'Name') continue\n if (!parts[2]?.startsWith('Link#')) continue\n rxPackets += parseInt(parts[4]!, 10) || 0\n rxErrors += parseInt(parts[5]!, 10) || 0\n rxBytes += parseInt(parts[6]!, 10) || 0\n txPackets += parseInt(parts[7]!, 10) || 0\n txErrors += parseInt(parts[8]!, 10) || 0\n txBytes += parseInt(parts[9]!, 10) || 0\n }\n return { rxBytes, txBytes, rxPackets, txPackets, rxErrors, txErrors, timestampMs: now }\n } catch { /* fallback */ }\n }\n\n return { rxBytes: 0, txBytes: 0, rxPackets: 0, txPackets: 0, rxErrors: 0, txErrors: 0, timestampMs: now }\n}\n\n// ─── CPU temperature ───────────────────────────────────────────────────────\n\nasync function getCpuTemperatureInternal(): Promise<number | null> {\n if (IS_LINUX) {\n const paths = ['/sys/class/thermal/thermal_zone0/temp', '/sys/class/hwmon/hwmon0/temp1_input']\n for (const p of paths) {\n try {\n const raw = fs.readFileSync(p, 'utf-8').trim()\n const millideg = parseInt(raw, 10)\n if (!isNaN(millideg)) return Math.round(millideg / 100) / 10\n } catch { continue }\n }\n }\n\n if (IS_DARWIN) {\n try {\n const stdout = await execAsync('sudo', ['-n', 'powermetrics', '--samplers', 'smc', '-i', '1', '-n', '1'], 3000)\n const match = stdout.match(/CPU die temperature:\\s+([\\d.]+)\\s*C/)\n if (match) return Math.round(parseFloat(match[1]!) * 10) / 10\n } catch { /* no root */ }\n }\n\n return null\n}\n\n// ─── GPU info ──────────────────────────────────────────────────────────────\n\nasync function getGpuInfoInternal(): Promise<MetricsGpuInfo | null> {\n if (IS_DARWIN) {\n try {\n const stdout = await execAsync('ioreg', ['-r', '-d', '1', '-c', 'IOAccelerator'])\n const utilMatch = stdout.match(/\"GPU Core Utilization\"\\s*=\\s*(\\d+)/)\n const util = utilMatch ? parseInt(utilMatch[1]!, 10) : 0\n const utilPct = util > 1000 ? Math.round(util / 10000000) : util\n return {\n utilization: Math.min(100, utilPct),\n model: 'Apple Silicon GPU',\n memoryUsedBytes: 0,\n memoryTotalBytes: 0,\n temperature: null,\n }\n } catch { /* ignore */ }\n }\n\n if (IS_LINUX) {\n try {\n const stdout = await execAsync('nvidia-smi', [\n '--query-gpu=utilization.gpu,name,memory.used,memory.total,temperature.gpu',\n '--format=csv,noheader,nounits',\n ])\n const parts = stdout.trim().split(',').map(s => s.trim())\n if (parts.length >= 5) {\n return {\n utilization: parseInt(parts[0]!, 10) || 0,\n model: parts[1] ?? 'Unknown GPU',\n memoryUsedBytes: (parseInt(parts[2]!, 10) || 0) * 1024 * 1024,\n memoryTotalBytes: (parseInt(parts[3]!, 10) || 0) * 1024 * 1024,\n temperature: parseInt(parts[4]!, 10) || null,\n }\n }\n } catch { /* no nvidia-smi */ }\n }\n\n return null\n}\n\n// ─── Process resources ─────────────────────────────────────────────────────\n\nfunction getProcessResources(): ProcessResourceInfo {\n let openFds = 0\n let threadCount = 0\n\n if (IS_LINUX) {\n try { openFds = fs.readdirSync(`/proc/${process.pid}/fd`).length } catch { /* ignore */ }\n try {\n const status = fs.readFileSync(`/proc/${process.pid}/status`, 'utf-8')\n const match = status.match(/Threads:\\s+(\\d+)/)\n if (match) threadCount = parseInt(match[1]!, 10)\n } catch { /* ignore */ }\n }\n\n const nodeProcess = process as typeof process & NodeProcessInternals\n return {\n openFds,\n threadCount,\n activeHandles: (nodeProcess._getActiveHandles?.() ?? []).length,\n activeRequests: (nodeProcess._getActiveRequests?.() ?? []).length,\n }\n}\n\n// ─── Linux PSI ─────────────────────────────────────────────────────────────\n\nfunction getPressure(resource: 'cpu' | 'memory' | 'io'): PressureInfo | null {\n if (!IS_LINUX) return null\n try {\n const data = fs.readFileSync(`/proc/pressure/${resource}`, 'utf-8')\n const parseLine = (prefix: string) => {\n const match = data.match(new RegExp(`${prefix} avg10=(\\\\d+\\\\.\\\\d+) avg60=(\\\\d+\\\\.\\\\d+) avg300=(\\\\d+\\\\.\\\\d+)`))\n if (!match) return null\n return { avg10: parseFloat(match[1]!), avg60: parseFloat(match[2]!), avg300: parseFloat(match[3]!) }\n }\n const some = parseLine('some')\n if (!some) return null\n return { some, full: parseLine('full') }\n } catch {\n return null\n }\n}\n\n// ─── Util ──────────────────────────────────────────────────────────────────\n\nfunction execAsync(cmd: string, args: string[], timeoutMs = 5000): Promise<string> {\n return new Promise((resolve, reject) => {\n execFile(cmd, args, { timeout: timeoutMs }, (err, stdout) => {\n if (err) return reject(err)\n resolve(stdout)\n })\n })\n}\n","import {\n EventCategory,\n type KnownEventCategory,\n type SystemEvent,\n type ProviderRegistration,\n} from '@camstack/types'\nimport type { Alert, AlertSeverity, AlertStatus } from '@camstack/types'\nimport { BaseAddon, AlertSchema, alertsCapability, createEvent , errMsg } from '@camstack/types'\n\n// ── Category → severity mapping ─────────────────────────────────────\n\ninterface CategoryMapping {\n readonly severity: AlertSeverity\n readonly titleTemplate: string\n}\n\nconst CATEGORY_MAPPINGS: Readonly<Record<string, CategoryMapping>> = {\n // ── Critical — always surface ──────────────────────────────────────\n 'addon.crashed': { severity: 'error', titleTemplate: 'Addon crashed' },\n 'addon.error': { severity: 'error', titleTemplate: 'Addon error' },\n 'process.crashed': { severity: 'error', titleTemplate: 'Process crashed' },\n 'recording.error': { severity: 'error', titleTemplate: 'Recording error' },\n 'recording.storage.critical': { severity: 'warning', titleTemplate: 'Storage critical' },\n 'notification.failed': { severity: 'error', titleTemplate: 'Notification failed' },\n\n // ── Cluster — agent connect/disconnect ─────────────────────────────\n 'agent.online': { severity: 'info', titleTemplate: 'Agent connected' },\n 'agent.offline': { severity: 'warning', titleTemplate: 'Agent disconnected' },\n\n // ── System lifecycle ──────────────────────────────────────────────\n 'system.boot': { severity: 'info', titleTemplate: 'System boot' },\n 'system.restarting': { severity: 'warning', titleTemplate: 'System restarting' },\n\n // ── Device lifecycle (add/remove only, not settings tweaks) ───────\n 'device.registered': { severity: 'info', titleTemplate: 'Device registered' },\n 'device.unregistered': { severity: 'warning', titleTemplate: 'Device unregistered' },\n\n // ── Package management ────────────────────────────────────────────\n 'addon.installed': { severity: 'info', titleTemplate: 'Addon installed' },\n 'addon.updated': { severity: 'info', titleTemplate: 'Addon updated' },\n 'addon.uninstalled': { severity: 'info', titleTemplate: 'Addon uninstalled' },\n\n // ── Backup (rare, important) ──────────────────────────────────────\n 'backup.completed': { severity: 'info', titleTemplate: 'Backup completed' },\n 'backup.restored': { severity: 'info', titleTemplate: 'Backup restored' },\n\n // ── Model downloads (in-progress merging path) ────────────────────\n 'model.download.progress': { severity: 'info', titleTemplate: 'Model download' },\n}\n\nconst TRACKED_CATEGORIES = Object.keys(CATEGORY_MAPPINGS)\n\n/**\n * `[ALERT-CENTER-EVENTS]` — rate limiting. Events that fire thousands of\n * times a minute (flaky cam reconnecting, chatty integration, …) would\n * flood the alert feed and push genuinely important alerts off the\n * visible page. We collapse bursts into a single throttled summary per\n * `(category, source.id)` tuple: the first N events within the window\n * still surface as individual alerts, but once the source crosses the\n * threshold we stop emitting alerts for it and wait out the window.\n *\n * A standalone category-count map is cleared on every window rollover.\n * Keep the threshold generous enough that legitimate bursts of ~a few\n * per minute still get through, but strict enough that a reconnect loop\n * firing every second gets muted.\n */\nconst RATE_LIMIT_WINDOW_MS = 60_000\nconst RATE_LIMIT_MAX_PER_SOURCE = 5\n\n/** Parse a raw settings record into a validated Alert. */\nfunction parseAlert(record: { id: string; data: Record<string, unknown> }): Alert {\n return AlertSchema.parse({ id: record.id, ...record.data })\n}\n\n// ── Alert Center Addon ─────────────────────────────────────────────\n\ninterface AlertCenterConfig {\n readonly maxAlerts: number\n readonly retentionDays: number\n}\n\nconst DEFAULT_CONFIG: AlertCenterConfig = {\n maxAlerts: 500,\n retentionDays: 30,\n}\n\nconst ALERTS_COLLECTION = 'alerts'\nconst EVENT_SOURCE = { type: 'addon', id: 'alert-center' } as const\n\n/**\n * Alert Center addon — core builtin that persists alerts in a\n * structured SQLite table and serves them to the admin UI.\n *\n * Registers as an `alerts` collection provider and subscribes to\n * important EventBus categories to create/update alerts automatically.\n */\nexport class AlertCenterAddon extends BaseAddon<AlertCenterConfig> {\n private unsubscribers: readonly (() => void)[] = []\n\n constructor() {\n super({ ...DEFAULT_CONFIG })\n }\n\n /**\n * Per `(category, source.id)` counter used to rate-limit chatty\n * events. Entries are pruned lazily when they age out of\n * `RATE_LIMIT_WINDOW_MS`; see `shouldSuppressByRate()` below.\n */\n private readonly rateLimitCounters = new Map<string, { firstAt: number; count: number; suppressedLogged: boolean }>()\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const alertsProvider = {\n emit: (alert: Alert) => this.emitAlert(alert),\n update: (input: { alertId: string; patch: Partial<Alert> }) =>\n this.updateAlert(input.alertId, input.patch),\n list: (filter?: { unreadOnly?: boolean; limit?: number }) =>\n this.listAlerts(filter),\n getUnreadCount: () => this.getUnreadCount(),\n markRead: (input: { alertId: string }) => this.markRead(input.alertId),\n markAllRead: () => this.markAllRead(),\n dismiss: (input: { alertId: string }) => this.dismiss(input.alertId),\n }\n\n const unsubs: (() => void)[] = []\n for (const category of TRACKED_CATEGORIES) {\n const unsub = this.ctx.eventBus.subscribe(\n { category: category as KnownEventCategory },\n (event: SystemEvent) => { void this.handleEvent(category, event) },\n )\n unsubs.push(unsub)\n }\n this.unsubscribers = unsubs\n\n this.ctx.logger.info('Initialized', { meta: { trackedCategoriesCount: TRACKED_CATEGORIES.length } })\n return [{ capability: alertsCapability, provider: alertsProvider }]\n }\n\n protected async onShutdown(): Promise<void> {\n for (const unsub of this.unsubscribers) {\n unsub()\n }\n this.unsubscribers = []\n }\n\n protected globalSettingsSchema() {\n return this.schema({\n sections: [{\n id: 'alerts',\n title: 'Alert Center',\n description: 'Configure alert storage and retention.',\n columns: 1,\n fields: [\n this.field({\n type: 'number', key: 'maxAlerts', label: 'Maximum stored alerts',\n description: 'Oldest read alerts are deleted when this limit is exceeded.',\n min: 50, max: 5000, step: 50, default: 500,\n }),\n this.field({\n type: 'number', key: 'retentionDays', label: 'Alert retention (days)',\n description: 'Alerts older than this are automatically removed.',\n min: 1, max: 365, step: 1, default: 30,\n }),\n ],\n }],\n })\n }\n\n // ── Public methods (called by the tRPC router) ────────────────────\n\n async listAlerts(filter?: { unreadOnly?: boolean; limit?: number }): Promise<readonly Alert[]> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return []\n\n const whereClause: Record<string, unknown> = {}\n if (filter?.unreadOnly) {\n whereClause.read = false\n }\n\n const records = await backend.query.query({ collection: ALERTS_COLLECTION, filter: {\n where: Object.keys(whereClause).length > 0 ? whereClause : undefined,\n orderBy: { field: 'updatedAt', direction: 'desc' },\n limit: filter?.limit ?? 100,\n } })\n\n return records.map(parseAlert)\n }\n\n async getUnreadCount(): Promise<number> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return 0\n\n return backend.count.query({ collection: ALERTS_COLLECTION, filter: { where: { read: false } } })\n }\n\n async markRead(alertId: string): Promise<void> {\n await this.mergeUpdate(alertId, { read: true, updatedAt: Date.now() })\n }\n\n async markAllRead(): Promise<void> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return\n\n const unread = await backend.query.query({ collection: ALERTS_COLLECTION, filter: { where: { read: false } } })\n const now = Date.now()\n for (const record of unread) {\n await this.mergeUpdate(record.id, { read: true, updatedAt: now })\n }\n }\n\n async dismiss(alertId: string): Promise<void> {\n await this.mergeUpdate(alertId, {\n status: 'dismissed' satisfies AlertStatus,\n read: true,\n updatedAt: Date.now(),\n })\n }\n\n // ── Private: event handling ──────────────────────────────────────\n\n private async handleEvent(category: string, event: SystemEvent): Promise<void> {\n try {\n if (category === 'model.download.progress') {\n // Model download progress has its own in-progress merging path\n // that intentionally overwrites a single alert per model, so\n // rate limiting does not apply here — the merger itself is the\n // collapse mechanism.\n await this.handleModelDownload(event)\n return\n }\n\n const mapping = CATEGORY_MAPPINGS[category]\n if (!mapping) return\n\n if (this.shouldSuppressByRate(category, event)) return\n\n const message = this.buildMessage(category, event.data)\n const alert: Alert = {\n id: crypto.randomUUID(),\n category,\n severity: mapping.severity,\n title: mapping.titleTemplate,\n message,\n status: 'active',\n read: false,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n source: event.source ? { type: event.source.type, id: String(event.source.id) } : undefined,\n metadata: event.data,\n }\n\n await this.emitAlert(alert)\n } catch (err) {\n this.ctx.logger?.warn(\n 'Failed to handle event',\n { meta: { category, error: errMsg(err) } },\n )\n }\n }\n\n private async handleModelDownload(event: SystemEvent): Promise<void> {\n const data = event.data\n const modelId = (data.modelId as string | undefined) ?? 'unknown'\n const progress = (data.progress as number | undefined) ?? 0\n const stableId = `model-download:${modelId}`\n\n const backend = this.ctx.api.settingsStore\n if (!backend) return\n\n // Check if an in-progress alert already exists for this model\n const existing = await backend.query.query({ collection: ALERTS_COLLECTION, filter: {\n where: { id: stableId },\n } })\n\n if (existing.length > 0) {\n // Update existing alert (read-merge-write)\n const now = Date.now()\n if (progress >= 100) {\n await this.mergeUpdate(stableId, {\n status: 'completed' satisfies AlertStatus,\n progress: 100,\n message: `Model \"${modelId}\" download completed`,\n updatedAt: now,\n })\n this.emitAlertUpdatedEvent(stableId, { status: 'completed', progress: 100 })\n } else if (progress < 0) {\n await this.mergeUpdate(stableId, {\n status: 'failed' satisfies AlertStatus,\n message: `Model \"${modelId}\" download failed`,\n updatedAt: now,\n })\n this.emitAlertUpdatedEvent(stableId, { status: 'failed' })\n } else {\n await this.mergeUpdate(stableId, {\n progress,\n message: `Downloading model \"${modelId}\" — ${String(Math.round(progress))}%`,\n updatedAt: now,\n })\n this.emitAlertUpdatedEvent(stableId, { progress })\n }\n } else {\n // Create new in-progress alert\n const alert: Alert = {\n id: stableId,\n category: EventCategory.ModelDownloadProgress,\n severity: 'info',\n title: 'Model download',\n message: `Downloading model \"${modelId}\" — ${String(Math.round(progress))}%`,\n status: 'in-progress',\n progress,\n read: false,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n source: event.source ? { type: event.source.type, id: String(event.source.id) } : undefined,\n metadata: { modelId },\n }\n\n await this.persistAlert(alert)\n this.emitAlertCreatedEvent(alert)\n }\n }\n\n /**\n * `[ALERT-CENTER-EVENTS]` — rate limit a `(category, source.id)`\n * tuple. Returns `true` when the caller should DROP this event\n * without persisting an alert, and `false` when the alert should\n * proceed normally.\n *\n * Heuristic: the first `RATE_LIMIT_MAX_PER_SOURCE` events within a\n * `RATE_LIMIT_WINDOW_MS` window go through. Once the threshold is\n * crossed, subsequent events are suppressed until the window rolls\n * over. When the threshold is first crossed, the suppression is\n * logged once so operators know why they're not seeing the follow-\n * up alerts; after the window rolls over the next event is\n * un-suppressed and starts a new window.\n */\n private shouldSuppressByRate(category: string, event: SystemEvent): boolean {\n const sourceId = event.source?.id ?? 'unknown'\n const key = `${category}::${sourceId}`\n const now = Date.now()\n const entry = this.rateLimitCounters.get(key)\n\n if (!entry || now - entry.firstAt > RATE_LIMIT_WINDOW_MS) {\n // First event of a new window — always allow, start the counter.\n this.rateLimitCounters.set(key, { firstAt: now, count: 1, suppressedLogged: false })\n return false\n }\n\n entry.count += 1\n if (entry.count <= RATE_LIMIT_MAX_PER_SOURCE) return false\n\n // Over threshold — suppress the rest of this window.\n if (!entry.suppressedLogged) {\n entry.suppressedLogged = true\n this.ctx.logger?.info(\n 'rate-limiting suppressing remainder of window',\n { meta: { category, sourceId, maxPerSource: RATE_LIMIT_MAX_PER_SOURCE, windowSeconds: RATE_LIMIT_WINDOW_MS / 1000 } },\n )\n }\n return true\n }\n\n private buildMessage(category: string, data: Record<string, unknown>): string {\n const addonId = data.addonId as string | undefined\n const deviceId = data.deviceId as string | undefined\n const error = data.error as string | undefined\n const processId = data.processId as string | undefined\n\n switch (category) {\n case 'addon.crashed':\n return `Addon \"${addonId ?? 'unknown'}\" crashed${error ? `: ${error}` : ''}`\n case 'addon.error':\n return `Addon \"${addonId ?? 'unknown'}\" error${error ? `: ${error}` : ''}`\n case 'addon.installed':\n return `Addon \"${addonId ?? 'unknown'}\" installed`\n case 'addon.updated': {\n const from = data.fromVersion as string | undefined\n const to = data.toVersion as string | undefined\n return `Addon \"${addonId ?? 'unknown'}\" updated${from && to ? ` from ${from} to ${to}` : ''}`\n }\n case 'addon.uninstalled':\n return `Addon \"${addonId ?? 'unknown'}\" uninstalled`\n case 'device.registered':\n return `Device \"${data.name as string | undefined ?? deviceId ?? 'unknown'}\" registered`\n case 'device.unregistered':\n return `Device \"${deviceId ?? 'unknown'}\" unregistered`\n case 'agent.online':\n return `Agent \"${data.agentId as string | undefined ?? data.nodeId as string | undefined ?? 'unknown'}\" connected`\n case 'agent.offline':\n return `Agent \"${data.agentId as string | undefined ?? data.nodeId as string | undefined ?? 'unknown'}\" disconnected${data.reason ? `: ${String(data.reason)}` : ''}`\n case 'backup.completed':\n return `Backup completed${data.targetId ? ` (${String(data.targetId)})` : ''}`\n case 'backup.restored':\n return `Backup restored${data.source ? ` from ${String(data.source)}` : ''}`\n case 'notification.failed':\n return `Notification failed${error ? `: ${error}` : ''}`\n case 'system.restarting':\n return `System restarting${data.reason ? ` — ${String(data.reason)}` : ''}`\n case 'recording.error':\n return `Recording error on device \"${deviceId ?? 'unknown'}\"${error ? `: ${error}` : ''}`\n case 'recording.storage.critical':\n return `Storage critical for device \"${deviceId ?? 'unknown'}\"`\n case 'system.boot':\n return `System booted in \"${data.mode as string | undefined ?? 'unknown'}\" mode`\n case 'process.crashed':\n return `Process \"${processId ?? 'unknown'}\" crashed`\n default:\n return `Event: ${category}`\n }\n }\n\n // ── Private: persistence ─────────────────────────────────────────\n\n private async emitAlert(alert: Alert): Promise<void> {\n await this.persistAlert(alert)\n this.emitAlertCreatedEvent(alert)\n await this.enforceMaxAlerts()\n await this.enforceRetention()\n }\n\n private async updateAlert(alertId: string, patch: Partial<Alert>): Promise<void> {\n await this.mergeUpdate(alertId, { ...patch, updatedAt: Date.now() })\n this.emitAlertUpdatedEvent(alertId, patch)\n }\n\n /**\n * Read-merge-write: SettingsBackend.update() replaces the entire `data` blob,\n * so we must read the existing record, merge the patch, and write back.\n */\n private async mergeUpdate(id: string, patch: Record<string, unknown>): Promise<void> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return\n\n const raw = await backend.get.query({ collection: ALERTS_COLLECTION, key: id })\n if (raw === null || raw === undefined || typeof raw !== 'object') return\n const existing: Record<string, unknown> = Object.fromEntries(Object.entries(raw))\n await backend.set.mutate({ collection: ALERTS_COLLECTION, key: id, value: { ...existing, ...patch } })\n }\n\n private async persistAlert(alert: Alert): Promise<void> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return\n\n // Serialize alert to a plain Record for SQLite JSON storage\n const data: Record<string, unknown> = {\n id: alert.id,\n category: alert.category,\n severity: alert.severity,\n title: alert.title,\n message: alert.message,\n status: alert.status,\n read: alert.read,\n createdAt: alert.createdAt,\n updatedAt: alert.updatedAt,\n ...(alert.progress !== undefined ? { progress: alert.progress } : {}),\n ...(alert.source ? { source: alert.source } : {}),\n ...(alert.metadata ? { metadata: alert.metadata } : {}),\n }\n await backend.set.mutate({ collection: ALERTS_COLLECTION, key: alert.id, value: data })\n }\n\n private emitAlertCreatedEvent(alert: Alert): void {\n this.ctx.eventBus?.emit(createEvent('alert.created', EVENT_SOURCE, {\n id: alert.id,\n category: alert.category,\n severity: alert.severity,\n title: alert.title,\n status: alert.status,\n }))\n }\n\n private emitAlertUpdatedEvent(alertId: string, patch: Partial<Alert>): void {\n const patchRecord: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(patch)) {\n patchRecord[key] = value\n }\n this.ctx.eventBus?.emit(createEvent('alert.updated', EVENT_SOURCE, {\n alertId,\n patch: patchRecord,\n }))\n }\n\n private async enforceMaxAlerts(): Promise<void> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return\n\n const total = await backend.count.query({ collection: ALERTS_COLLECTION })\n if (total <= this.config.maxAlerts) return\n\n // Delete oldest read alerts\n const excess = total - this.config.maxAlerts\n const oldest = await backend.query.query({ collection: ALERTS_COLLECTION, filter: {\n where: { read: true },\n orderBy: { field: 'createdAt', direction: 'asc' },\n limit: excess,\n } })\n\n for (const record of oldest) {\n await backend.delete.mutate({ collection: ALERTS_COLLECTION, key: record.id })\n }\n }\n\n private async enforceRetention(): Promise<void> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return\n\n const cutoff = Date.now() - this.config.retentionDays * 24 * 60 * 60 * 1000\n const expired = await backend.query.query({ collection: ALERTS_COLLECTION, filter: {\n where: { read: true },\n orderBy: { field: 'createdAt', direction: 'asc' },\n } })\n\n for (const record of expired) {\n if (Number(record.data['createdAt'] ?? 0) < cutoff) {\n await backend.delete.mutate({ collection: ALERTS_COLLECTION, key: record.id })\n }\n }\n }\n}\n\nexport default AlertCenterAddon\n","import type {\n ConfigUISchema,\n ConfigUISchemaWithValues,\n} from '@camstack/types'\nimport { BaseAddon, hydrateSchema , errMsg } from '@camstack/types'\n\n/**\n * Built-in `system-config` addon — Phase 4 of the settings redesign.\n *\n * Exposes the cluster-wide yml-backed sections that the bootstrap\n * loader reads before any addon is instantiated — things that cannot\n * live inside an addon because changing them requires a server\n * restart (port, host, dataPath) or because they own no runtime\n * state of their own (auth token expiry, global ffmpeg binary path).\n *\n * Sections exposed:\n * - server (port, host, dataPath — READ-ONLY, loaded from config.yaml at bootstrap)\n * - auth (tokenExpiry)\n * - ffmpeg (binaryPath, hwAccel, threadCount)\n *\n * Sections NOT exposed (each owned by the addon that implements them):\n * - logging → `winston-logging` addon (level + retention)\n * - recording → `recording` addon (segment duration, retention)\n * - retention → analytics / detection addons (per-table retention)\n *\n * Implementation notes:\n * - Runs only on the hub process (yml sections are hub-side state).\n * On agent nodes this addon would still instantiate, but every\n * `ctx.settings.getSection(section)` call would hit an empty\n * ConfigManager section so the UI would show the schema defaults.\n * In practice the built-in loader can skip it on agents; for now we\n * just let it run everywhere because it's harmless.\n * - Reads via `ctx.settings.getSection(section)` and writes via\n * `ctx.settings.setSection(section, patch)` — the explicit\n * yml-section pair on `AddonSettingsApi`.\n * - Does NOT register as a capability provider. It's a pure \"settings\n * surface\" addon — its sole purpose is to expose the yml sections\n * through the new three-level settings API.\n *\n * This addon is declared in `@camstack/core`'s package.json `camstack.addons[]`\n * and loaded automatically via AddonLoader like any other core built-in.\n */\n\n/** Section key → user-facing section title. */\nconst SECTION_TITLES: Readonly<Record<string, string>> = {\n server: 'Server',\n auth: 'Authentication',\n ffmpeg: 'FFmpeg',\n}\n\n/** Keys that map 1:1 to a given yml section — used by `updateGlobalSettings`\n * to figure out which section owns each key in the incoming patch. */\nconst KEY_TO_SECTION: Readonly<Record<string, string>> = {\n // server (read-only)\n port: 'server',\n host: 'server',\n dataPath: 'server',\n // auth\n tokenExpiry: 'auth',\n // ffmpeg\n binaryPath: 'ffmpeg',\n hwAccel: 'ffmpeg',\n threadCount: 'ffmpeg',\n}\n\nexport class SystemConfigAddon extends BaseAddon {\n readonly id = 'system-config'\n\n constructor() { super({}) }\n\n protected async onInitialize(): Promise<void> {\n this.ctx.logger.info('Initialized — exposes yml-backed sections via getGlobalSettings')\n }\n\n // ── Three-level settings API (only `getGlobalSettings` is implemented) ──\n\n private buildGlobalSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'system-config-server',\n title: SECTION_TITLES['server']!,\n description: 'Core server connection settings — read-only, loaded from config.yaml at bootstrap.',\n columns: 2,\n fields: [\n {\n type: 'info',\n key: 'server-restart-note',\n label: 'Restart required',\n content: 'Server settings are read-only. Change them in config.yaml and restart.',\n variant: 'warning',\n },\n { type: 'text', key: 'port', label: 'Port', description: 'Listening port', disabled: true },\n { type: 'text', key: 'host', label: 'Host', description: 'Bind address', disabled: true },\n { type: 'text', key: 'dataPath', label: 'Data Path', description: 'Root data directory', disabled: true, span: 2 },\n ],\n },\n {\n id: 'system-config-auth',\n title: SECTION_TITLES['auth']!,\n description: 'Token and session settings.',\n columns: 1,\n fields: [\n {\n type: 'text',\n key: 'tokenExpiry',\n label: 'Token Expiry',\n description: 'JWT token lifetime (e.g. 24h, 7d, 1h)',\n placeholder: '24h',\n default: '24h',\n },\n ],\n },\n {\n id: 'system-config-ffmpeg',\n title: SECTION_TITLES['ffmpeg']!,\n description: 'FFmpeg binary and hardware acceleration settings.',\n columns: 2,\n fields: [\n {\n type: 'text',\n key: 'binaryPath',\n label: 'Binary Path',\n description: 'Path to ffmpeg executable',\n placeholder: 'ffmpeg',\n default: 'ffmpeg',\n span: 2,\n },\n {\n type: 'select',\n key: 'hwAccel',\n label: 'Hardware Acceleration',\n description: 'GPU decoding/encoding backend',\n default: 'auto',\n options: [\n { value: 'auto', label: 'Auto-detect' },\n { value: 'none', label: 'None (CPU only)' },\n { value: 'videotoolbox', label: 'VideoToolbox (macOS)' },\n { value: 'vaapi', label: 'VA-API (Linux Intel/AMD)' },\n { value: 'qsv', label: 'QSV (Intel Quick Sync)' },\n { value: 'cuda', label: 'CUDA (NVIDIA)' },\n ],\n },\n {\n type: 'number',\n key: 'threadCount',\n label: 'Thread Count',\n description: '0 = auto (let FFmpeg decide)',\n min: 0,\n max: 16,\n step: 1,\n default: 0,\n },\n ],\n },\n ],\n }\n }\n\n async getGlobalSettings(): Promise<ConfigUISchemaWithValues> {\n const schema = this.buildGlobalSchema()\n if (!this.ctx.settings) {\n return hydrateSchema(schema, {})\n }\n\n // Read all yml sections in parallel and merge their values into a\n // single flat record keyed by field name. The `KEY_TO_SECTION` map\n // guarantees uniqueness (each key belongs to exactly one section).\n const sectionNames = Object.keys(SECTION_TITLES)\n const merged: Record<string, unknown> = {}\n for (const section of sectionNames) {\n try {\n const values = await this.ctx.settings!.getSection(section)\n Object.assign(merged, values)\n } catch (err: unknown) {\n const msg = errMsg(err)\n this.ctx.logger.debug('Failed to read section', { meta: { section, error: msg } })\n }\n }\n\n return hydrateSchema(schema, merged)\n }\n\n async updateGlobalSettings(patch: Record<string, unknown>): Promise<void> {\n if (!this.ctx.settings) {\n throw new Error('system-config: ctx.settings not available — cannot write sections')\n }\n\n // Group the patch keys by the section they belong to, then write\n // each section in one shot via ctx.settings.setSection(). The\n // server section is read-only, so any keys targeting it are skipped\n // with a warning.\n const perSection = new Map<string, Record<string, unknown>>()\n for (const [key, value] of Object.entries(patch)) {\n const section = KEY_TO_SECTION[key]\n if (section === undefined) {\n this.ctx.logger.warn('update ignored unknown key (not mapped to any section)', { meta: { key } })\n continue\n }\n if (section === 'server') {\n this.ctx.logger.warn('update ignored read-only server-section key', { meta: { key } })\n continue\n }\n let bucket = perSection.get(section)\n if (!bucket) {\n bucket = {}\n perSection.set(section, bucket)\n }\n bucket[key] = value\n }\n\n for (const [section, sectionPatch] of perSection) {\n await this.ctx.settings!.setSection(section, sectionPatch)\n this.ctx.logger.info('Wrote keys to section', { meta: { section, keyCount: Object.keys(sectionPatch).length } })\n }\n }\n}\n\nexport default SystemConfigAddon\n","/**\n * Local Auth Addon — owns user accounts, API keys, scoped tokens,\n * and local password authentication.\n *\n * Capabilities registered:\n * - `auth-provider` (collection) — local password authentication\n * - `user-management` (singleton) — user CRUD, API keys, scoped tokens\n *\n * Extension: an OIDC addon can register another `auth-provider` entry.\n * The server's login flow iterates the `auth-provider` collection.\n */\nimport type { IUserManagementProvider, ProviderRegistration } from '@camstack/types'\nimport { BaseAddon, authProviderCapability, userManagementCapability } from '@camstack/types'\nimport { AuthManager } from '../../auth/auth-manager.js'\nimport { UserManager, type UserRecord, type UserStorageAccess } from '../../auth/user-manager.js'\nimport { ApiKeyManager, type ApiKeyStorageAccess } from '../../auth/api-key-manager.js'\nimport { ScopedTokenManager } from '../../auth/scoped-token-manager.js'\nimport { declareAuthSchema } from './auth-schema.js'\n\n// ── Auth result (mirrors auth-provider cap) ─────────────────────────\n\ninterface AuthResult {\n readonly userId: string\n readonly username: string\n readonly email?: string\n readonly displayName?: string\n readonly roles?: readonly string[]\n}\n\nfunction toAuthResult(user: UserRecord): AuthResult {\n return {\n userId: user.id,\n username: user.username,\n displayName: user.username,\n roles: [user.role],\n }\n}\n\n// ── Config reader shim ──────────────────────────────────────────────\n\ninterface LocalAuthConfig {\n jwtSecret?: string\n adminUsername?: string\n adminPassword?: string\n}\n\nexport class LocalAuthAddon extends BaseAddon<LocalAuthConfig> {\n private authManager: AuthManager | null = null\n private userManager: UserManager | null = null\n private apiKeyManager: ApiKeyManager | null = null\n private scopedTokenManager: ScopedTokenManager | null = null\n\n constructor() { super({ jwtSecret: '', adminUsername: '', adminPassword: '' }) }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n // Read auth section from the global settings store (config.yaml + env\n // overrides + SQL). Addon-level config (`this.config`) is kept as a\n // fallback for isolated/test environments where ctx.settings is absent.\n const authSection = (await this.ctx.settings?.getSection('auth')) ?? {}\n const resolvedJwtSecret = typeof authSection['jwtSecret'] === 'string'\n ? authSection['jwtSecret']\n : (this.config.jwtSecret ?? '')\n const resolvedAdminUser = typeof authSection['adminUsername'] === 'string' && authSection['adminUsername']\n ? authSection['adminUsername']\n : (this.config.adminUsername ?? '')\n const resolvedAdminPass = typeof authSection['adminPassword'] === 'string' && authSection['adminPassword']\n ? authSection['adminPassword']\n : (this.config.adminPassword ?? '')\n\n const reader = {\n get<T>(path: string): T {\n if (path === 'auth.jwtSecret') return resolvedJwtSecret as unknown as T\n if (path === 'auth.adminUsername') return resolvedAdminUser as unknown as T\n if (path === 'auth.adminPassword') return resolvedAdminPass as unknown as T\n return undefined as unknown as T\n },\n update: (_section: string, data: Record<string, unknown>): void => {\n if (typeof data['jwtSecret'] === 'string') {\n void this.ctx.settings?.setSection('auth', { jwtSecret: data['jwtSecret'] })\n }\n },\n }\n\n this.authManager = new AuthManager(reader, this.ctx.logger)\n\n const store = this.ctx.api?.settingsStore\n if (store) {\n // Own the schema. Same pattern as `pipeline-analytics` — each\n // addon declares its typed collections in `onInitialize`. The\n // backend just exposes the `declareCollection` primitive and\n // doesn't carry domain knowledge about auth tables.\n await declareAuthSchema(store)\n\n const storageAccess: UserStorageAccess & ApiKeyStorageAccess = {\n getStore() { return store },\n }\n this.userManager = new UserManager(storageAccess, this.authManager, reader)\n this.apiKeyManager = new ApiKeyManager(storageAccess, this.authManager)\n this.scopedTokenManager = new ScopedTokenManager(store)\n try {\n await this.userManager.ensureAdminExists()\n } catch (err: unknown) {\n // Surface the underlying cause loudly: AddonRegistry catches\n // and skips on throw, leaving auth.login to return the opaque\n // \"User management not available\" message at runtime. The\n // wrap below makes the actual fault (settings-store query\n // shape regression, sqlite migration glitch, …) visible in\n // both the addon error log and the user-facing error chain.\n const detail = err instanceof Error ? err.message : String(err)\n throw new Error(\n 'local-auth bootstrap failed: ensureAdminExists threw before '\n + '`user-management` could be registered. Most likely a '\n + '`users` collection schema mismatch in the settings-store. '\n + `Underlying: ${detail}`,\n { cause: err },\n )\n }\n } else {\n // Hard fail rather than register a no-op cap that throws\n // \"User management not available\" on every call later — the\n // operator sees the boot-time error instead of a confused login\n // panel. Local-auth without a settings store cannot persist\n // anything, so registering the cap would be a lie.\n throw new Error(\n 'local-auth: settings-store API not available — refusing to '\n + 'register `user-management` cap. Check that `sqlite-storage` '\n + 'addon initialized before `local-auth`.',\n )\n }\n\n // ── auth-provider capability (collection) ──────────────────────\n\n const authProvider = {\n validateCredentials: async (input: { username: string; password: string }): Promise<AuthResult | null> => {\n if (!this.userManager) return null\n const user = await this.userManager.validateCredentials(input.username, input.password)\n return user ? toAuthResult(user) : null\n },\n getLoginUrl: async (): Promise<string> => {\n throw new Error('local-auth: URL-based login not supported')\n },\n handleCallback: async (): Promise<AuthResult> => {\n throw new Error('local-auth: URL-based login not supported')\n },\n validateToken: async (input: { token: string }): Promise<AuthResult | null> => {\n if (!this.authManager || !this.userManager) return null\n try {\n const payload = this.authManager.verifyToken(input.token)\n const userId = payload.userId\n if (!userId) return null\n const user = await this.userManager.findById(userId)\n return user ? toAuthResult(user) : null\n } catch {\n return null\n }\n },\n }\n\n // ── user-management capability (singleton) ─────────────────────\n\n const userMgmt: IUserManagementProvider = {\n listUsers: async () => {\n if (!this.userManager) return []\n return this.userManager.listAll()\n },\n createUser: async (input) => {\n if (!this.userManager) throw new Error('User management not available')\n const record = await this.userManager.create(input)\n const { passwordHash: _, ...summary } = record\n return summary\n },\n updateUser: async (input) => {\n if (!this.userManager) throw new Error('User management not available')\n const { id, ...data } = input\n await this.userManager.update(id, data)\n return { success: true as const }\n },\n deleteUser: async (input) => {\n if (!this.userManager) throw new Error('User management not available')\n await this.userManager.delete(input.id)\n return { success: true as const }\n },\n resetPassword: async (input) => {\n if (!this.userManager) throw new Error('User management not available')\n await this.userManager.resetPassword(input.id, input.newPassword)\n return { success: true as const }\n },\n validateCredentials: async (input) => {\n if (!this.userManager) return null\n const user = await this.userManager.validateCredentials(input.username, input.password)\n return user ?? null\n },\n listApiKeys: async () => {\n if (!this.apiKeyManager) return []\n return this.apiKeyManager.listAll()\n },\n createApiKey: async (input) => {\n if (!this.apiKeyManager) throw new Error('API key management not available')\n const { record, token } = await this.apiKeyManager.create(input)\n const { tokenHash: _, ...summary } = record\n return { token, record: summary }\n },\n revokeApiKey: async (input) => {\n if (!this.apiKeyManager) throw new Error('API key management not available')\n await this.apiKeyManager.revoke(input.id)\n return { success: true as const }\n },\n validateApiKey: async (input) => {\n if (!this.apiKeyManager) return null\n const record = await this.apiKeyManager.validateToken(input.token)\n if (!record) return null\n const { tokenHash: _, ...summary } = record\n return summary\n },\n createScopedToken: async (input) => {\n if (!this.scopedTokenManager) throw new Error('Scoped token management not available')\n // userId comes from the tRPC context in production — for now\n // we use a placeholder. The server's login flow sets the real userId.\n const { token, record } = await this.scopedTokenManager.create('system', input.name, input.scopes, input.expiresAt)\n return { token, record }\n },\n revokeScopedToken: async (input) => {\n if (!this.scopedTokenManager) throw new Error('Scoped token management not available')\n await this.scopedTokenManager.revoke(input.id)\n return { success: true as const }\n },\n validateScopedToken: async (input) => {\n if (!this.scopedTokenManager) return null\n return this.scopedTokenManager.validate(input.token)\n },\n listScopedTokens: async (input) => {\n if (!this.scopedTokenManager) return []\n return this.scopedTokenManager.listForUser(input.userId)\n },\n }\n\n this.ctx.logger.info('registered auth-provider + user-management capabilities')\n return [\n { capability: authProviderCapability, provider: authProvider },\n { capability: userManagementCapability, provider: userMgmt },\n ]\n }\n\n protected async onShutdown(): Promise<void> {\n this.authManager = null\n this.userManager = null\n this.apiKeyManager = null\n this.scopedTokenManager = null\n }\n}\n\nexport default LocalAuthAddon\n","import * as jwt from 'jsonwebtoken'\nimport * as bcrypt from 'bcryptjs'\nimport * as crypto from 'node:crypto'\nimport type { ScopedToken, UserRole, TokenPayload, IScopedLogger } from '@camstack/types'\nimport type { ScopedTokenManager } from './scoped-token-manager.js'\n\n/** Minimal no-op logger for default parameter */\nconst noopLogger: IScopedLogger = {\n debug() {},\n info() {},\n warn() {},\n error() {},\n child() { return noopLogger },\n withTags() { return noopLogger },\n}\n\nexport type { UserRole, TokenPayload }\n\nexport type AuthConfigReader = {\n get<T>(path: string): T\n update(section: string, data: Record<string, unknown>): void\n}\n\nexport class AuthManager {\n private readonly jwtSecret: string\n private scopedTokenManager: ScopedTokenManager | null = null\n private readonly logger: IScopedLogger\n\n constructor(private readonly config: AuthConfigReader, logger: IScopedLogger = noopLogger) {\n this.logger = logger\n const configured = this.config.get<string>('auth.jwtSecret')\n if (configured) {\n this.jwtSecret = configured\n } else {\n const secret = crypto.randomBytes(32).toString('hex')\n // Persist directly into config.yaml so it survives restarts\n this.config.update('auth', { jwtSecret: secret })\n this.logger.info('Generated JWT secret and saved to config.yaml (auth.jwtSecret)')\n this.jwtSecret = secret\n }\n }\n\n signToken(payload: Omit<TokenPayload, 'iat' | 'exp'>): string {\n return jwt.sign({ ...payload }, this.jwtSecret, { expiresIn: '24h' })\n }\n\n verifyToken(token: string): TokenPayload {\n return jwt.verify(token, this.jwtSecret) as TokenPayload\n }\n\n async hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, 10)\n }\n\n async comparePassword(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash)\n }\n\n generateApiKey(): { token: string; hash: string; prefix: string } {\n const token = crypto.randomBytes(32).toString('hex')\n const hash = crypto.createHash('sha256').update(token).digest('hex')\n const prefix = token.slice(0, 8)\n return { token, hash, prefix }\n }\n\n validateApiKey(token: string, storedHash: string): boolean {\n const hash = crypto.createHash('sha256').update(token).digest('hex')\n return hash === storedHash\n }\n\n /**\n * Create a service token for agent/worker authentication.\n * Used when forking workers or when agents register.\n */\n createServiceToken(opts: {\n readonly agentId: string\n readonly role?: string\n readonly expiresIn?: string\n }): string {\n const payload: Record<string, unknown> = {\n userId: opts.agentId,\n username: opts.agentId,\n role: opts.role ?? 'agent',\n type: 'service',\n agentId: opts.agentId,\n allowedProviders: '*',\n allowedDevices: {},\n }\n const expiresIn = (opts.expiresIn ?? '24h') as jwt.SignOptions['expiresIn']\n return jwt.sign(payload as object, this.jwtSecret, { expiresIn })\n }\n\n /**\n * Set the scoped token manager for the auth chain.\n */\n setScopedTokenManager(manager: ScopedTokenManager): void {\n this.scopedTokenManager = manager\n }\n\n /**\n * Validate a scoped token string.\n * Returns the token record if valid, null otherwise.\n */\n async validateScopedToken(rawToken: string): Promise<ScopedToken | null> {\n if (!this.scopedTokenManager) {\n return null\n }\n return this.scopedTokenManager.validate(rawToken)\n }\n\n /**\n * Check whether a scoped token grants access to a given addon/route/capability.\n */\n matchesScopedTokenScope(\n token: ScopedToken,\n addonId?: string,\n routePath?: string,\n capability?: string,\n ): boolean {\n if (!this.scopedTokenManager) {\n return false\n }\n return this.scopedTokenManager.matchesScope(token, addonId, routePath, capability)\n }\n}\n","import * as crypto from 'node:crypto'\nimport type { AuthManager } from './auth-manager.js'\nimport { UserRecordSchema } from '@camstack/types'\nimport type { UserRecord, UserRole, SettingsStoreClient } from '@camstack/types'\nimport { parseRecord } from './parse-record.js'\n\nexport type { UserRecord }\n\ninterface CreateUserInput {\n username: string\n password: string\n role: UserRole\n allowedProviders?: string[] | '*'\n allowedDevices?: Record<string, string[] | '*'>\n}\n\ntype UpdatableUserFields = Partial<Pick<UserRecord, 'role' | 'allowedProviders' | 'allowedDevices'>>\n\nconst USERS_COLLECTION = 'users'\n\nexport interface UserStorageAccess {\n getStore(): SettingsStoreClient\n}\n\nexport interface UserConfigReader {\n get<T>(path: string): T\n}\n\nfunction parseUser(data: Record<string, unknown>): UserRecord {\n return parseRecord('user', UserRecordSchema, data)\n}\n\nexport class UserManager {\n constructor(\n private readonly storageAccess: UserStorageAccess,\n private readonly auth: AuthManager,\n private readonly config: UserConfigReader,\n ) {}\n\n private get store(): SettingsStoreClient {\n return this.storageAccess.getStore()\n }\n\n async create(input: CreateUserInput): Promise<UserRecord> {\n const existing = await this.findByUsername(input.username)\n if (existing) throw new Error(`User with username \"${input.username}\" already exists`)\n\n const passwordHash = await this.auth.hashPassword(input.password)\n const now = Date.now()\n const record: UserRecord = {\n id: crypto.randomUUID(),\n username: input.username,\n passwordHash,\n role: input.role,\n allowedProviders: input.allowedProviders ?? '*',\n allowedDevices: input.allowedDevices ?? {},\n createdAt: now,\n updatedAt: now,\n }\n\n await this.store.insert.mutate({ collection: USERS_COLLECTION, record: { id: record.id, data: { ...record } } })\n return record\n }\n\n async findByUsername(username: string): Promise<UserRecord | null> {\n const results = await this.store.query.query({ collection: USERS_COLLECTION, filter: { where: { username } } })\n if (results.length === 0) return null\n return parseUser(results[0]!.data)\n }\n\n async findById(id: string): Promise<UserRecord | null> {\n const results = await this.store.query.query({ collection: USERS_COLLECTION, filter: { where: { id } } })\n if (results.length === 0) return null\n return parseUser(results[0]!.data)\n }\n\n async validateCredentials(username: string, password: string): Promise<UserRecord | null> {\n const user = await this.findByUsername(username)\n if (!user) return null\n const valid = await this.auth.comparePassword(password, user.passwordHash)\n return valid ? user : null\n }\n\n async listAll(): Promise<Omit<UserRecord, 'passwordHash'>[]> {\n const results = await this.store.query.query({ collection: USERS_COLLECTION })\n return results.map((r) => {\n const parsed = parseUser(r.data)\n const { passwordHash: _ph, ...rest } = parsed\n return rest\n })\n }\n\n async update(id: string, data: UpdatableUserFields): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) throw new Error(`User with id \"${id}\" not found`)\n await this.store.update.mutate({ collection: USERS_COLLECTION, id, data: { ...existing, ...data, updatedAt: Date.now() } })\n }\n\n async delete(id: string): Promise<void> {\n await this.store.delete.mutate({ collection: USERS_COLLECTION, key: id })\n }\n\n async resetPassword(id: string, newPassword: string): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) throw new Error(`User with id \"${id}\" not found`)\n const passwordHash = await this.auth.hashPassword(newPassword)\n await this.store.update.mutate({ collection: USERS_COLLECTION, id, data: { ...existing, passwordHash, updatedAt: Date.now() } })\n }\n\n async ensureAdminExists(): Promise<void> {\n const adminUsername = this.config.get<string>('auth.adminUsername')\n const adminPassword = this.config.get<string>('auth.adminPassword')\n if (!adminUsername || !adminPassword) return\n const existing = await this.findByUsername(adminUsername)\n if (existing) {\n // Admin already exists — sync the password if the configured one has\n // changed. Comparison uses bcrypt.compare against the stored hash\n // (bcrypt includes the per-record salt). When they diverge, re-hash\n // and persist so the config.yaml / env-var is the source of truth.\n const matches = await this.auth.comparePassword(adminPassword, existing.passwordHash)\n if (!matches) {\n await this.resetPassword(existing.id, adminPassword)\n }\n return\n }\n await this.create({ username: adminUsername, password: adminPassword, role: 'super_admin', allowedProviders: '*', allowedDevices: {} })\n }\n}\n","/**\n * Wrap a Zod schema parse with an actionable error message. The\n * settings-store regression that broke local-auth in May 2026 surfaced\n * as an opaque Zod error listing every required field as `undefined`\n * — confusing because the data IS in the DB, just exposed through the\n * wrong shape by `queryDeclared`. This helper makes the failure mode\n * obvious: it explicitly mentions the kind, the offending value's top-\n * level keys, and a hint about the most common cause.\n *\n * `schema` is typed loosely (any with a `parse` method) to avoid the\n * generic ZodTypeAny variance error across Zod major versions when this\n * helper is reused by callers that import schemas from `@camstack/types`.\n */\ninterface ZodLikeSchema<T> {\n parse(data: unknown): T\n}\n\nexport function parseRecord<T>(\n kind: string,\n schema: ZodLikeSchema<T>,\n data: unknown,\n): T {\n try {\n return schema.parse(data)\n } catch (err: unknown) {\n const topKeys = data && typeof data === 'object' && !Array.isArray(data)\n ? Object.keys(data as Record<string, unknown>).join(', ') || '(empty)'\n : `(non-object: ${typeof data})`\n const detail = err instanceof Error ? err.message : String(err)\n const looksDoubleWrapped =\n data\n && typeof data === 'object'\n && !Array.isArray(data)\n && Object.keys(data as Record<string, unknown>).length === 1\n && 'data' in (data as Record<string, unknown>)\n const hint = looksDoubleWrapped\n ? ' This shape is the legacy double-wrap from a stale settings-store query path. Restart the server with the latest @camstack/core build.'\n : ''\n throw new Error(\n `Failed to parse ${kind} from settings store. Top-level keys=[${topKeys}].${hint} Underlying: ${detail}`,\n { cause: err },\n )\n }\n}\n","import * as crypto from 'node:crypto'\nimport type { AuthManager } from './auth-manager.js'\nimport { ApiKeyRecordSchema } from '@camstack/types'\nimport type { ApiKeyRecord, UserRole, SettingsStoreClient } from '@camstack/types'\nimport { parseRecord } from './parse-record.js'\n\nexport type { ApiKeyRecord }\n\ninterface CreateApiKeyInput {\n label: string\n role: UserRole\n allowedProviders?: string[] | '*'\n allowedDevices?: Record<string, string[] | '*'>\n}\n\nconst API_KEYS_COLLECTION = 'api_keys'\n\nexport interface ApiKeyStorageAccess {\n getStore(): SettingsStoreClient\n}\n\nfunction parseApiKey(data: Record<string, unknown>): ApiKeyRecord {\n return parseRecord('api-key', ApiKeyRecordSchema, data)\n}\n\nexport class ApiKeyManager {\n constructor(\n private readonly storageAccess: ApiKeyStorageAccess,\n private readonly auth: AuthManager,\n ) {}\n\n private get store(): SettingsStoreClient {\n return this.storageAccess.getStore()\n }\n\n async create(input: CreateApiKeyInput): Promise<{ record: ApiKeyRecord; token: string }> {\n const { token: rawToken, hash, prefix } = this.auth.generateApiKey()\n const now = Date.now()\n const record: ApiKeyRecord = {\n id: crypto.randomUUID(),\n label: input.label,\n role: input.role,\n allowedProviders: input.allowedProviders ?? '*',\n allowedDevices: input.allowedDevices ?? {},\n tokenHash: hash,\n tokenPrefix: prefix,\n createdAt: now,\n }\n\n await this.store.insert.mutate({ collection: API_KEYS_COLLECTION, record: { id: record.id, data: { ...record } } })\n return { record, token: rawToken }\n }\n\n async validateToken(token: string): Promise<ApiKeyRecord | null> {\n const allKeys = await this.store.query.query({ collection: API_KEYS_COLLECTION })\n for (const entry of allKeys) {\n const record = parseApiKey(entry.data)\n if (this.auth.validateApiKey(token, record.tokenHash)) {\n const updatedData: ApiKeyRecord = { ...record, lastUsedAt: Date.now() }\n await this.store.update.mutate({ collection: API_KEYS_COLLECTION, id: record.id, data: { ...updatedData } })\n return updatedData\n }\n }\n return null\n }\n\n async listAll(): Promise<Omit<ApiKeyRecord, 'tokenHash'>[]> {\n const results = await this.store.query.query({ collection: API_KEYS_COLLECTION })\n return results.map((r) => {\n const parsed = parseApiKey(r.data)\n const { tokenHash: _th, ...rest } = parsed\n return rest\n })\n }\n\n async revoke(id: string): Promise<void> {\n await this.store.delete.mutate({ collection: API_KEYS_COLLECTION, key: id })\n }\n\n async findById(id: string): Promise<ApiKeyRecord | null> {\n const results = await this.store.query.query({ collection: API_KEYS_COLLECTION, filter: { where: { id } } })\n if (results.length === 0) return null\n return parseApiKey(results[0]!.data)\n }\n}\n","import * as crypto from 'node:crypto'\nimport { ScopedTokenSchema } from '@camstack/types'\nimport type { ScopedToken, TokenScope, SettingsStoreClient } from '@camstack/types'\nimport { parseRecord } from './parse-record.js'\n\nconst TOKENS_COLLECTION = 'scoped_tokens'\nconst TOKEN_PREFIX = 'cst_'\n\nfunction parseToken(data: Record<string, unknown>): ScopedToken {\n return parseRecord('scoped-token', ScopedTokenSchema, data)\n}\n\n/**\n * Manages scoped API tokens with restricted addon/route/capability access.\n */\nexport class ScopedTokenManager {\n constructor(private readonly store: SettingsStoreClient) {}\n\n async create(\n userId: string,\n name: string,\n scopes: TokenScope[],\n expiresAt?: number,\n ): Promise<{ token: string; record: ScopedToken }> {\n const rawHex = crypto.randomBytes(32).toString('hex')\n const rawToken = `${TOKEN_PREFIX}${rawHex}`\n const tokenHash = crypto.createHash('sha256').update(rawToken).digest('hex')\n const tokenPrefix = rawToken.slice(0, 12)\n\n const record: ScopedToken = {\n id: crypto.randomUUID(),\n userId,\n name,\n tokenHash,\n tokenPrefix,\n scopes: scopes.map((s) => ({ ...s })),\n expiresAt,\n lastUsedAt: undefined,\n createdAt: Date.now(),\n }\n\n await this.store.insert.mutate({ collection: TOKENS_COLLECTION, record: { id: record.id, data: { ...record } } })\n return { token: rawToken, record }\n }\n\n async validate(rawToken: string): Promise<ScopedToken | null> {\n if (!rawToken.startsWith(TOKEN_PREFIX)) return null\n const tokenHash = crypto.createHash('sha256').update(rawToken).digest('hex')\n const results = await this.store.query.query({ collection: TOKENS_COLLECTION, filter: { where: { tokenHash } } })\n if (results.length === 0) return null\n\n const record = parseToken(results[0]!.data)\n if (record.expiresAt !== undefined && record.expiresAt !== null && Date.now() > record.expiresAt) return null\n this.updateLastUsed(record.id).catch(() => {})\n return record\n }\n\n matchesScope(token: ScopedToken, addonId?: string, routePath?: string, capability?: string): boolean {\n for (const scope of token.scopes) {\n switch (scope.type) {\n case 'addon': if (addonId && scope.target === addonId) return true; break\n case 'route-prefix': if (routePath && routePath.startsWith(scope.target)) return true; break\n case 'capability': if (capability && scope.target === capability) return true; break\n }\n }\n return false\n }\n\n async revoke(tokenId: string): Promise<void> {\n await this.store.delete.mutate({ collection: TOKENS_COLLECTION, key: tokenId })\n }\n\n async listForUser(userId: string): Promise<ScopedToken[]> {\n const results = await this.store.query.query({ collection: TOKENS_COLLECTION, filter: { where: { userId } } })\n return results.map((r) => parseToken(r.data))\n }\n\n async updateLastUsed(tokenId: string): Promise<void> {\n const results = await this.store.query.query({ collection: TOKENS_COLLECTION, filter: { where: { id: tokenId } } })\n if (results.length === 0) return\n const existing = parseToken(results[0]!.data)\n await this.store.update.mutate({ collection: TOKENS_COLLECTION, id: tokenId, data: { ...existing, lastUsedAt: Date.now() } })\n }\n}\n","/**\n * Auth-schema — typed SQL schemas for local-auth's three collections.\n *\n * Mirrors the pattern used by pipeline-analytics (`event-store.ts`,\n * `track-store.ts`): each addon owns its own schema, declared once\n * in `onInitialize` via `store.declareCollection.mutate(...)`.\n *\n * Collection names (no namespace — these are global, single-tenant\n * tables backing the auth layer):\n * - users\n * - api_keys\n * - scoped_tokens\n *\n * Schema migration: when the backend receives `declareCollection` for\n * a name that already exists with a legacy `(id, data)` KV shape, the\n * `ensureTable` helper drops the old table and recreates it. Existing\n * data is wiped — `ensureAdminExists` re-seeds the admin from\n * CAMSTACK_ADMIN_USER / CAMSTACK_ADMIN_PASS on the next boot.\n */\nimport type { SettingsStoreClient } from '@camstack/types'\n\nexport const USERS_COLLECTION = 'users'\nexport const API_KEYS_COLLECTION = 'api_keys'\nexport const SCOPED_TOKENS_COLLECTION = 'scoped_tokens'\n\nconst USERS_COLUMNS = [\n { name: 'id', type: 'TEXT' as const, primaryKey: true, notNull: true },\n { name: 'username', type: 'TEXT' as const, notNull: true, unique: true },\n { name: 'passwordHash', type: 'TEXT' as const, notNull: true },\n { name: 'role', type: 'TEXT' as const, notNull: true },\n { name: 'allowedProviders', type: 'JSON' as const },\n { name: 'allowedDevices', type: 'JSON' as const },\n { name: 'createdAt', type: 'INTEGER' as const, notNull: true },\n { name: 'updatedAt', type: 'INTEGER' as const, notNull: true },\n]\n\nconst API_KEYS_COLUMNS = [\n { name: 'id', type: 'TEXT' as const, primaryKey: true, notNull: true },\n { name: 'label', type: 'TEXT' as const, notNull: true },\n { name: 'role', type: 'TEXT' as const, notNull: true },\n { name: 'tokenHash', type: 'TEXT' as const, notNull: true, unique: true },\n { name: 'tokenPrefix', type: 'TEXT' as const, notNull: true },\n { name: 'allowedProviders', type: 'JSON' as const },\n { name: 'allowedDevices', type: 'JSON' as const },\n { name: 'createdAt', type: 'INTEGER' as const, notNull: true },\n { name: 'lastUsedAt', type: 'INTEGER' as const },\n]\n\nconst SCOPED_TOKENS_COLUMNS = [\n { name: 'id', type: 'TEXT' as const, primaryKey: true, notNull: true },\n { name: 'userId', type: 'TEXT' as const, notNull: true },\n { name: 'name', type: 'TEXT' as const, notNull: true },\n { name: 'tokenHash', type: 'TEXT' as const, notNull: true, unique: true },\n { name: 'tokenPrefix', type: 'TEXT' as const, notNull: true },\n { name: 'scopes', type: 'JSON' as const },\n { name: 'expiresAt', type: 'INTEGER' as const },\n { name: 'lastUsedAt', type: 'INTEGER' as const },\n { name: 'createdAt', type: 'INTEGER' as const, notNull: true },\n]\n\n/**\n * Declare every auth collection with the typed schema. Called by\n * `LocalAuthAddon.onInitialize` before constructing the per-collection\n * managers. Idempotent — `declareCollection` is a no-op when the\n * collection has already been declared (same shape).\n */\nexport async function declareAuthSchema(store: SettingsStoreClient): Promise<void> {\n await store.declareCollection.mutate({\n collection: USERS_COLLECTION,\n columns: USERS_COLUMNS,\n })\n await store.declareCollection.mutate({\n collection: API_KEYS_COLLECTION,\n columns: API_KEYS_COLUMNS,\n indexes: [\n { name: 'idx_api_keys_token_prefix', columns: ['tokenPrefix'] },\n ],\n })\n await store.declareCollection.mutate({\n collection: SCOPED_TOKENS_COLLECTION,\n columns: SCOPED_TOKENS_COLUMNS,\n indexes: [\n { name: 'idx_scoped_tokens_user_id', columns: ['userId'] },\n ],\n })\n}\n","/**\n * Device Manager addon — hub-side singleton that unifies device persistence,\n * live registry queries, and all management operations into a single\n * tRPC-routable capability.\n *\n * Persistence strategy: all device data is stored via `ctx.settings`, the same\n * settings API every other addon uses. No raw SQLite access.\n *\n * Addon store layout:\n * deviceIndex → Record<addonId, stableId[]> (which devices exist per addon)\n * deviceMeta → Record<\"addonId:stableId\", DeviceMeta> (type, name, parentDeviceId, id)\n *\n * Device store (per-device config):\n * readDeviceStore(numericDeviceId) → config blob\n * writeDeviceStore(numericDeviceId, patch)\n *\n * Live registry: resolved from the kernel capability registry after Phase 2.\n * This gives direct access to in-memory IDevice instances registered by provider addons.\n * The DeviceManagerAddon is the single owner of the live device operations API.\n *\n * Replaces:\n * - `device-persistence` capability (absorbed here)\n * - live operations previously served by `device-management.router.ts`\n */\nimport { randomUUID } from 'node:crypto'\nimport { EventCategory,\n ProviderRegistration,\n BaseAddon,\n DeviceType,\n DeviceFeature,\n errMsg,\n} from '@camstack/types'\nimport { DeviceEventPropagator } from './device-event-propagator.js'\nimport { CAP_NAMES_WITH_STATUS } from '@camstack/types'\nimport { WELL_KNOWN_TAB_MAP } from '@camstack/types'\nimport type {\n IDevice,\n ICameraDevice,\n StreamSourceEntry,\n DeviceSettingsContribution,\n ConfigUISchemaWithValues,\n} from '@camstack/types'\n\n/**\n * Wire shape matching `z.infer<typeof SettingsSchemaWithValuesSchema>` —\n * duplicated as a plain interface because importing the Zod schema across\n * package boundaries confuses `tsc` when the types package pins a\n * different `zod` minor than the core package. Keeping the shape local\n * keeps the addon decoupled from the schema's internal type encoding.\n */\ninterface ContributionShape {\n tabs?: Array<{ id: string; label: string; icon: string; order?: number }>\n sections: Array<{\n id: string\n title: string\n description?: string\n style?: 'card' | 'accordion'\n defaultCollapsed?: boolean\n columns?: 1 | 2 | 3 | 4\n tab?: string\n /** Where the section renders. Default 'settings' (Config tab); 'top-tab' hoists into the device-detail tab bar via DeviceDetail discovery. */\n location?: 'settings' | 'top-tab'\n order?: number\n fields: unknown[]\n }>\n}\nimport { deviceManagerCapability, deviceProviderCapability, deviceStateCapability } from '@camstack/types'\nimport type { InferProvider, IDeviceOpsProvider, ICapabilityRegistry } from '@camstack/types'\nimport type { IDeviceRegistry } from '@camstack/types'\nimport type { DeviceBindingEntry } from '@camstack/types'\n\ntype IDeviceManagerProvider = InferProvider<typeof deviceManagerCapability>\ntype IDeviceProviderCap = InferProvider<typeof deviceProviderCapability>\n\n// ── Bindings store types ─────────────────────────────────────────────────────\n\ninterface DeviceBindingsStore {\n readonly deviceBindings: Record<string /* deviceId */, Record<string /* capName */, { wrapperAddonId: string | null }>>\n}\n\ninterface PersistedDeviceMeta {\n type: string\n name: string\n /**\n * Operator-organisational label (room / area / zone). `null` when\n * unset. Mutable through `setLocation` action; surfaced on\n * `IDevice.location` via the kernel-built `DeviceContext.deviceMeta`\n * snapshot. Free-text — providers don't interpret it.\n */\n location: string | null\n /**\n * Soft-disabled flag. When `true`, the device class is still\n * instantiated and visible in the UI (so the operator can flip\n * back on without re-adding) but lifecycle hooks are gated by\n * `BaseDevice.disabled`. Mutable through `setDisabled` action.\n */\n disabled: boolean\n /** Numeric parent id (or null for standalone). The hub resolves the\n * parent's stableId to its numeric id at registration time, and from\n * there everything internal references the parent by `parentDeviceId`\n * — `stableId` only crosses the external boundary (autodiscovery and\n * `(addonId, stableId)` row lookups). */\n parentDeviceId: number | null\n /** Progressive, system-wide unique id. Allocated through\n * `allocateDeviceId` before `registerDevice` runs; backfilled at boot\n * for any legacy meta entry missing it (see init migration below).\n * Post-init invariant: every persisted device has a numeric id. */\n id: number\n /** Snapshot of `device.features` from the most recent `registerDevice`\n * call. Used by `getDevice` when the live `IDevice` instance lives\n * on a forked-worker / remote agent and isn't reachable from the\n * hub registry. Optional for legacy rows that predate the field —\n * callers fall back to an empty array. */\n features?: readonly string[]\n}\n\ninterface AddonStore {\n deviceIndex?: Record<string, string[]>\n deviceMeta?: Record<string, PersistedDeviceMeta>\n /** Hardware-identity metadata blob keyed by `<addonId>:<stableId>`.\n * Stored in a separate key from `deviceMeta` so the lifecycle\n * writers (registerDevice / setName / setLocation / setDisabled)\n * never need to read or preserve the metadata field — single-writer\n * per row eliminates the \"writer X clobbers writer Y's field\" bug\n * class. The `metadata` field on `PersistedDeviceMeta` is a legacy\n * fallback consulted only at read time during the lazy migration —\n * new writes always go to `deviceMetadata`. */\n deviceMetadata?: Record<string, Record<string, unknown>>\n /** Monotonic counter that feeds `PersistedDeviceMeta.id` for every\n * new device. Incremented exactly once per registerDevice; never\n * decremented. */\n nextDeviceId?: number\n /**\n * Operator-curated location registry. Each entry is a free-form room/\n * area label (e.g. \"Cucina\", \"Garage\") that drives the\n * autocomplete in the Device Info location editor. Devices reference\n * these as plain strings via `PersistedDeviceMeta.location` — the\n * registry is purely a suggestion list, NOT a foreign key. Removing a\n * location from the registry leaves devices that still reference it\n * intact; `listLocations` returns the union of registered labels +\n * labels currently in use, so nothing disappears from the UI even if\n * the operator forgot to register a label before assigning it.\n */\n locations?: readonly string[]\n}\n\nfunction shallowEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {\n const ak = Object.keys(a)\n const bk = Object.keys(b)\n if (ak.length !== bk.length) return false\n for (const k of ak) {\n if (a[k] !== b[k]) return false\n }\n return true\n}\n\nfunction deviceKey(addonId: string, stableId: string): string {\n return `${addonId}:${stableId}`\n}\n\n// ── Type guards ──────────────────────────────────────────────────────────────\n\nfunction isCameraDevice(device: IDevice): device is ICameraDevice {\n return 'getStreamSources' in device && typeof (device as ICameraDevice).getStreamSources === 'function'\n}\n\nconst DEVICE_FEATURE_VALUES = new Set<string>(Object.values(DeviceFeature) as readonly string[])\n\n/**\n * Validate persisted feature strings against the `DeviceFeature` enum\n * — workers serialise the live `device.features` array (so every entry\n * is a valid enum value at write time) but the persisted blob is loose\n * `string[]` on the wire. The narrow keeps unknown values out of the\n * `getDevice` response without losing the enum-typed contract.\n */\nfunction persistedFeatures(features: readonly string[] | undefined): DeviceFeature[] {\n if (!features) return []\n const out: DeviceFeature[] = []\n for (const f of features) {\n if (DEVICE_FEATURE_VALUES.has(f)) out.push(f as DeviceFeature)\n }\n return out\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction toDeviceInfo(\n addonId: string,\n device: IDevice,\n metadata: Record<string, unknown> | null = null,\n metaRow: PersistedDeviceMeta | null = null,\n) {\n const configValues: Record<string, unknown> = {}\n for (const entry of device.config.entries()) {\n configValues[entry.key] = entry.value\n }\n // Operator-organisational fields (`name` / `location` / `disabled`)\n // are mutated through `setName` / `setLocation` / `setDisabled`,\n // which write to the persisted `deviceMeta` row and emit\n // `DeviceMetaChanged`. The live `BaseDevice` instance reads these\n // from `ctx.deviceMeta` at CONSTRUCTION ONLY (see\n // `base-device.ts:140-142`), so its `device.name` / `device.location`\n // / `device.disabled` fields are stale until the device class is\n // re-instantiated. Reading from `metaRow` here guarantees the wire\n // response reflects the latest persisted value within one settings\n // round-trip — the UI's enable/disable toggle (and rename) flips\n // immediately after the mutation completes. Falls back to the live\n // device fields when no meta row was supplied (test fixtures, edge\n // paths) so existing behaviour is preserved.\n const name = metaRow?.name ?? device.name\n const location = metaRow?.location !== undefined ? metaRow.location : device.location\n const disabled = metaRow?.disabled ?? device.disabled\n return {\n // Progressive system-wide id — bound on the live `IDevice` at\n // construction time (see `DeviceContext.id` / `BaseDevice.id`). The\n // hub allocates via `allocateDeviceId` BEFORE the device is\n // instantiated, so every live device exposes one.\n id: device.id,\n stableId: device.stableId,\n addonId,\n type: device.type,\n name,\n location,\n disabled,\n parentDeviceId: device.parentDeviceId,\n // `role` is set by the provider on accessory children (synthesized\n // via `getAccessoryChildren()` — Reolink siren/floodlight/PIR,\n // Hikvision supplemental light/siren). Top-level devices and\n // first-class hub-adopted children leave it `undefined`. Surfacing\n // it on `DeviceInfo` lets the UI distinguish accessory rows from\n // adopted-camera rows without re-deriving the heuristic from the\n // provider's `deviceClasses` map.\n role: device.role ?? null,\n online: device.online,\n features: [...device.features],\n isCamera: isCameraDevice(device),\n config: configValues,\n metadata,\n }\n}\n\nfunction resolveDeviceById(\n registry: IDeviceRegistry,\n deviceId: number,\n): { addonId: string; device: IDevice } | null {\n const device = registry.getById(deviceId)\n if (!device) return null\n const addonId = registry.getAddonId(deviceId)\n if (!addonId) return null\n return { addonId, device }\n}\n\n// ── Aggregator merge ─────────────────────────────────────────────────────────\n//\n// Concatenate several contributions into a single wire-shape object matching\n// `z.infer<typeof SettingsSchemaWithValuesSchema>` (plain mutable arrays).\n// Tabs with the same `id` collapse into one; sections within a tab are kept\n// in contribution order (contributors self-sort via `order`).\n//\n// No field-level merge — if two providers target the same `(tab, section)`\n// they're concatenated in discovery order. This is intentional: letting the\n// aggregator pick a winner would mask accidental collisions and silently\n// drop fields.\n//\n// `ContributionShape` / `AggregateShape` mirror the cap output exactly so no\n// assertion is needed when returning from the device-manager handlers.\n\ntype AggregateTabDecl = NonNullable<ContributionShape['tabs']>[number]\ntype AggregateSection = ContributionShape['sections'][number]\n\n/**\n * Walk the sections/fields of a contribution and inject `writerCapName` +\n * `writerAddonId` + `source` on each editable field. Readonly fields and\n * structural fields (separator/info/button) pass through untouched. The\n * aggregator is the single place that knows provenance — provider schemas\n * stay clean, UI-bound metadata is attached once at the boundary.\n */\nfunction tagContribution(\n contribution: ContributionShape,\n capName: string,\n addonId: string,\n kind: 'settings' | 'live',\n): ContributionShape {\n const source = kind === 'settings' ? 'settings' : 'live'\n return {\n ...(contribution.tabs ? { tabs: [...contribution.tabs] } : {}),\n sections: contribution.sections.map(section => ({\n ...section,\n fields: section.fields.map(field => tagField(field, capName, addonId, source, kind)),\n })),\n }\n}\n\nfunction isFieldRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\n/**\n * Convert a strict `ConfigUISchemaWithValues` (readonly arrays, typed\n * field union) into the cap wire shape `ContributionShape` (mutable\n * arrays, opaque field records). Required because the cap method z.infer\n * uses mutable arrays — readonly arrays are not assignable to mutable\n * even when structurally identical, so a structural copy bridges the gap\n * without disabling the type checker.\n */\nfunction toWireShape(input: ConfigUISchemaWithValues): ContributionShape {\n const out: ContributionShape = {\n sections: input.sections.map(s => ({\n id: s.id,\n title: s.title,\n ...(s.description !== undefined ? { description: s.description } : {}),\n ...(s.style !== undefined ? { style: s.style } : {}),\n ...(s.defaultCollapsed !== undefined ? { defaultCollapsed: s.defaultCollapsed } : {}),\n ...(s.columns !== undefined ? { columns: s.columns } : {}),\n ...(s.tab !== undefined ? { tab: s.tab } : {}),\n // `location: 'top-tab'` hoists the section into a discovered top-\n // level device tab in DeviceDetail. Forgetting to forward it here\n // strips the marker before the client sees it, so the tab never\n // shows up — see `DeviceDetail.tsx` aggregate-driven tab discovery.\n ...(s.location !== undefined ? { location: s.location } : {}),\n ...(s.order !== undefined ? { order: s.order } : {}),\n fields: [...s.fields],\n })),\n }\n if (input.tabs) out.tabs = [...input.tabs]\n return out\n}\n\nfunction tagField(\n field: unknown,\n capName: string,\n addonId: string,\n source: 'settings' | 'live',\n kind: 'settings' | 'live',\n): unknown {\n if (!isFieldRecord(field)) return field\n const f = field\n const structuralTypes = new Set(['separator', 'info', 'button'])\n if (typeof f.type === 'string' && structuralTypes.has(f.type)) return field\n\n const tagged: Record<string, unknown> = { ...f, source }\n if (kind === 'live' || f.readonlyField === true) {\n tagged.readonlyField = true\n } else {\n tagged.writerCapName = capName\n tagged.writerAddonId = addonId\n }\n\n // Recurse into composite layouts so nested leaf fields carry the\n // writer routing too. Without this, fields buried inside `'group'`\n // or `'sub-tabs'` containers are surfaced to the UI without a\n // writerCapName/writerAddonId — `findWriter` then can't route the\n // patch back to the cap that produced the field. Records are\n // typed `Record<string, unknown>`, so each step needs an explicit\n // `unknown[]` narrow before `.map` to keep the no-`any` rule happy.\n if (f.type === 'group') {\n const children: readonly unknown[] = Array.isArray(f.fields) ? f.fields : []\n if (children.length > 0) {\n tagged.fields = children.map((child) => tagField(child, capName, addonId, source, kind))\n }\n } else if (f.type === 'sub-tabs') {\n const rawTabs: readonly unknown[] = Array.isArray(f.tabs) ? f.tabs : []\n if (rawTabs.length > 0) {\n tagged.tabs = rawTabs.map((tab) => {\n if (!isFieldRecord(tab)) return tab\n const tabChildren: readonly unknown[] = Array.isArray(tab.fields) ? tab.fields : []\n return {\n ...tab,\n fields: tabChildren.map((child) => tagField(child, capName, addonId, source, kind)),\n }\n })\n }\n }\n return tagged\n}\n\nfunction mergeAggregates(parts: readonly ContributionShape[]): ContributionShape {\n const tabDecls = new Map<string, AggregateTabDecl>()\n const sections: AggregateSection[] = []\n\n for (const part of parts) {\n if (part.tabs) {\n for (const t of part.tabs) {\n if (!tabDecls.has(t.id)) tabDecls.set(t.id, t)\n }\n }\n for (const s of part.sections) {\n sections.push(s)\n }\n }\n\n // Auto-derive tab declarations from section references when contributors\n // don't emit one explicitly. Every tab id referenced in a section's `tab`\n // field gets a declaration — if the id matches a well-known tab\n // (general/detection/streaming/recording/…) the canonical label+icon+order\n // is used; otherwise we fall back to the raw id as label with a generic\n // icon. Ensures the UI has everything it needs to render the tab bar\n // from a single payload — no extra lookup, no duplicate source of truth.\n for (const s of sections) {\n const tabId = s.tab ?? 'general'\n if (tabDecls.has(tabId)) continue\n const known = WELL_KNOWN_TAB_MAP[tabId as keyof typeof WELL_KNOWN_TAB_MAP]\n if (known) {\n tabDecls.set(tabId, { id: known.id, label: known.label, icon: known.icon, order: known.order })\n } else {\n tabDecls.set(tabId, { id: tabId, label: tabId, icon: 'wrench', order: 100 })\n }\n }\n\n sections.sort((a, b) => {\n const tabA = a.tab ?? 'general'\n const tabB = b.tab ?? 'general'\n if (tabA !== tabB) {\n const orderA = tabDecls.get(tabA)?.order ?? 100\n const orderB = tabDecls.get(tabB)?.order ?? 100\n if (orderA !== orderB) return orderA - orderB\n return tabA.localeCompare(tabB)\n }\n return (a.order ?? 0) - (b.order ?? 0)\n })\n\n const sortedTabs = [...tabDecls.values()].sort((a, b) => (a.order ?? 100) - (b.order ?? 100))\n const out: ContributionShape = { sections }\n if (sortedTabs.length > 0) out.tabs = sortedTabs\n return out\n}\n\nexport class DeviceManagerAddon extends BaseAddon {\n constructor() { super({}) }\n\n /** Shorthand for the kernel-injected capability registry. */\n private get capabilityRegistry(): ICapabilityRegistry | undefined {\n return this.ctx.kernel.capabilityRegistry\n }\n\n /**\n * Parent-chain event propagator. Started in `onInitialize` once the\n * hub's `deviceRegistry` is available; listens to every device-sourced\n * event and re-emits a copy on each ancestor scope with `via[]`\n * populated. Stopped in `onShutdown`.\n */\n private propagator: DeviceEventPropagator | null = null\n /**\n * Hub-side mirror of every device's cap-keyed runtime state.\n * Populated whenever any caller writes via `deviceState.setCapSlice`\n * (the canonical cross-layer write entrypoint) and on first load\n * via `loadRuntimeState`. Cross-process consumers reach the mirror\n * through the `deviceState` cap router; per-cap event subscribers\n * (e.g. `battery.onStatusChanged`) get the same data via\n * cap-specific events still emitted by the owning device.\n *\n * Key: deviceId. Value: per-cap slice map. Empty by default —\n * slices show up as `setCapSlice` calls trickle in.\n */\n private readonly stateMirror = new Map<number, Map<string, Record<string, unknown>>>()\n\n /**\n * Per-device disk-write debouncer for runtime-state. `setCapSlice`\n * updates the in-memory mirror synchronously and emits the change\n * event immediately, but the disk write is coalesced — frequent\n * back-to-back writes (motion phase transitions, battery pushes,\n * etc.) collapse to one `writeDeviceRuntimeState` per\n * `RUNTIME_STATE_DEBOUNCE_MS` window. `flushRuntimeStateWrites`\n * awaits any in-flight write + scheduled flush so shutdown is\n * lossless.\n */\n private readonly runtimeStateDebounce = new Map<number, {\n timer: ReturnType<typeof setTimeout> | null\n inFlight: Promise<void> | null\n }>()\n private static readonly RUNTIME_STATE_DEBOUNCE_MS = 1000\n\n /**\n * Cross-process native-provider cache: deviceId (numeric) → capName → { addonId, nodeId }.\n * Kept in sync with `device.bindings-changed` events emitted by forked\n * workers. Union'd into `getBindings` so hub-side consumers see every\n * native cap regardless of which process owns the IDevice. No persistence\n * — entries re-register when the worker restarts. Purged on\n * `$node.disconnected` to avoid stale routing after a worker crash.\n */\n private remoteNativeCaps: Map<number, Map<string, { addonId: string; nodeId: string }>> = new Map()\n\n /** Wait for a device-provider by addonId, returning null on timeout. */\n private async waitDeviceProvider(addonId: string, timeoutMs = 5_000): Promise<IDeviceProviderCap | null> {\n const provider = await this.capabilityRegistry?.waitForProvider('device-provider', addonId, timeoutMs)\n return provider ? (provider as IDeviceProviderCap) : null\n }\n\n /** Require a device-provider by addonId — throws if not found. */\n private async requireDeviceProvider(addonId: string): Promise<IDeviceProviderCap> {\n const dp = await this.waitDeviceProvider(addonId)\n if (!dp) {\n throw new Error(`Device provider \"${addonId}\" not found or not registered`)\n }\n return dp\n }\n\n // ── Binding store (persisted wrapper activation) ───────────────────────────\n //\n // These methods are public so the device-manager capability router can\n // expose them as cap methods. They read/write through\n // ctx.settings.readAddonStore/writeAddonStore — the same persistence channel\n // the rest of the addon uses.\n\n private async readBindingsStore(): Promise<DeviceBindingsStore> {\n const raw = (await this.ctx.settings!.readAddonStore()) as Partial<DeviceBindingsStore>\n return { deviceBindings: raw.deviceBindings ?? {} }\n }\n\n private async writeBindingsStore(next: DeviceBindingsStore): Promise<void> {\n await this.ctx.settings!.writeAddonStore({ deviceBindings: next.deviceBindings })\n }\n\n private resolveWrapperNodeId(_wrapperAddonId: string): string {\n // TODO(phase-7): read from cluster view so cluster-deployed wrappers\n // report their actual node. For now assume hub-co-located.\n return 'hub'\n }\n\n /**\n * Active discovery of native caps registered on a worker node.\n * Called from the `$node.connected` handler to recover from lost\n * `DeviceBindingsChanged` broadcasts after worker restart.\n *\n * Iterates the broker's service registry, picks\n * `<addonId>.native-provider.<capName>` services owned by the\n * connected node, calls each service's `$listDeviceIds` action to\n * fetch the deviceIds the worker has registered that cap on, then\n * writes entries into `remoteNativeCaps`.\n *\n * Best-effort: per-service failures are logged and swallowed so a\n * single bad service doesn't abort the whole rebuild.\n */\n private async discoverWorkerNativeCaps(connectedNodeId: string, _connectedAddonId: string): Promise<void> {\n const cluster = this.ctx.kernel.cluster\n if (!cluster) return\n const broker = cluster.broker as unknown as {\n registry?: {\n getServiceList?: (opts: Record<string, boolean>) => readonly { name: string; nodeID: string; metadata?: Record<string, unknown> }[]\n }\n call?: (action: string, params: unknown, opts?: { nodeID?: string }) => Promise<unknown>\n }\n const services = broker.registry?.getServiceList?.({ onlyAvailable: true, withActions: false }) ?? []\n const NATIVE_INFIX = '.native-provider.'\n // Filter on nodeID + the `.native-provider.` infix only. The\n // service-name addonId prefix may differ from the addonId we'd\n // derive from the nodeId (groupId suffixes like `-isolated`), so\n // we extract addonId + capName straight from the service name.\n const matched = services.filter((s) =>\n s.nodeID === connectedNodeId && s.name.includes(NATIVE_INFIX),\n )\n if (matched.length === 0) return\n for (const svc of matched) {\n const idx = svc.name.indexOf(NATIVE_INFIX)\n if (idx <= 0) continue\n const addonId = svc.name.slice(0, idx)\n const capName = svc.name.slice(idx + NATIVE_INFIX.length)\n if (!addonId || !capName) continue\n try {\n const action = `${svc.name}.$listDeviceIds`\n const deviceIds = await broker.call?.(action, {}, { nodeID: connectedNodeId }) as readonly number[] | undefined\n if (!deviceIds || deviceIds.length === 0) continue\n for (const deviceId of deviceIds) {\n if (this.capabilityRegistry?.getNativeAddonId(capName, deviceId)) continue\n let perDevice = this.remoteNativeCaps.get(deviceId)\n if (!perDevice) {\n perDevice = new Map()\n this.remoteNativeCaps.set(deviceId, perDevice)\n }\n perDevice.set(capName, { addonId, nodeId: connectedNodeId })\n }\n this.ctx.logger.debug('worker native-cap discovered', {\n meta: { nodeId: connectedNodeId, addonId, capName, deviceIds },\n })\n } catch (err) {\n this.ctx.logger.debug('worker native-cap $listDeviceIds failed', {\n meta: { service: svc.name, nodeId: connectedNodeId, error: errMsg(err) },\n })\n }\n }\n this.ctx.logger.info('worker native-cap discovery completed', {\n meta: { nodeId: connectedNodeId, services: matched.length },\n })\n }\n\n async getBindings(input: { deviceId: number }): Promise<{ deviceId: number; entries: DeviceBindingEntry[] }> {\n // Every map (bindings store, native-cap registry, remoteNativeCaps) is\n // keyed by numeric deviceId now that Phase 2 finished the migration.\n const storeKey = String(input.deviceId)\n const store = await this.readBindingsStore()\n const perDevice = store.deviceBindings[storeKey] ?? {}\n\n const entries: DeviceBindingEntry[] = []\n const seenCaps = new Set<string>()\n\n // 1. Entries from persisted wrapper activations\n for (const [capName, { wrapperAddonId }] of Object.entries(perDevice)) {\n const hubLocalNative = this.capabilityRegistry?.getNativeAddonId(capName, input.deviceId) ?? null\n const remoteNative = this.remoteNativeCaps.get(input.deviceId)?.get(capName) ?? null\n const nativeAddonId = hubLocalNative ?? remoteNative?.addonId ?? ''\n const nativeNodeId = hubLocalNative\n ? (this.ctx.kernel.localNodeId ?? 'hub')\n : (remoteNative?.nodeId ?? (this.ctx.kernel.localNodeId ?? 'hub'))\n // Operator explicitly disabled the wrapper AND no native is available\n // → cap is genuinely off for this device. Mark it seen so step 2's\n // defaultActive auto-bind doesn't silently re-bind the wrapper.\n if (wrapperAddonId === null && !nativeAddonId) {\n seenCaps.add(capName)\n continue\n }\n entries.push({\n capName,\n kind: wrapperAddonId ? 'wrapped' : 'native',\n providerAddonId: wrapperAddonId ?? nativeAddonId,\n providerNodeId: wrapperAddonId ? this.resolveWrapperNodeId(wrapperAddonId) : nativeNodeId,\n nativeAddonId,\n })\n seenCaps.add(capName)\n }\n\n const remote = this.remoteNativeCaps.get(input.deviceId)\n\n // 2. Auto-activated wrappers — any cap a wrapper addon declared with\n // `defaultActive: true` claims the binding HERE, ahead of native\n // discovery. The wrapper is the active provider; it delegates to\n // the native via `ctx.getNativeProvider`, so \"wrapper decorates\n // native\" is the intended runtime shape and the cap router resolves\n // locally on the wrapper's node instead of trying to forward to the\n // native's worker (cap routers like `snapshot` are mounted without\n // a `createRemoteProxy` because the wrapper handles cross-process\n // delegation internally).\n //\n // Step 1 (persisted activations) still wins: an operator-toggled\n // deactivation marks the cap seen with no entry, blocking this\n // branch from re-binding the wrapper.\n //\n // Pure-wrapper caps (motion-detection, audio-analysis,\n // detection-pipeline) have NO native — the wrapper is the only\n // implementation. They still bind here with an empty `nativeAddonId`\n // so consumers (UI bindings table, pipeline-orchestrator's\n // `isCapActiveForDevice` gate) see the wrapper as active by default.\n // Mirrors the fallback semantics of step 1 (`?? ''`).\n if (this.capabilityRegistry) {\n for (const capName of this.capabilityRegistry.getCapsWithDefaultWrapper()) {\n if (seenCaps.has(capName)) continue\n const defaultWrapperAddonId = this.capabilityRegistry.getDefaultWrapperForCap(capName)\n if (!defaultWrapperAddonId) continue\n const hubLocalNative = this.capabilityRegistry.getNativeAddonId(capName, input.deviceId) ?? null\n const remoteNative = remote?.get(capName) ?? null\n const nativeAddonId = hubLocalNative ?? remoteNative?.addonId ?? ''\n entries.push({\n capName,\n kind: 'wrapped',\n providerAddonId: defaultWrapperAddonId,\n providerNodeId: this.resolveWrapperNodeId(defaultWrapperAddonId),\n nativeAddonId,\n })\n seenCaps.add(capName)\n }\n }\n\n // 3. Entries from hub-local registered natives (no wrapper configured)\n if (this.capabilityRegistry) {\n for (const capName of this.capabilityRegistry.getNativeCapsForDevice(input.deviceId)) {\n if (seenCaps.has(capName)) continue\n const nativeAddonId = this.capabilityRegistry.getNativeAddonId(capName, input.deviceId) ?? ''\n entries.push({\n capName,\n kind: 'native',\n providerAddonId: nativeAddonId,\n providerNodeId: this.ctx.kernel.localNodeId ?? 'hub',\n nativeAddonId,\n })\n seenCaps.add(capName)\n }\n }\n\n // 4. Entries from remote (forked-worker) natives learned via\n // `device.bindings-changed` broadcasts. Union'd here so consumers see\n // every cap for the device regardless of owning process.\n if (remote) {\n for (const [capName, info] of remote) {\n if (seenCaps.has(capName)) continue\n entries.push({\n capName,\n kind: 'native',\n providerAddonId: info.addonId,\n providerNodeId: info.nodeId,\n nativeAddonId: info.addonId,\n })\n seenCaps.add(capName)\n }\n }\n\n return { deviceId: input.deviceId, entries }\n }\n\n /**\n * Whole-fleet binding dump. Iterates every device known to the\n * deviceRegistry and reuses the per-device `getBindings` resolver\n * for each — same routing rules, single round-trip. Used by\n * `SystemManager.init()` for warm-boot.\n *\n * Bindings change rarely (wrapper toggle, device add/remove) so\n * clients invalidate via the existing\n * `capability.binding-changed` event rather than re-fetching this\n * payload periodically.\n */\n async getAllBindings(): Promise<Array<{ deviceId: number; entries: DeviceBindingEntry[] }>> {\n const hubRegistry = this.ctx.kernel?.deviceRegistry\n if (!hubRegistry) return []\n const out: Array<{ deviceId: number; entries: DeviceBindingEntry[] }> = []\n for (const device of hubRegistry.getAll()) {\n out.push(await this.getBindings({ deviceId: device.id }))\n }\n return out\n }\n\n /**\n * Resolve a numeric deviceId to a stableId via persisted meta.\n * Used only by the device-identity section of the device-details\n * aggregator (see `buildBaseDeviceSection`) to surface the stableId as\n * a readonly display field. All runtime/registry lookups are keyed by\n * numeric deviceId; this helper is display-only.\n */\n private async lookupPersistedStableId(deviceId: number): Promise<string | undefined> {\n const store = (await this.ctx.settings!.readAddonStore()) as AddonStore\n const meta = store.deviceMeta ?? {}\n for (const [key, m] of Object.entries(meta)) {\n if (m.id === deviceId) {\n const sep = key.indexOf(':')\n if (sep < 0) continue\n return key.slice(sep + 1)\n }\n }\n return undefined\n }\n\n\n // ── Device-details aggregator ──────────────────────────────────────────────\n //\n // Walks the bindings for `deviceId` (native + wrapped), picks every\n // provider whose cap declares `exposesDeviceSettings: true`, and asks\n // each for its per-device contribution. Contributions are concatenated\n // into a single `ConfigUISchemaWithValues`; editable fields are tagged\n // with `writerCapName` + `writerAddonId` so `updateDeviceField` can\n // route the mutation back to the exact provider that produced them.\n //\n // `kind` selects settings vs live-info. The two aggregators share the\n // enumeration + tagging pipeline; only the method invoked on each\n // contributing provider differs.\n async getDeviceAggregate(\n deviceId: number,\n kind: 'settings' | 'live',\n ): Promise<ContributionShape | null> {\n const registry = this.capabilityRegistry\n if (!registry) {\n this.ctx.logger.debug('capability registry unavailable — aggregate empty', { meta: { kind } })\n return null\n }\n\n const method = kind === 'settings' ? 'getDeviceSettingsContribution' : 'getDeviceLiveContribution'\n\n // Enumerate EVERY capability with `exposesDeviceSettings: true`, not\n // just the caps for which this device has a per-device binding. The\n // system-wide singletons that hold per-device state (pipeline-\n // orchestrator assignments, motion-detection tuning, stream-broker\n // RTSP restream toggles, audio-analyzer VAD thresholds, …) are\n // registered once per system — they don't map to `(deviceId → cap)`\n // bindings. Walking bindings alone left their sections off the\n // aggregate, producing the \"5 empty fields\" device-details page.\n //\n // Each provider decides whether `deviceId` is relevant and returns\n // either a contribution or `null`. The aggregator flattens results\n // and tags each section with `(capName, addonId)` so the write path\n // can route a patch back to the provider that produced the field.\n const contributors: Array<{ capName: string; addonId: string }> = []\n for (const info of registry.listCapabilities()) {\n const def = registry.getDefinition(info.name)\n if (!def?.exposesDeviceSettings) continue\n // Deduplicate by base addon id — remote agents register with\n // \"addonId@nodeId\" keys but device settings are hub-centric:\n // only one contribution per logical addon, preferring the local\n // instance (shortest key = no \"@\" suffix).\n //\n // Skip synthetic addonIds (`<addonId>::native-<capName>`) created\n // for native-cap proxy services in `mountNativeCapService`. Those\n // services exist only to expose the cap's actual methods over\n // Moleculer; they don't implement contribution methods, so calling\n // `getDeviceSettingsContribution` on them throws and floods the\n // log. The owning addon (without the suffix) is the legitimate\n // contributor — it's listed separately and handled normally.\n const seen = new Set<string>()\n const sorted = [...info.providers].sort((a, b) => a.length - b.length)\n for (const addonId of sorted) {\n if (addonId.includes('::native-')) continue\n const baseId = addonId.includes('@') ? addonId.slice(0, addonId.indexOf('@')) : addonId\n if (seen.has(baseId)) continue\n seen.add(baseId)\n contributors.push({ capName: info.name, addonId })\n }\n }\n\n const results = await Promise.all(contributors.map(async ({ capName, addonId }) => {\n const provider = registry.getProviderByAddon<DeviceSettingsContribution>(capName, addonId)\n if (!provider) {\n // `listCapabilities()` returned this pair — it must resolve. A\n // null here means the registry's internal state diverged from\n // its public listing, which is always a bug (not a silent skip).\n throw new Error(\n `[device-manager] capability \"${capName}\" lists provider \"${addonId}\" but getProviderByAddon returned null — registry inconsistency`,\n )\n }\n // No typeof-function gate: `registerProvider` enforces that every\n // provider of an `exposesDeviceSettings` cap implements the three\n // contribution methods. Missing-method failures happen at register\n // time, not here.\n try {\n const contribution = await provider[method]({ deviceId })\n if (!contribution) return null\n return {\n capName,\n addonId,\n contribution: tagContribution(toWireShape(contribution), capName, addonId, kind),\n }\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err)\n this.ctx.logger.warn('contribution method failed', { tags: { deviceId, addonId }, meta: { capName, method, error: msg } })\n return null\n }\n }))\n\n // Prepend the device-manager's own base section (only for settings —\n // live contribution from device-manager is currently empty). The base\n // section holds the device's identity + driver-specific config, tagged\n // with writer = 'device-manager' so updateDeviceField can route its\n // mutations back to `device.config.setAll`.\n const base = kind === 'settings' ? await this.buildBaseDeviceSection(deviceId) : null\n const parts: ContributionShape[] = [\n ...(base ? [tagContribution(base, 'device-manager', 'device-manager', kind)] : []),\n ...results.filter((r): r is { capName: string; addonId: string; contribution: ContributionShape } => r !== null).map(r => r.contribution),\n ]\n if (parts.length === 0) return null\n return mergeAggregates(parts)\n }\n\n /**\n * Build the device-manager's own contribution to the aggregator — the\n * device identity (id, stableId, addonId, type, online) + the\n * driver-specific config exposed by the device class via\n * `zodEntriesToConfigUI`.\n *\n * Two paths, deliberately symmetric with `getSettingsSchema`:\n *\n * - Hub-local: device's IDevice instance lives in this process'\n * DeviceRegistry, we read config + schema directly by reference.\n * - Cross-process: device lives in a forked worker (RtspCamera on\n * provider-rtsp, ONVIF on provider-onvif, …). We ask the worker's\n * `device-ops.getSettingsSchema` native provider for a wire-\n * serializable ConfigUISchema and merge it in under the same\n * \"Driver Config\" section, so the UI sees the same shape regardless\n * of where the IDevice physically runs.\n *\n * Returns `null` only when the device genuinely doesn't exist anywhere\n * (no hub-local, no persisted ownership, no device-ops native). The\n * aggregator falls back to contributor sections only in that case.\n */\n private async buildBaseDeviceSection(deviceId: number): Promise<ContributionShape | null> {\n const hubRegistry = this.ctx.kernel?.deviceRegistry\n const hubLocal = hubRegistry ? resolveDeviceById(hubRegistry, deviceId) : null\n const stableId = hubLocal?.device.stableId ?? await this.lookupPersistedStableId(deviceId)\n\n // Resolve identity fields regardless of where the device lives. The\n // capability-registry's native fallback populates remoteNativeCaps\n // from DeviceBindingsChanged events (so every worker-owned device\n // that registered device-ops shows up here with its addonId/nodeId).\n const nativeOwner = this.resolveNativeDeviceOwner(deviceId)\n const addonId = hubLocal?.addonId ?? nativeOwner?.addonId ?? null\n if (!hubLocal && !nativeOwner) return null\n\n const identityFields: unknown[] = [\n {\n type: 'text',\n key: '_deviceId',\n label: 'Device ID',\n readonlyField: true,\n value: String(deviceId),\n },\n {\n type: 'text',\n key: '_stableId',\n label: 'Stable ID',\n readonlyField: true,\n value: stableId ?? '',\n },\n {\n type: 'text',\n key: '_addonId',\n label: 'Driver',\n readonlyField: true,\n value: addonId ?? 'unknown',\n },\n ...(hubLocal\n ? [\n {\n type: 'text',\n key: '_type',\n label: 'Type',\n readonlyField: true,\n value: hubLocal.device.type,\n },\n {\n type: 'text',\n key: '_online',\n label: 'Online',\n readonlyField: true,\n value: hubLocal.device.online ? 'yes' : 'no',\n },\n ]\n : []),\n ]\n\n const sections: ContributionShape['sections'] = [\n {\n id: 'device-identity',\n title: 'Identity',\n tab: 'general',\n order: 0,\n fields: identityFields,\n },\n ]\n // Hardware-info metadata is exposed read-only via `getDevice` and\n // rendered by a dedicated UI tab — it's facts, not preferences,\n // so it doesn't belong in the editable settings aggregate.\n\n // Driver config — either built in-process from the live IDevice's Zod\n // schema (hub-local path) or obtained as a pre-built ConfigUISchema\n // from the worker that owns the device (cross-process path).\n const driverSchema = await this.resolveDriverConfigSchema(deviceId, hubLocal)\n if (driverSchema) {\n for (const section of driverSchema.sections) {\n sections.push({\n id: section.id,\n title: section.title,\n tab: section.tab ?? 'general',\n order: section.order ?? 1,\n fields: [...section.fields],\n ...(section.description !== undefined ? { description: section.description } : {}),\n ...(section.columns !== undefined ? { columns: section.columns } : {}),\n })\n }\n }\n\n // Propagate driver-declared tab metadata (label + icon + order).\n // Without this the merge step in `mergeAggregates` falls back to\n // auto-derived tabs (raw id as label, generic icon) — UI then shows\n // lowercase `sessions` / `streams` instead of the driver's\n // `Sessions` / `Streams`. First-wins inside mergeAggregates so the\n // driver's declarations beat any later contributor.\n return {\n sections,\n ...(driverSchema?.tabs ? { tabs: [...driverSchema.tabs] } : {}),\n }\n }\n\n /**\n * Lookup the native owner for `device-ops` on `deviceId` — the native-cap\n * registry (hub-local and remote) is keyed by numeric id.\n */\n private resolveNativeDeviceOwner(deviceId: number): { addonId: string; nodeId: string } | null {\n const local = this.capabilityRegistry?.getNativeAddonId('device-ops', deviceId) ?? null\n if (local) return { addonId: local, nodeId: this.ctx.kernel.localNodeId ?? 'hub' }\n const remote = this.remoteNativeCaps.get(deviceId)?.get('device-ops') ?? null\n return remote ? { addonId: remote.addonId, nodeId: remote.nodeId } : null\n }\n\n /**\n * Aggregate `status` across every registered cap for a device.\n *\n * Walks the supplied cap list (or `CAP_NAMES_WITH_STATUS` when\n * omitted), looks up a native provider per cap via the capability\n * registry, calls `provider.getStatus({ deviceId })`, and validates\n * the return against the cap's own `status.schema`. Validation\n * failures log a warning and yield `null` for that cap so the\n * overall aggregate stays usable — a single misbehaving provider\n * must not blank out a device's entire status view.\n *\n * Returned shape is `Record<capName, unknown | null>`; the client-\n * side hook tightens this to `CapStatusTypeMap` via the generated\n * `cap-status-types.ts`.\n */\n private async getDeviceStatusAggregate(input: {\n readonly deviceId: number\n readonly caps?: readonly string[]\n }): Promise<Record<string, unknown | null>> {\n const capNames: readonly string[] = input.caps ?? CAP_NAMES_WITH_STATUS\n const registry = this.capabilityRegistry\n const out: Record<string, unknown | null> = {}\n if (!registry) {\n for (const name of capNames) out[name] = null\n return out\n }\n\n await Promise.all(capNames.map(async (capName) => {\n try {\n const def = registry.getDefinition(capName)\n if (!def?.status) { out[capName] = null; return }\n\n const provider = registry.getNativeProvider<{\n getStatus?: (input: { deviceId: number }) => Promise<unknown>\n }>(capName, input.deviceId)\n if (!provider || typeof provider.getStatus !== 'function') {\n out[capName] = null\n return\n }\n\n const raw = await provider.getStatus({ deviceId: input.deviceId })\n if (raw == null) { out[capName] = null; return }\n\n // Validate against the cap's own schema — single misbehaving\n // provider must not poison the rest of the aggregate.\n const parsed = def.status.schema.safeParse(raw)\n if (!parsed.success) {\n this.ctx.logger.warn('getDeviceStatusAggregate: provider returned invalid status, dropping', {\n tags: { deviceId: input.deviceId },\n meta: { capName, issues: parsed.error.issues.slice(0, 3) },\n })\n out[capName] = null\n return\n }\n out[capName] = parsed.data\n } catch (err) {\n this.ctx.logger.warn('getDeviceStatusAggregate: provider threw, dropping', {\n tags: { deviceId: input.deviceId },\n meta: { capName, error: errMsg(err) },\n })\n out[capName] = null\n }\n }))\n\n return out\n }\n\n /**\n * Return the driver-specific device-settings contribution. Hub-local\n * devices call `getSettingsUISchema()` directly; forked-worker devices\n * go through the `device-ops.getSettingsSchema` cap method on the\n * numeric-id-keyed native registry.\n */\n private async resolveDriverConfigSchema(\n deviceId: number,\n hubLocal: { addonId: string; device: IDevice } | null,\n ): Promise<ContributionShape | null> {\n if (hubLocal) {\n const schema = hubLocal.device.getSettingsUISchema()\n return schema.sections.length === 0 ? null : toWireShape(schema)\n }\n const ops = this.capabilityRegistry?.getNativeProvider<IDeviceOpsProvider>('device-ops', deviceId)\n if (!ops) return null\n try {\n const schema = await ops.getSettingsSchema({ deviceId })\n if (!schema) return null\n const wire = schema as ConfigUISchemaWithValues\n return wire.sections.length === 0 ? null : toWireShape(wire)\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err)\n this.ctx.logger.warn('cross-process getSettingsSchema failed', { tags: { deviceId }, meta: { error: msg } })\n return null\n }\n }\n\n async updateDeviceField(input: {\n deviceId: number\n writerCapName: string\n writerAddonId: string\n key: string\n value: unknown\n }): Promise<{ success: true }> {\n // Special-case: the device-manager's own base section tags fields with\n // writer='device-manager'. Route those to `device.config.setAll` via the\n // live registry — the device-manager cap itself does not participate in\n // the binding-enumerated aggregator (it's a hub singleton), so it would\n // otherwise fail the capability lookup below.\n if (input.writerCapName === 'device-manager') {\n // Hub-local fast path — the device instance is in this process.\n const hubRegistry = this.ctx.kernel?.deviceRegistry\n const found = hubRegistry ? resolveDeviceById(hubRegistry, input.deviceId) : null\n if (found) {\n // Always go through `applySettingsPatch` — drivers whose UI shape\n // differs from storage (RtspCamera's flat mainStreamUrl projecting\n // onto a `streams: [{label,url}]` array) reshape here. `BaseDevice`\n // defaults the method to `config.setAll` so drivers that don't\n // reshape keep the old behaviour for free.\n await found.device.applySettingsPatch({ [input.key]: input.value })\n return { success: true as const }\n }\n // Cross-process fallback — device lives in a forked worker. Native\n // registry is numeric-keyed; dispatch through device-ops directly.\n const ops = this.capabilityRegistry?.getNativeProvider<IDeviceOpsProvider>('device-ops', input.deviceId)\n if (!ops) {\n throw new Error(`[device-manager] device \"${input.deviceId}\" not found (no hub-local entry, no device-ops native provider)`)\n }\n await ops.setConfig({ deviceId: input.deviceId, values: { [input.key]: input.value } })\n return { success: true as const }\n }\n\n const registry = this.capabilityRegistry\n if (!registry) {\n throw new Error('[device-manager] updateDeviceField requires capability registry — unavailable on this node')\n }\n\n const def = registry.getDefinition(input.writerCapName)\n if (!def?.exposesDeviceSettings) {\n throw new Error(`[device-manager] cap \"${input.writerCapName}\" does not expose device settings`)\n }\n\n const provider = registry.getProviderByAddon<DeviceSettingsContribution>(input.writerCapName, input.writerAddonId)\n if (!provider) {\n throw new Error(`[device-manager] provider \"${input.writerAddonId}\" not registered for cap \"${input.writerCapName}\"`)\n }\n\n await provider.applyDeviceSettingsPatch({\n deviceId: input.deviceId,\n patch: { [input.key]: input.value },\n })\n return { success: true as const }\n }\n\n /**\n * Batched counterpart of `updateDeviceField`. Groups changes by\n * `(writerCapName, writerAddonId)` so each contributor receives a\n * single `applyDeviceSettingsPatch` with all of its updates merged —\n * avoids N round-trips for simultaneous edits in the same save.\n *\n * Per-provider failures are captured in the `failures[]` output so the\n * admin UI can highlight which sections didn't persist; a failure on\n * one provider does NOT abort the others.\n */\n async updateDeviceFieldsBatch(input: {\n deviceId: number\n changes: ReadonlyArray<{\n writerCapName: string\n writerAddonId: string\n key: string\n value: unknown\n }>\n }): Promise<{ success: true; failures: { writerCapName: string; writerAddonId: string; error: string }[] }> {\n // Group by `(writerCapName, writerAddonId)` so we fire at most one\n // applyDeviceSettingsPatch per contributing provider.\n const groups = new Map<string, { writerCapName: string; writerAddonId: string; patch: Record<string, unknown> }>()\n for (const change of input.changes) {\n const key = `${change.writerCapName}::${change.writerAddonId}`\n const existing = groups.get(key)\n if (existing) {\n existing.patch[change.key] = change.value\n } else {\n groups.set(key, {\n writerCapName: change.writerCapName,\n writerAddonId: change.writerAddonId,\n patch: { [change.key]: change.value },\n })\n }\n }\n\n const failures: { writerCapName: string; writerAddonId: string; error: string }[] = []\n for (const group of groups.values()) {\n try {\n await this.applyGroupPatch(input.deviceId, group)\n } catch (err: unknown) {\n failures.push({\n writerCapName: group.writerCapName,\n writerAddonId: group.writerAddonId,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n return { success: true as const, failures }\n }\n\n /** Apply a single grouped patch to the appropriate provider. Mirrors\n * `updateDeviceField` routing (special-case device-manager, else\n * registry lookup). Used by `updateDeviceFieldsBatch`. */\n private async applyGroupPatch(\n deviceId: number,\n group: { writerCapName: string; writerAddonId: string; patch: Record<string, unknown> },\n ): Promise<void> {\n if (group.writerCapName === 'device-manager') {\n // Hub-local fast path (same reshape-aware path used by `updateDeviceField`).\n const hubRegistry = this.ctx.kernel?.deviceRegistry\n const found = hubRegistry ? resolveDeviceById(hubRegistry, deviceId) : null\n if (found) {\n await found.device.applySettingsPatch(group.patch)\n return\n }\n // Cross-process fallback via `device-ops.setConfig` — native registry\n // is numeric-keyed.\n const ops = this.capabilityRegistry?.getNativeProvider<IDeviceOpsProvider>('device-ops', deviceId)\n if (!ops) {\n throw new Error(`[device-manager] device \"${deviceId}\" not found (no hub-local entry, no device-ops native provider)`)\n }\n await ops.setConfig({ deviceId, values: group.patch })\n return\n }\n\n const registry = this.capabilityRegistry\n if (!registry) throw new Error('[device-manager] capability registry unavailable')\n const def = registry.getDefinition(group.writerCapName)\n if (!def?.exposesDeviceSettings) {\n throw new Error(`[device-manager] cap \"${group.writerCapName}\" does not expose device settings`)\n }\n const provider = registry.getProviderByAddon<DeviceSettingsContribution>(group.writerCapName, group.writerAddonId)\n if (!provider) {\n throw new Error(`[device-manager] provider \"${group.writerAddonId}\" not registered for cap \"${group.writerCapName}\"`)\n }\n await provider.applyDeviceSettingsPatch({ deviceId, patch: group.patch })\n }\n\n async listWrappersForCap(input: { capName: string }): Promise<string[]> {\n return [...(this.capabilityRegistry?.getWrappersForCap(input.capName) ?? [])]\n }\n\n async listBindableCapsForDeviceType(input: { deviceType: string }): Promise<Array<{ capName: string; wrappers: string[] }>> {\n const registry = this.capabilityRegistry\n if (!registry) return []\n const capNames = registry.listDeviceScopedCapsForType(input.deviceType)\n return capNames.map(capName => ({\n capName,\n wrappers: [...registry.getWrappersForCap(capName)],\n }))\n }\n\n async setWrapperActive(input: {\n deviceId: number\n capName: string\n wrapperAddonId: string\n active: boolean\n }): Promise<void> {\n const storeKey = String(input.deviceId)\n const store = await this.readBindingsStore()\n const perDevice = { ...(store.deviceBindings[storeKey] ?? {}) }\n if (input.active) {\n perDevice[input.capName] = { wrapperAddonId: input.wrapperAddonId }\n } else {\n // Explicit \"operator disabled\" marker. Persisting {wrapperAddonId:null}\n // (instead of deleting) prevents getBindings step 4 from re-binding\n // the defaultActive wrapper after a toggle-off. When a native provider\n // exists, the null marker still surfaces as `kind:'native'` (the revert\n // path the old delete branch was optimising for); when no native is\n // registered, the cap stays truly unbound for this device.\n perDevice[input.capName] = { wrapperAddonId: null }\n }\n const nextDeviceBindings = Object.keys(perDevice).length > 0\n ? { ...store.deviceBindings, [storeKey]: perDevice }\n : (() => { const { [storeKey]: _drop, ...rest } = store.deviceBindings; return rest })()\n await this.writeBindingsStore({ deviceBindings: nextDeviceBindings })\n this.ctx.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: this.ctx.id },\n category: EventCategory.DeviceBindingsChanged,\n data: {\n deviceId: input.deviceId,\n capName: input.capName,\n reason: input.active ? 'wrapper-activated' : 'wrapper-deactivated',\n addonId: input.wrapperAddonId,\n nodeId: this.resolveWrapperNodeId(input.wrapperAddonId),\n },\n })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[] | void> {\n const settings = this.ctx.settings\n if (!settings) {\n this.ctx.logger.warn('ctx.settings not available — device persistence unavailable')\n return\n }\n\n const registry = this.ctx.kernel.deviceRegistry ?? null\n\n if (!registry) {\n this.ctx.logger.warn('device-registry not available — live operations will use persisted data only')\n }\n\n // Cross-process device-ops dispatch. Forked-worker addons (e.g.\n // provider-rtsp) register devices whose live IDevice instance lives in\n // the worker's own DeviceRegistry — invisible to this hub-side\n // `registry`. Instead of a bespoke Moleculer bridge, every worker\n // auto-registers a `device-ops` NATIVE capability provider per device\n // (see createBrokerDeviceManagerApi.register). Hub consumers reach it\n // via `capabilityRegistry.getNativeProvider('device-ops', deviceId)`:\n // the CapabilityRegistry's native-fallback builds a typed proxy that\n // routes the call to the owning worker through the standard native-cap\n // bridge — same plumbing every other per-device cap (snapshot, events,\n // ptz, …) already uses.\n\n // Cross-process native-cap discovery. Workers emit `device.bindings-changed`\n // on `registerNativeCap` / device removal; we mirror those into\n // `remoteNativeCaps` so `getBindings` returns the full cluster view.\n // Events from the local node are ignored: hub-local natives live in\n // `capabilityRegistry` and are folded in directly by getBindings.\n const localNodeId = this.ctx.kernel.localNodeId ?? 'hub'\n this.ctx.eventBus.subscribe(\n { category: EventCategory.DeviceBindingsChanged },\n (event) => {\n const { deviceId, capName, reason, addonId, nodeId } = event.data\n if (nodeId === localNodeId) return\n if (reason === 'native-registered') {\n let perDevice = this.remoteNativeCaps.get(deviceId)\n if (!perDevice) {\n perDevice = new Map()\n this.remoteNativeCaps.set(deviceId, perDevice)\n }\n perDevice.set(capName, { addonId, nodeId })\n } else if (reason === 'native-unregistered') {\n const perDevice = this.remoteNativeCaps.get(deviceId)\n if (!perDevice) return\n perDevice.delete(capName)\n if (perDevice.size === 0) this.remoteNativeCaps.delete(deviceId)\n }\n },\n )\n\n // Purge every remote native-cap entry owned by a node that just dropped.\n // The worker will re-emit `native-registered` on its next boot — no\n // persistence needed here.\n const cluster = this.ctx.kernel.cluster\n if (cluster) {\n cluster.broker.localBus.on('$node.disconnected', (payload) => {\n const gone = payload.node.id\n const emptyDevices: number[] = []\n for (const [deviceId, perDevice] of this.remoteNativeCaps) {\n const toDelete: string[] = []\n for (const [capName, entry] of perDevice) {\n if (entry.nodeId === gone) toDelete.push(capName)\n }\n for (const capName of toDelete) perDevice.delete(capName)\n if (perDevice.size === 0) emptyDevices.push(deviceId)\n }\n for (const deviceId of emptyDevices) this.remoteNativeCaps.delete(deviceId)\n })\n }\n // Resolve the per-device `device-ops` native provider. Works hub-local\n // (direct CapabilityRegistry lookup) and cross-process (the native-cap\n // fallback builds a proxy that routes to the owning worker). Consumers\n // that previously spoke the `<addonId>.device-ops.device.<method>`\n // Moleculer action go through this path instead — no bridge, no\n // parallel transport, just the standard native-cap dispatch.\n const requireDeviceOps = (deviceId: number): IDeviceOpsProvider => {\n const ops = this.capabilityRegistry?.getNativeProvider<IDeviceOpsProvider>('device-ops', deviceId)\n if (!ops) {\n throw new Error(`[device-manager] device-ops native provider not found for '${deviceId}'`)\n }\n return ops\n }\n\n // ── Helpers ──────────────────────────────────────────────────────────────\n\n const readStore = async (): Promise<AddonStore> => {\n return (await settings.readAddonStore()) as AddonStore\n }\n\n const readIndex = async (): Promise<Record<string, string[]>> => {\n const store = await readStore()\n return store.deviceIndex ?? {}\n }\n\n const readMeta = async (): Promise<Record<string, PersistedDeviceMeta>> => {\n const store = await readStore()\n return store.deviceMeta ?? {}\n }\n\n /** Hardware-identity metadata map. Lives in a sibling key on the\n * device-manager addon store so its writers (`setMetadata`) never\n * collide with the lifecycle writers on `deviceMeta`\n * (`registerDevice` / `setName` / `setLocation` / `setDisabled`).\n * Single-writer per row eliminates the \"writer X clobbers writer\n * Y's field\" bug class — `setMetadata` is the only producer. */\n const readMetadataMap = async (): Promise<Record<string, Record<string, unknown>>> => {\n const store = await readStore()\n return store.deviceMetadata ?? {}\n }\n\n // Serialize every read-modify-write of the deviceMeta / deviceIndex\n // blob through a single promise chain. Without this, concurrent\n // setMetadata / setName / setLocation / setDisabled callers race:\n // each reads the same `allMeta` snapshot, patches its own row,\n // then writes back the FULL blob — last writer wins, prior patches\n // are silently lost. The race fired on every addon restart when 5\n // Reolink cameras populate metadata in parallel and only the last\n // write survives. The mutex queues writes; reads in between still\n // hit `readStore()` directly (no penalty for hot read paths).\n let metaWriteChain: Promise<unknown> = Promise.resolve()\n const withMetaWriteLock = async <T>(fn: () => Promise<T>): Promise<T> => {\n const previous = metaWriteChain\n let release: () => void = () => {}\n const next = new Promise<void>((resolve) => { release = resolve })\n metaWriteChain = next\n try {\n await previous.catch(() => { /* swallow — keep chain alive */ })\n return await fn()\n } finally {\n release()\n }\n }\n\n /**\n * Resolve a numeric deviceId to the owning `(addonId, stableId)` pair.\n * Scans persisted meta — live IDevice lookup (hub registry) is handled\n * separately per call site so callers can decide whether to route to\n * an in-process driver or to the cross-process `device-ops` bridge.\n * Returns null when no device with that id is known to the hub.\n */\n const resolvePersistedById = async (\n deviceId: number,\n ): Promise<{ addonId: string; stableId: string; meta: PersistedDeviceMeta } | null> => {\n const meta = await readMeta()\n for (const [key, m] of Object.entries(meta)) {\n if (m.id === deviceId) {\n const sep = key.indexOf(':')\n if (sep < 0) continue\n return { addonId: key.slice(0, sep), stableId: key.slice(sep + 1), meta: m }\n }\n }\n return null\n }\n\n // ── Provider implementation ───────────────────────────────────────────────\n\n // Synchronous ownership cache, keyed by NUMERIC deviceId now that the\n // hub allocates ids before construction. The persisted meta store is\n // authoritative but reads are async; hub-side callers (e.g.\n // `CapabilityRegistry.getNativeProvider` fallback) need ownership\n // without awaiting. We keep this map in sync with every\n // registerDevice/removeDevice the provider serves, and warm it from\n // persistence on boot.\n const idToAddonId = new Map<number, string>()\n {\n const meta = await readMeta()\n for (const [key, m] of Object.entries(meta)) {\n const sep = key.indexOf(':')\n if (sep < 0) continue\n idToAddonId.set(m.id, key.slice(0, sep))\n }\n }\n\n // `$node.connected` bootstrap seed for cross-process `device-ops`. When a\n // forked worker reconnects after a hub restart, its `registerNativeCap`\n // broadcast for the auto-registered `device-ops` cap can be lost if the\n // Moleculer transport is still mid-handshake at the moment of emit — the\n // `broker.broadcast($cluster-events, …)` reaches no peer. `remoteNativeCaps`\n // then stays empty for that device forever, and every `getBindings` /\n // `requireDeviceOps` call on the hub throws \"device-ops native provider\n // not found\", which in turn blocks `stream-broker` from wiring the\n // camera and every tRPC `getStreamSources` from succeeding.\n //\n // Since `device-ops` is auto-registered for every device by contract\n // (see `createBrokerDeviceManagerApi.register`), ownership alone is\n // enough to synthesize a valid entry: if addon X owns deviceId N (per\n // persisted meta), then X's worker MUST host `device-ops` for N.\n // Routing through `buildNativeCapProxy` keys on `addonId` only —\n // Moleculer resolves the node — so the synthetic entry is always\n // correct once the worker's service is mounted.\n //\n // Idempotent: a late-arriving real `DeviceBindingsChanged` event\n // overwrites the entry with the authoritative payload. Hub-local\n // natives are skipped: those sit in `capabilityRegistry` and are\n // folded in directly by `getBindings` / `getNativeProvider`.\n if (cluster) {\n cluster.broker.localBus.on('$node.connected', (payload: { node: { id: string } }) => {\n const connectedNodeId = payload.node.id\n const lastSlash = connectedNodeId.lastIndexOf('/')\n if (lastSlash < 0) return\n const connectedAddonId = connectedNodeId.slice(lastSlash + 1)\n if (connectedAddonId.length === 0) return\n for (const [deviceId, ownerAddonId] of idToAddonId) {\n if (ownerAddonId !== connectedAddonId) continue\n if (this.capabilityRegistry?.getNativeAddonId('device-ops', deviceId)) continue\n let perDevice = this.remoteNativeCaps.get(deviceId)\n if (!perDevice) {\n perDevice = new Map()\n this.remoteNativeCaps.set(deviceId, perDevice)\n }\n if (!perDevice.has('device-ops')) {\n perDevice.set('device-ops', { addonId: connectedAddonId, nodeId: connectedNodeId })\n }\n }\n // Active discovery for ALL native caps the worker hosts. The\n // `device-ops` seed above only covers one cap because device\n // ownership trivially implies it; for other caps (intercom,\n // ptz, motion, osd, …) we need to ASK the worker which devices\n // it has registered each cap on. Without this poll, an\n // `addon-restart` of a forked worker leaves `remoteNativeCaps`\n // empty for every cap whose `DeviceBindingsChanged` broadcast\n // got lost in the transport handshake window — the symptom is\n // bindings UI dropping from 13→7 entries until full server\n // restart.\n //\n // The poll is deferred to the next tick so service discovery\n // has time to register the worker's `*.native-provider.*`\n // services. We then iterate the broker's service registry,\n // pick services that match this connected node, and call\n // `$listDeviceIds` on each (ports the worker-side\n // `workerNativeCaps` map). Per-device entries are written\n // straight into `remoteNativeCaps`; a late real\n // `DeviceBindingsChanged` event idempotently overwrites them.\n setTimeout(() => {\n this.discoverWorkerNativeCaps(connectedNodeId, connectedAddonId).catch((err) => {\n this.ctx.logger.warn('worker native-cap discovery failed', {\n meta: { nodeId: connectedNodeId, addonId: connectedAddonId, error: errMsg(err) },\n })\n })\n }, 500)\n })\n }\n\n const allocateNextDeviceId = async (): Promise<number> => {\n // Read-modify-write under the same settings writer the rest of the\n // addon uses — sqlite-settings serializes writes per addon, so two\n // concurrent registerDevice calls are ordered and each gets a unique\n // id. No in-memory counter: the store is the single source of truth.\n const store = await readStore()\n const current = store.nextDeviceId ?? 1\n await settings.writeAddonStore({ nextDeviceId: current + 1 })\n return current\n }\n\n const provider: IDeviceManagerProvider & {\n resolveDeviceOwnerSync: (deviceId: number) => string | null\n resolveNativeCapOwnerSync: (capName: string, deviceId: number) => { addonId: string; nodeId: string } | null\n } = {\n\n /** Sync ownership lookup backing persistence fallbacks (e.g. remove()\n * when the owning worker is offline). Ownership is keyed by numeric\n * deviceId → owning addonId as recorded in the persisted meta. NOT\n * a native-cap lookup: an addon can own a device without registering\n * every possible cap natively (e.g. RtspCamera without snapshotUrl\n * doesn't register the snapshot cap). Use\n * `resolveNativeCapOwnerSync` for cap-resolution paths.\n */\n resolveDeviceOwnerSync: (deviceId: number): string | null => {\n return idToAddonId.get(deviceId) ?? null\n },\n\n /** Sync lookup for the addon that registered a native provider for\n * `(capName, deviceId)`. Backs `CapabilityRegistry`'s native fallback\n * so the hub only synthesizes a cross-process proxy when the cap is\n * actually published — never on speculative device ownership.\n *\n * Consults hub-local registrations first (in-process natives),\n * then the `remoteNativeCaps` map populated from\n * `DeviceBindingsChanged` events emitted by forked-worker\n * `registerNativeCap` calls. Both are generic: any addon that hosts\n * devices and registers caps via the standard context API shows up\n * here without per-addon branching.\n */\n resolveNativeCapOwnerSync: (capName: string, deviceId: number): { addonId: string; nodeId: string } | null => {\n const localAddonId = this.capabilityRegistry?.getNativeAddonId(capName, deviceId) ?? null\n if (localAddonId) {\n return { addonId: localAddonId, nodeId: this.ctx.kernel.localNodeId ?? 'hub' }\n }\n const remote = this.remoteNativeCaps.get(deviceId)?.get(capName) ?? null\n if (remote) return { addonId: remote.addonId, nodeId: remote.nodeId }\n return null\n },\n\n // ── Persistence ────────────────────────────────────────────────────────\n\n /** Idempotent numeric-id reservation. Callers invoke this before\n * constructing the owning `IDevice` so `DeviceContext.id` is bound\n * at construction time. A repeat call for the same `(addonId,\n * stableId)` returns the already-persisted id — same physical\n * device reconnecting after a driver restart keeps its original\n * number. Fresh pairs burn one slot from the monotonic\n * `nextDeviceId` counter and seed a meta placeholder so the\n * `deviceMeta` → `id` invariant holds even before\n * `registerDevice` completes. */\n allocateDeviceId: async (input) => {\n const { addonId, stableId } = input\n const key = deviceKey(addonId, stableId)\n return await withMetaWriteLock(async () => {\n const meta = await readMeta()\n const existing = meta[key]\n if (existing) return { id: existing.id }\n const id = await allocateNextDeviceId()\n await settings.writeAddonStore({\n deviceMeta: {\n ...meta,\n [key]: {\n type: 'generic',\n name: stableId,\n location: null,\n disabled: false,\n parentDeviceId: null,\n id,\n },\n },\n })\n return { id }\n })\n },\n\n registerDevice: async (input) => {\n const { addonId, stableId, id, type, name, parentDeviceId, features, config } = input\n const key = deviceKey(addonId, stableId)\n\n const featuresArr = Array.isArray(features) ? [...features] : []\n // Index update + meta write together under the lock so a\n // concurrent registerDevice for a different (addonId, stableId)\n // can't read/clobber our deviceMeta snapshot.\n const { isFirstRegistration } = await withMetaWriteLock(async () => {\n const index = await readIndex()\n const existing = index[addonId] ?? []\n const wasInIndex = existing.includes(stableId)\n if (!wasInIndex) {\n await settings.writeAddonStore({\n deviceIndex: { ...index, [addonId]: [...existing, stableId] },\n })\n }\n\n // Persist the full meta record. The kernel's `create()`\n // shortcut writes operator-supplied `name` + `location`\n // BEFORE construction via `setName` / `setLocation` actions,\n // so by the time we land here the placeholder name is already\n // overwritten. Preserve every operator-edited field; the\n // `name` arg coming through this action is the device's\n // construction-time `device.name` which already reflects\n // whatever the meta row carries (`BaseDevice` reads from\n // `ctx.deviceMeta.name`).\n const meta = await readMeta()\n const existingMeta = meta[key]\n // First registration vs subsequent meta refresh (e.g. post-probe\n // features update). Drives whether we emit a `DeviceRegistered`\n // event below — listeners (ReolinkHub discovery refresh, etc)\n // must not re-fire on every meta update or downstream work\n // multiplies.\n const isFirst = !existingMeta || !wasInIndex\n await settings.writeAddonStore({\n deviceMeta: {\n ...meta,\n [key]: {\n type,\n // Prefer the persisted name (set by `setName` pre-construct)\n // over the construction-time fallback. Only when the meta\n // row literally still carries `name === stableId` (the\n // placeholder seeded by `allocateDeviceId`) do we fall\n // back to the action arg.\n name: existingMeta && existingMeta.name !== stableId ? existingMeta.name : name,\n location: existingMeta?.location ?? null,\n disabled: existingMeta?.disabled ?? false,\n parentDeviceId,\n id,\n features: featuresArr,\n },\n },\n })\n return { isFirstRegistration: isFirst }\n })\n\n // Config is pre-persisted by the kernel's `create()` shortcut\n // via `persistConfig` BEFORE construction. We still accept a\n // non-empty `config` payload here for back-compat with paths\n // that haven't migrated, and write it through — but the\n // canonical CREATE path passes `config: {}` and the persisted\n // row stays untouched.\n if (Object.keys(config).length > 0) {\n await settings.writeDeviceStore(id, config)\n }\n\n idToAddonId.set(id, addonId)\n\n // Emit `DeviceRegistered` ONLY on first registration. Subsequent\n // calls (driver re-publishing post-probe features, accessory\n // count update, …) are silent meta refreshes — listeners that\n // care about the device existing already saw the first event.\n // Skipping the duplicate prevents listeners like ReolinkHub from\n // burning a discovery-refresh roundtrip per re-register.\n if (isFirstRegistration) {\n this.ctx.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'device', id },\n category: EventCategory.DeviceRegistered,\n data: {\n deviceId: id,\n name: (name.length > 0 ? name : stableId),\n providerId: addonId,\n parentDeviceId: parentDeviceId ?? null,\n },\n })\n } else {\n this.ctx.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'device', id },\n category: EventCategory.DeviceMetaChanged,\n data: {\n deviceId: id,\n name: (name.length > 0 ? name : stableId),\n providerId: addonId,\n parentDeviceId: parentDeviceId ?? null,\n features: featuresArr,\n },\n })\n }\n },\n\n removeDevice: async (input) => {\n const { deviceId } = input\n // Resolve `(addonId, stableId)` from the meta store. The cap input\n // only carries the numeric id now — internal cleanup still needs\n // the composite key for index/meta storage rows (those are the\n // external-linkage rows we deliberately keep stableId in).\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) {\n // Removal of an unknown device is a no-op (idempotent) — the\n // caller may be racing teardown after a crash. No throw: the\n // hub-level `remove()` already error-checks first.\n return\n }\n const { addonId, stableId, meta: persistedMeta } = persisted\n const key = deviceKey(addonId, stableId)\n const deviceName = persistedMeta.name\n\n await withMetaWriteLock(async () => {\n // Update index + meta + hardware-metadata together under the\n // lock so we can't lose a concurrent register's freshly-persisted\n // row by reading a pre-write snapshot of `meta`.\n const index = await readIndex()\n const remaining = (index[addonId] ?? []).filter(sid => sid !== stableId)\n const updatedIndex = remaining.length > 0\n ? { ...index, [addonId]: remaining }\n : (() => { const { [addonId]: _removed, ...rest } = index; return rest })()\n await settings.writeAddonStore({ deviceIndex: updatedIndex })\n\n const meta = await readMeta()\n const { [key]: _removedMeta, ...restMeta } = meta\n await settings.writeAddonStore({ deviceMeta: restMeta })\n\n const map = await readMetadataMap()\n if (key in map) {\n const { [key]: _removedMetadata, ...restMap } = map\n await settings.writeAddonStore({ deviceMetadata: restMap })\n }\n })\n\n // Delete all per-device config rows so no orphaned settings remain after removal.\n await settings.clearDeviceStore(deviceId)\n\n // Drop any persisted wrapper activations tied to this device so\n // `getBindings({deviceId})` stops returning stale entries after remove.\n const bindingsStore = await this.readBindingsStore()\n const bindingKey = String(deviceId)\n if (bindingsStore.deviceBindings[bindingKey]) {\n const { [bindingKey]: _removedBindings, ...restBindings } = bindingsStore.deviceBindings\n await this.writeBindingsStore({ deviceBindings: restBindings })\n }\n\n // Drop every cross-process native-cap mirror entry for this device.\n // The worker's device-ops bridge removeDevice handler doesn't emit\n // `native-unregistered` events today; doing the purge here keeps the\n // hub view consistent regardless of which teardown path ran.\n this.remoteNativeCaps.delete(deviceId)\n // Hub-local natives live in the CapabilityRegistry — clear them too\n // so in-process devices don't linger in `getNativeCapsForDevice`.\n this.capabilityRegistry?.unregisterAllNativeForDevice(deviceId)\n\n idToAddonId.delete(deviceId)\n\n this.ctx.logger.info('removed device', { tags: { deviceId, deviceName: deviceName.length > 0 ? deviceName : stableId } })\n this.ctx.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'device', id: deviceId },\n category: EventCategory.DeviceUnregistered,\n data: {\n deviceId,\n providerId: addonId,\n // Carry parentDeviceId so listeners can filter on \"is\n // this MY child?\" without consulting an in-memory map\n // they had to keep in sync. By the time this event\n // fires the meta row is already gone — we read it from\n // the resolved snapshot above.\n parentDeviceId: persistedMeta.parentDeviceId ?? null,\n },\n })\n },\n\n persistConfig: async (input) => {\n const { deviceId, data } = input\n // Per-device config is keyed by numeric id end-to-end. We still\n // verify the device is known (resolves through meta) so a write\n // for a non-existent id throws instead of silently allocating a\n // stray store entry.\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) throw new Error(`[device-manager] persistConfig: unknown device id=${deviceId}`)\n await settings.writeDeviceStore(deviceId, data)\n },\n\n loadConfig: async (input) => {\n const { deviceId } = input\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) return {}\n return settings.readDeviceStore(deviceId)\n },\n\n /**\n * Load the operator-organisational meta surface for one device\n * (`name` / `location` / `disabled` / `type` / `parentDeviceId`\n * / `addonId` + `id` / `stableId`). Used by the kernel proxy's\n * device-context factory to populate `ctx.deviceMeta` before\n * the device class constructor runs. Returns `null` when no\n * persisted row exists for the id.\n *\n * Reads default `location` to `null` and `disabled` to `false`\n * for legacy rows that predate the field — production code\n * relies on the IDevice type contract that both are present.\n */\n loadMeta: async (input) => {\n const { deviceId } = input\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) return null\n const { addonId, stableId, meta: m } = persisted\n const key = deviceKey(addonId, stableId)\n const map = await readMetadataMap()\n const metadata = map[key] ?? null\n return {\n id: m.id,\n stableId,\n addonId,\n type: m.type as DeviceType,\n name: m.name,\n location: m.location ?? null,\n disabled: m.disabled ?? false,\n parentDeviceId: m.parentDeviceId,\n metadata,\n }\n },\n\n /**\n * Update the operator-edited display name. Writes the meta\n * row, emits a `DeviceMetaChanged` event so live consumers\n * (UI device list, alert center) see the rename without\n * polling. The live `IDevice.name` mirror is updated by the\n * kernel proxy on its side (`device-cap-proxy.ts`).\n */\n setName: async (input) => {\n const { deviceId, name } = input\n await withMetaWriteLock(async () => {\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) throw new Error(`[device-manager] setName: unknown device id=${deviceId}`)\n const { addonId, stableId, meta: m } = persisted\n const key = deviceKey(addonId, stableId)\n const allMeta = await readMeta()\n await settings.writeAddonStore({\n deviceMeta: { ...allMeta, [key]: { ...m, name } },\n })\n })\n this.ctx.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'device', id: deviceId },\n category: EventCategory.DeviceMetaChanged,\n data: { deviceId, field: 'name', value: name },\n })\n },\n\n /**\n * Update the operator-organisational location label. `null`\n * clears it. Mirrors the same persist-then-emit shape as\n * `setName`; consumers subscribe to `DeviceMetaChanged` and\n * filter on `field: 'location'`.\n */\n setLocation: async (input) => {\n const { deviceId, location } = input\n await withMetaWriteLock(async () => {\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) throw new Error(`[device-manager] setLocation: unknown device id=${deviceId}`)\n const { addonId, stableId, meta: m } = persisted\n const key = deviceKey(addonId, stableId)\n const allMeta = await readMeta()\n await settings.writeAddonStore({\n deviceMeta: { ...allMeta, [key]: { ...m, location } },\n })\n })\n this.ctx.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'device', id: deviceId },\n category: EventCategory.DeviceMetaChanged,\n data: { deviceId, field: 'location', value: location },\n })\n },\n\n /**\n * Patch the device's hardware-identity metadata blob. Shallow\n * merge — `null` removes a key, anything else overwrites.\n * Drivers populate factual fields on first probe; operators\n * augment via the Device Info tab. Idempotent: a no-op patch\n * (every key already present with the same value) doesn't emit\n * the meta-changed event.\n */\n setMetadata: async (input) => {\n const { deviceId, patch } = input\n const result = await withMetaWriteLock(async () => {\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) throw new Error(`[device-manager] setMetadata: unknown device id=${deviceId}`)\n const { addonId, stableId } = persisted\n const key = deviceKey(addonId, stableId)\n const map = await readMetadataMap()\n const current = (map[key] ?? {}) as Record<string, unknown>\n const next: Record<string, unknown> = { ...current }\n let changed = false\n for (const [k, v] of Object.entries(patch)) {\n if (v === null) {\n if (k in next) {\n delete next[k]\n changed = true\n }\n } else if (next[k] !== v) {\n next[k] = v\n changed = true\n }\n }\n if (!changed) return { changed: false as const }\n const hasFields = Object.keys(next).length > 0\n const updatedMap = { ...map }\n if (hasFields) {\n updatedMap[key] = next\n } else {\n delete updatedMap[key]\n }\n await settings.writeAddonStore({ deviceMetadata: updatedMap })\n return { changed: true as const, finalMeta: hasFields ? next : null }\n })\n if (!result.changed) return\n this.ctx.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'device', id: deviceId },\n category: EventCategory.DeviceMetaChanged,\n data: { deviceId, field: 'metadata', value: result.finalMeta },\n })\n },\n\n /**\n * Soft-disable the device. Persisted on the meta row;\n * lifecycle gating is the driver's responsibility (BaseDevice\n * exposes `this.disabled` for the driver to consult at the top\n * of its lifecycle methods).\n */\n setDisabled: async (input) => {\n const { deviceId, disabled } = input\n await withMetaWriteLock(async () => {\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) throw new Error(`[device-manager] setDisabled: unknown device id=${deviceId}`)\n const { addonId, stableId, meta: m } = persisted\n const key = deviceKey(addonId, stableId)\n const allMeta = await readMeta()\n await settings.writeAddonStore({\n deviceMeta: { ...allMeta, [key]: { ...m, disabled } },\n })\n })\n this.ctx.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'device', id: deviceId },\n category: EventCategory.DeviceMetaChanged,\n data: { deviceId, field: 'disabled', value: disabled },\n })\n },\n\n loadRuntimeState: async (input) => {\n const { deviceId } = input\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) return {}\n const data = await settings.readDeviceRuntimeState(deviceId)\n // Seed the mirror at first load so the hub knows about every\n // existing slice immediately — providers might never call\n // `setCapSlice` if their runtime state doesn't change, and\n // the mirror would otherwise stay empty until the first\n // change.\n this.seedMirror(deviceId, data)\n return data\n },\n\n /**\n * Union of (1) operator-curated location registry and (2) labels\n * currently in use on persisted devices. Case-insensitive\n * dedupe (preserves the first-seen casing). Sorted\n * case-insensitively for stable UI. Drives the Device Info\n * location autocomplete.\n */\n listLocations: async () => {\n const store = (await settings.readAddonStore()) as AddonStore\n const meta = store.deviceMeta ?? {}\n const registry = store.locations ?? []\n // Map from lower-cased key to the first-seen casing so duplicate\n // entries with different cases collapse to one.\n const seen = new Map<string, string>()\n const consider = (raw: unknown): void => {\n if (typeof raw !== 'string') return\n const trimmed = raw.trim()\n if (trimmed.length === 0) return\n const key = trimmed.toLowerCase()\n if (!seen.has(key)) seen.set(key, trimmed)\n }\n for (const label of registry) consider(label)\n for (const m of Object.values(meta)) consider(m.location)\n return [...seen.values()].sort((a, b) =>\n a.localeCompare(b, undefined, { sensitivity: 'base' }),\n )\n },\n\n /**\n * Add a label to the curated location registry. Idempotent:\n * existing entries (case-insensitive match) are silently kept.\n * Empty / whitespace-only inputs throw — operators must supply a\n * meaningful label.\n */\n addLocation: async (input) => {\n const trimmed = input.name.trim()\n if (trimmed.length === 0) {\n throw new Error('[device-manager] addLocation: name must be non-empty')\n }\n const store = (await settings.readAddonStore()) as AddonStore\n const current = store.locations ?? []\n if (current.some((l) => l.toLowerCase() === trimmed.toLowerCase())) {\n // Already present — no-op (preserves first-seen casing).\n return\n }\n await settings.writeAddonStore({ locations: [...current, trimmed] })\n },\n\n /**\n * Remove a label from the curated registry. Match is\n * case-insensitive. Devices that still reference this label keep\n * their `meta.location` value (the registry is a suggestion\n * list, not a foreign key) — pass `cascade: true` to also clear\n * `setLocation` on every device that referenced this exact\n * label. Cascade only matches case-insensitively + trimmed, same\n * as the registry equality check.\n */\n removeLocation: async (input) => {\n const trimmed = input.name.trim()\n if (trimmed.length === 0) return\n const store = (await settings.readAddonStore()) as AddonStore\n const current = store.locations ?? []\n const remaining = current.filter((l) => l.toLowerCase() !== trimmed.toLowerCase())\n if (remaining.length !== current.length) {\n await settings.writeAddonStore({ locations: remaining })\n }\n if (input.cascade !== true) return\n\n const meta = store.deviceMeta ?? {}\n const updates: Record<string, PersistedDeviceMeta> = { ...meta }\n const cleared: number[] = []\n for (const [key, m] of Object.entries(meta)) {\n if (typeof m.location !== 'string') continue\n if (m.location.trim().toLowerCase() !== trimmed.toLowerCase()) continue\n updates[key] = { ...m, location: null }\n cleared.push(m.id)\n }\n if (cleared.length === 0) return\n await settings.writeAddonStore({ deviceMeta: updates })\n for (const deviceId of cleared) {\n this.ctx.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'device', id: deviceId },\n category: EventCategory.DeviceMetaChanged,\n data: { deviceId, field: 'location', value: null },\n })\n }\n },\n\n listPersistedByAddon: async (input) => {\n const { addonId } = input\n const [index, meta] = await Promise.all([readIndex(), readMeta()])\n const stableIds = index[addonId] ?? []\n return stableIds.map(stableId => {\n const m = meta[deviceKey(addonId, stableId)]!\n return {\n id: m.id,\n stableId,\n type: m.type,\n name: m.name,\n location: m.location ?? null,\n disabled: m.disabled ?? false,\n parentDeviceId: m.parentDeviceId,\n }\n })\n },\n\n // ── Live queries — serve from live registry when available ────────────\n\n listAll: async (input) => {\n const { addonId } = input\n\n // Union of two sources, de-duped on (addonId, stableId):\n // 1. Hub-process live registry: IDevice instances owned by this\n // process (hub-resident addons). Provides live `online`,\n // features, and isCamera.\n // 2. Persisted index (settings): authoritative cross-process ledger\n // including devices owned by forked workers, whose IDevice\n // instance lives in the worker's registry and is invisible to\n // the hub-registry.\n //\n // Live wins on the overlap, so hub-owned devices keep their accurate\n // online/features. Forked-worker devices are reconstructed from\n // persisted metadata + persisted config.\n const results: ReturnType<typeof toDeviceInfo>[] = []\n const seen = new Set<string>()\n\n const meta = await readMeta()\n // Hardware metadata lives in its own row; pre-load once and inject\n // into every result regardless of branch.\n const metadataMap = await readMetadataMap()\n\n if (registry) {\n const liveEntries = addonId\n ? registry.getAllForAddon(addonId).map(device => ({ addonId: addonId!, device }))\n : registry.getAllWithAddonId()\n for (const { addonId: aid, device } of liveEntries) {\n const key = deviceKey(aid, device.stableId)\n const metadata = metadataMap[key] ?? null\n const metaRow = meta[key] ?? null\n results.push(toDeviceInfo(aid, device, metadata, metaRow))\n seen.add(key)\n }\n }\n\n const index = await readIndex()\n const targetAddons = addonId ? [addonId] : Object.keys(index)\n for (const aid of targetAddons) {\n for (const stableId of (index[aid] ?? [])) {\n const key = deviceKey(aid, stableId)\n if (seen.has(key)) continue\n const m = meta[key]!\n const persistedType = m.type as DeviceType\n const persistedConfig = (await settings.readDeviceStore(m.id)) as Record<string, unknown>\n const metadata = metadataMap[key] ?? null\n results.push({\n id: m.id,\n stableId,\n addonId: aid,\n type: persistedType,\n name: m?.name ?? stableId,\n location: m?.location ?? null,\n disabled: m?.disabled ?? false,\n parentDeviceId: m?.parentDeviceId ?? null,\n // role is not persisted to disk — only set on the live\n // IDevice (`BaseDevice.role`) by accessory subclasses. The\n // forked-worker fallback path can't read it, so emit null;\n // accessories typically run in the same process as their\n // parent provider, so the live path covers them in practice.\n role: null,\n // registry===null was the legacy \"offline view\" signal; keep it\n // for that case so existing callers see online=false. When a\n // registry is present and the device lives elsewhere (forked\n // worker), default to online=true — persisted state implies it\n // was successfully registered by its owning process.\n online: registry !== null,\n features: persistedFeatures(m?.features),\n // Live IDevice isn't reachable from the hub, so infer\n // isCamera from the persisted DeviceType rather than the\n // method-presence check `toDeviceInfo` uses. Without this\n // forked-worker cameras looked non-camera to the stream-broker\n // and never got their RTSP restream wired up.\n isCamera: persistedType === DeviceType.Camera,\n config: persistedConfig ?? {},\n metadata,\n })\n }\n }\n return results\n },\n\n getDevice: async (input) => {\n const { deviceId } = input\n\n // Prefer live (hub-registry) when present; otherwise fall back to\n // persisted metadata so we also find devices owned by forked workers.\n if (registry) {\n const found = resolveDeviceById(registry, deviceId)\n if (found) {\n const key = deviceKey(found.addonId, found.device.stableId)\n const [map, metaMap] = await Promise.all([readMetadataMap(), readMeta()])\n const metadata = map[key] ?? null\n const metaRow = metaMap[key] ?? null\n return toDeviceInfo(found.addonId, found.device, metadata, metaRow)\n }\n }\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) return null\n const { addonId: aid, stableId, meta: m } = persisted\n const persistedConfig = (await settings.readDeviceStore(m.id)) as Record<string, unknown>\n const key = deviceKey(aid, stableId)\n const map = await readMetadataMap()\n const metadata = map[key] ?? null\n // Name now lives exclusively on the meta surface (mutated via\n // `setName` action) — the legacy config.name fallback is gone\n // since drivers no longer carry `name` in their config schema.\n return {\n id: deviceId,\n stableId,\n addonId: aid,\n type: m.type as DeviceType,\n name: m.name,\n location: m.location ?? null,\n disabled: m.disabled ?? false,\n parentDeviceId: m.parentDeviceId,\n role: null,\n online: true,\n features: persistedFeatures(m.features),\n isCamera: false,\n config: persistedConfig ?? {},\n metadata,\n }\n },\n\n getChildren: async (input) => {\n const { parentDeviceId } = input\n\n // Resolve parent ownership so we can scope the persisted-child scan\n // per owning addon. Children are always registered under the same\n // addonId as their parent. The hub registry's getChildren() is a\n // pure numeric filter (`d.parentDeviceId === parentDeviceId`) so\n // we no longer need the parent's stableId for live lookups.\n let ownerAddonId: string | null = null\n if (registry) {\n const liveParent = registry.getById(parentDeviceId)\n if (liveParent) {\n ownerAddonId = registry.getAddonId(parentDeviceId)\n }\n }\n if (!ownerAddonId) {\n const persisted = await resolvePersistedById(parentDeviceId)\n if (!persisted) return []\n ownerAddonId = persisted.addonId\n }\n\n // Same union pattern as listAll: live (hub-registry) wins, persisted\n // fills in devices owned by forked workers.\n const results: ReturnType<typeof toDeviceInfo>[] = []\n const seen = new Set<string>()\n\n const [index, meta, metadataMap] = await Promise.all([readIndex(), readMeta(), readMetadataMap()])\n\n if (registry) {\n const liveChildren = registry.getChildren(parentDeviceId)\n for (const device of liveChildren) {\n const key = deviceKey(ownerAddonId, device.stableId)\n const metadata = metadataMap[key] ?? null\n const metaRow = meta[key] ?? null\n results.push(toDeviceInfo(ownerAddonId, device, metadata, metaRow))\n seen.add(key)\n }\n }\n\n const stableIds = index[ownerAddonId] ?? []\n const persistedChildren = stableIds.filter(\n sid => meta[deviceKey(ownerAddonId!, sid)]?.parentDeviceId === parentDeviceId,\n )\n for (const childStableId of persistedChildren) {\n const key = deviceKey(ownerAddonId, childStableId)\n if (seen.has(key)) continue\n const m = meta[key]!\n const persistedConfig = (await settings.readDeviceStore(m.id)) as Record<string, unknown>\n const metadata = metadataMap[key] ?? null\n results.push({\n id: m.id,\n stableId: childStableId,\n addonId: ownerAddonId,\n type: m.type as DeviceType,\n name: m.name,\n location: m.location ?? null,\n disabled: m.disabled ?? false,\n parentDeviceId,\n role: null,\n online: registry !== null,\n features: persistedFeatures(m.features),\n isCamera: false,\n config: persistedConfig ?? {},\n metadata,\n })\n }\n return results\n },\n\n // ── Live runtime methods ──────────────────────────────────────────────\n\n getStreamSources: async (input) => {\n const { deviceId } = input\n // Hub-local path\n if (registry) {\n const found = resolveDeviceById(registry, deviceId)\n if (found) {\n // Non-camera devices have no streams by definition — return\n // an empty list immediately instead of round-tripping through\n // `device-ops`. Cross-process dispatch is strictly for\n // worker-owned devices, not for wrong-type hub-local ones.\n if (!isCameraDevice(found.device)) return []\n const sources: readonly StreamSourceEntry[] = await found.device.getStreamSources()\n return sources.map(s => ({\n id: s.id,\n label: s.label,\n protocol: s.protocol,\n url: s.url,\n resolution: s.resolution,\n fps: s.fps,\n bitrate: s.bitrate,\n codec: s.codec,\n profileHint: s.profileHint,\n }))\n }\n }\n // Cross-process fallback — dispatch through the `device-ops` native\n // provider, now keyed on the numeric id in both hub and worker.\n // Errors propagate: a transient worker error must NOT masquerade as\n // \"device has no streams\" — callers need the real error.\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) throw new Error(`[device-manager] Device with id ${deviceId} not found`)\n const ops = requireDeviceOps(deviceId)\n const sources = await ops.getStreamSources({ deviceId })\n return sources.map(s => ({ ...s }))\n },\n\n getConfigSchema: async (input) => {\n const { deviceId } = input\n if (registry) {\n const found = resolveDeviceById(registry, deviceId)\n if (found) {\n return found.device.config.entries().map(entry => ({\n key: entry.key,\n value: entry.value,\n ...(entry.description !== undefined ? { description: entry.description } : {}),\n }))\n }\n }\n // Cross-process fallback. Propagates the real error when the\n // owning worker is offline or the device genuinely doesn't exist —\n // surfacing \"no config\" silently used to let the UI render empty\n // forms for broken devices.\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) throw new Error(`[device-manager] Device with id ${deviceId} not found`)\n const ops = requireDeviceOps(deviceId)\n const entries = await ops.getConfigEntries({ deviceId })\n return entries.map(e => ({ ...e }))\n },\n\n getSettingsSchema: async (input) => {\n const { deviceId } = input\n // Single source of truth: every IDevice implements\n // `getSettingsUISchema`. Hub-local devices answer in-process;\n // forked-worker devices go through the `device-ops.getSettingsSchema`\n // native provider which delegates to the same method worker-side.\n if (registry) {\n const found = resolveDeviceById(registry, deviceId)\n if (found) {\n return found.device.getSettingsUISchema()\n }\n }\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) return null\n const ops = requireDeviceOps(deviceId)\n const schema = await ops.getSettingsSchema({ deviceId })\n return (schema as ConfigUISchemaWithValues | null) ?? null\n },\n\n updateConfig: async (input) => {\n const { deviceId } = input\n if (registry) {\n const found = resolveDeviceById(registry, deviceId)\n if (found) {\n await found.device.config.setAll(input.values)\n return { success: true as const }\n }\n }\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) throw new Error(`[device-manager] Device with id ${deviceId} not found`)\n const ops = requireDeviceOps(deviceId)\n await ops.setConfig({ deviceId, values: input.values })\n return { success: true as const }\n },\n\n // `enable` / `disable` write to deviceMeta.disabled (the canonical\n // soft-disable flag that drivers consult via `BaseDevice.disabled`\n // at lifecycle entrypoints, and that `toDeviceInfo` projects onto\n // the wire by reading the LATEST persisted meta row — see the\n // `metaRow` argument plumbed through `listAll` / `getDevice` /\n // `getChildren`).\n //\n // Earlier these wrappers wrote `enabled: true/false` into the\n // device CONFIG blob — wrong store entirely. The config write\n // succeeded but the flag the rest of the system reads\n // (deviceMeta) stayed unchanged, so the UI's enable/disable\n // toggle appeared to do nothing. Delegating to `setDisabled`\n // routes through the correct withMetaWriteLock path and emits\n // the `DeviceMetaChanged` event for live invalidation.\n //\n // NB: `BaseDevice.disabled` is `readonly` and bound at\n // construction (base-device.ts:142). Drivers that gate behaviour\n // off `this.disabled` only see the value the device was\n // instantiated with — flipping disabled at runtime updates the\n // wire response immediately, but lifecycle gating inside the\n // driver only takes effect on the next instantiation. That's\n // acceptable today: the operator-facing semantic is \"hide /\n // mark inactive in the UI\"; the heavyweight teardown semantic\n // is `remove`.\n enable: async (input) => {\n await provider.setDisabled({ deviceId: input.deviceId, disabled: false })\n return { success: true as const }\n },\n\n disable: async (input) => {\n await provider.setDisabled({ deviceId: input.deviceId, disabled: true })\n return { success: true as const }\n },\n\n remove: async (input) => {\n const { deviceId } = input\n // (a) Device lives in the hub registry → local teardown, then persistence.\n if (registry) {\n const live = resolveDeviceById(registry, deviceId)\n if (live) {\n const deviceName = live.device.name\n await live.device.removeDevice()\n registry.remove(deviceId)\n await provider.removeDevice({ deviceId })\n this.ctx.logger.info('removed hub-local device', { tags: { deviceId, deviceName } })\n return { success: true as const }\n }\n }\n // (b) Device is owned by a forked worker → invoke its `device-ops`\n // native provider to let the driver release resources, then\n // clear hub persistence.\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) throw new Error(`[device-manager] Device with id ${deviceId} not found`)\n const { meta: persistedMeta } = persisted\n try {\n const ops = requireDeviceOps(deviceId)\n await ops.removeDevice({ deviceId })\n } catch (err) {\n // Worker might be offline or missing — still clear persistence so\n // the UI recovers. The warning is best-effort diagnostics.\n this.ctx.logger.warn('remove via device-ops failed — clearing persistence anyway', { tags: { deviceId, deviceName: persistedMeta.name }, meta: { error: errMsg(err) } })\n }\n await provider.removeDevice({ deviceId })\n return { success: true as const }\n },\n\n getStreamProfileMap: async (input) => {\n if (!registry) return {}\n const found = resolveDeviceById(registry, input.deviceId)\n if (!found) return {}\n\n // Check for explicitly stored profile map first\n const storedMap: unknown = found.device.config.entries().find(e => e.key === '_profileMap')?.value\n if (storedMap !== undefined && typeof storedMap === 'object' && storedMap !== null) {\n return storedMap as Record<string, string>\n }\n\n // Derive from profileHint fields on stream sources\n if (!isCameraDevice(found.device)) return {}\n const sources: readonly StreamSourceEntry[] = await found.device.getStreamSources()\n const profileMap: Record<string, string> = {}\n for (const s of sources) {\n if (s.profileHint && s.id) {\n profileMap[s.profileHint] = s.id\n }\n }\n return profileMap\n },\n\n setStreamProfileMap: async (input) => {\n const { deviceId } = input\n if (registry) {\n const found = resolveDeviceById(registry, deviceId)\n if (found) {\n await found.device.config.setAll({ _profileMap: input.profileMap })\n return { success: true as const }\n }\n }\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) throw new Error(`[device-manager] Device with id ${deviceId} not found`)\n const ops = requireDeviceOps(deviceId)\n await ops.setConfig({ deviceId, values: { _profileMap: input.profileMap } })\n return { success: true as const }\n },\n\n probeStreams: async (input) => {\n const streamProbe = this.ctx.kernel.streamProbe\n if (!streamProbe) return []\n\n const sources = await provider.getStreamSources({ deviceId: input.deviceId })\n const results: Array<{\n streamId: string\n width?: number\n height?: number\n codec?: string\n fps?: number\n bitrateKbps?: number\n }> = []\n\n for (const s of sources) {\n if (!s.url) continue\n try {\n const metadata = await streamProbe.probe(s.url, { force: true })\n results.push({\n streamId: s.id,\n width: metadata.width,\n height: metadata.height,\n codec: metadata.codec,\n fps: metadata.fps,\n bitrateKbps: metadata.bitrateKbps,\n })\n } catch (err) {\n this.ctx.logger.debug('streamProbe.probe failed — returning placeholder', {\n meta: {\n deviceId: input.deviceId,\n streamId: s.id,\n error: err instanceof Error ? err.message : String(err),\n },\n })\n results.push({ streamId: s.id })\n }\n }\n\n return results\n },\n\n // ── Device-provider operations (routed via CapabilityRegistry) ───────\n\n discoverDevices: async (input) => {\n const dp = await this.requireDeviceProvider(input.addonId)\n\n const supported = await dp.supportsDiscovery({})\n if (!supported) {\n throw new Error(`Addon \"${input.addonId}\" does not support device discovery`)\n }\n\n const discovered = await dp.discoverDevices({})\n return discovered.map((d) => ({\n stableId: d.stableId,\n type: d.type,\n suggestedName: d.suggestedName,\n prefilledConfig: d.prefilledConfig,\n }))\n },\n\n adoptDevice: async (input) => {\n const dp = await this.requireDeviceProvider(input.addonId)\n\n const supported = await dp.supportsDiscovery({})\n if (!supported) {\n throw new Error(`Addon \"${input.addonId}\" does not support device adoption`)\n }\n\n return dp.adoptDiscoveredDevice({\n candidate: input.candidate as Parameters<IDeviceProviderCap['adoptDiscoveredDevice']>[0]['candidate'],\n })\n },\n\n getCreationSchema: async (input) => {\n const dp = await this.requireDeviceProvider(input.addonId)\n\n const supported = await dp.supportsManualCreation({})\n if (!supported) return null\n\n const schema = await dp.getChildCreationSchema({ type: input.type })\n return schema ?? null\n },\n\n createDevice: async (input) => {\n const dp = await this.requireDeviceProvider(input.addonId)\n\n const supported = await dp.supportsManualCreation({})\n if (!supported) {\n throw new Error(`Addon \"${input.addonId}\" does not support manual device creation`)\n }\n\n return dp.createDevice({ type: input.type, config: input.config })\n },\n\n testCreationField: async (input) => {\n const dp = await this.requireDeviceProvider(input.addonId)\n return dp.testCreationField({\n type: input.type,\n key: input.key,\n value: input.value,\n ...(input.formValues !== undefined ? { formValues: input.formValues } : {}),\n })\n },\n\n testField: async (input) => {\n const { deviceId } = input\n let owningAddonId: string | null = null\n if (registry) {\n owningAddonId = registry.getAddonId(deviceId)\n }\n if (!owningAddonId) {\n const persisted = await resolvePersistedById(deviceId)\n owningAddonId = persisted?.addonId ?? null\n }\n if (!owningAddonId) {\n throw new Error(`Device with id ${deviceId} not found`)\n }\n\n const dp = await this.waitDeviceProvider(owningAddonId)\n if (!dp) {\n return { status: 'ok' as const, labels: [], error: undefined }\n }\n\n if (typeof (dp as Record<string, unknown>).testCreationField !== 'function') {\n return { status: 'ok' as const, labels: [], error: undefined }\n }\n\n return dp.testCreationField({ type: DeviceType.Camera, key: input.key, value: input.value })\n },\n\n // ── Bindings — per-device capability provider map ────────────────────\n\n getBindings: async (input) => {\n const result = await this.getBindings({ deviceId: input.deviceId })\n return { deviceId: input.deviceId, entries: result.entries }\n },\n getAllBindings: async () => {\n return this.getAllBindings()\n },\n setWrapperActive: async (input) => {\n return this.setWrapperActive({\n deviceId: input.deviceId,\n capName: input.capName,\n wrapperAddonId: input.wrapperAddonId,\n active: input.active,\n })\n },\n listWrappersForCap: async (input) => this.listWrappersForCap(input),\n listBindableCapsForDeviceType: async (input) => this.listBindableCapsForDeviceType(input),\n\n // ── Device-details aggregators ──────────────────────────────────────\n\n getDeviceSettingsAggregate: async (input) => {\n return this.getDeviceAggregate(input.deviceId, 'settings')\n },\n getDeviceLiveInfoAggregate: async (input) => {\n return this.getDeviceAggregate(input.deviceId, 'live')\n },\n getDeviceAggregate: async (input) => {\n // Run both aggregations in parallel — the live + settings passes\n // enumerate the same provider set but call different methods, so\n // there's no overlap to serialize.\n const [settings, live] = await Promise.all([\n this.getDeviceAggregate(input.deviceId, 'settings'),\n this.getDeviceAggregate(input.deviceId, 'live'),\n ])\n return { settings, live }\n },\n updateDeviceField: async (input) => {\n return this.updateDeviceField({\n deviceId: input.deviceId,\n writerCapName: input.writerCapName,\n writerAddonId: input.writerAddonId,\n key: input.key,\n value: input.value,\n })\n },\n updateDeviceFieldsBatch: async (input) => {\n return this.updateDeviceFieldsBatch({ deviceId: input.deviceId, changes: input.changes })\n },\n getDeviceStatusAggregate: async (input) => this.getDeviceStatusAggregate(input),\n }\n\n this.ctx.logger.info('registered device-manager capability', { meta: { liveRegistry: registry !== null } })\n\n // Fan-out device events to ancestor scopes. Runs only when a live\n // registry is available on this node — forked workers that don't\n // own the registry rely on the hub's propagator (events cross the\n // Moleculer bridge already, propagation is idempotent with the\n // `via` guard so emitting on both sides is safe).\n if (registry) {\n this.propagator = new DeviceEventPropagator({\n eventBus: this.ctx.eventBus,\n getParentOf: (id) => registry.getById(id)?.parentDeviceId ?? null,\n logger: {\n warn: (msg, meta) => this.ctx.logger.warn(msg, meta ?? {}),\n debug: (msg, meta) => this.ctx.logger.debug(msg, meta ?? {}),\n },\n })\n this.propagator.start()\n this.ctx.logger.info('device-event-propagator started')\n }\n\n // `deviceState` cap — generic cross-process surface over the\n // hub mirror. Drivers don't implement this directly; we mount\n // the singleton here so any addon / UI can read any cap's\n // runtime-state slice without the cap having to define its own\n // getStatus / onChanged.\n const deviceStateProvider = {\n getSnapshot: async (input: { deviceId: number }): Promise<Record<string, Record<string, unknown>>> => {\n return this.snapshotForDevice(input.deviceId)\n },\n getCapSlice: async (input: { deviceId: number; capName: string }): Promise<Record<string, unknown> | null> => {\n const perCap = this.stateMirror.get(input.deviceId)\n const slice = perCap?.get(input.capName)\n return slice ? { ...slice } : null\n },\n // Whole-system warm-boot dump. Iterates the mirror once and\n // returns a deeply-cloned `{[deviceId]: {[capName]: slice}}`\n // payload so callers (SystemManager, dashboards) seed their\n // local mirror with one round-trip instead of N per-device\n // calls. Empty inner record for devices with no slices yet.\n getAllSnapshots: async (): Promise<Record<string, Record<string, Record<string, unknown>>>> => {\n const out: Record<string, Record<string, Record<string, unknown>>> = {}\n for (const [deviceId, perCap] of this.stateMirror) {\n const dev: Record<string, Record<string, unknown>> = {}\n for (const [capName, slice] of perCap) dev[capName] = { ...slice }\n out[String(deviceId)] = dev\n }\n return out\n },\n // Canonical cross-layer write — the single entrypoint every\n // caller funnels through. In-process providers reach it via\n // `BaseDevice.runtimeState.setCapState` (which delegates here);\n // system-scope addons (e.g. pipeline runner writing the motion\n // slice on phase transitions) call this cap method directly\n // through `ctx.api.deviceState.setCapSlice.mutate(...)`.\n setCapSlice: async (input: { deviceId: number; capName: string; slice: Record<string, unknown> }): Promise<void> => {\n const { deviceId, capName, slice } = input\n const persisted = await resolvePersistedById(deviceId)\n if (!persisted) throw new Error(`[device-manager] setCapSlice: unknown device id=${deviceId}`)\n // Mirror update + onChanged event are synchronous and ordered;\n // disk write is debounced so frequent writes (motion phase\n // transitions, battery pushes) collapse to one fsync per\n // RUNTIME_STATE_DEBOUNCE_MS window.\n this.applySingleCapUpdate(deviceId, capName, slice)\n this.scheduleRuntimeStateDiskWrite(deviceId, settings)\n },\n }\n\n return [\n { capability: deviceManagerCapability, provider },\n { capability: deviceStateCapability, provider: deviceStateProvider },\n ]\n }\n\n /**\n * Single-cap mirror update — diff against the current mirror,\n * persist the new slice in-memory, emit `DeviceStateChanged` for\n * this cap. No-op on identical writes (both same shape and same\n * values). Called by `setCapSlice` provider.\n */\n private applySingleCapUpdate(\n deviceId: number,\n capName: string,\n slice: Record<string, unknown>,\n ): void {\n let perCap = this.stateMirror.get(deviceId)\n if (!perCap) {\n perCap = new Map()\n this.stateMirror.set(deviceId, perCap)\n }\n const prior = perCap.get(capName)\n if (prior && shallowEqual(prior, slice)) return\n perCap.set(capName, { ...slice })\n this.emitStateChanged(deviceId, capName, slice)\n }\n\n /**\n * Debounced disk writer. Coalesces frequent writes (motion phase\n * transitions, battery pushes) into one `writeDeviceRuntimeState`\n * per `RUNTIME_STATE_DEBOUNCE_MS` window. Reads the per-device\n * blob from the live mirror at flush time so the disk picture is\n * always the latest state — no risk of writing a stale snapshot.\n */\n private scheduleRuntimeStateDiskWrite(\n deviceId: number,\n settings: NonNullable<typeof this.ctx.settings>,\n ): void {\n let slot = this.runtimeStateDebounce.get(deviceId)\n if (!slot) {\n slot = { timer: null, inFlight: null }\n this.runtimeStateDebounce.set(deviceId, slot)\n }\n if (slot.timer) return\n slot.timer = setTimeout(() => {\n slot!.timer = null\n const blob = this.snapshotForDevice(deviceId)\n const write = (async () => {\n try {\n await settings.writeDeviceRuntimeState(deviceId, blob)\n } catch (err: unknown) {\n this.ctx.logger.warn('writeDeviceRuntimeState failed', {\n tags: { deviceId },\n meta: { error: err instanceof Error ? err.message : String(err) },\n })\n } finally {\n slot!.inFlight = null\n }\n })()\n slot!.inFlight = write\n }, DeviceManagerAddon.RUNTIME_STATE_DEBOUNCE_MS)\n }\n\n /**\n * One-shot mirror seed used by `loadRuntimeState` at boot so the\n * hub knows about every persisted slice without waiting for the\n * first `setCapSlice` call. No events emitted — this is\n * initial-state population, not a transition.\n */\n private seedMirror(deviceId: number, blob: Record<string, unknown>): void {\n let perCap = this.stateMirror.get(deviceId)\n if (!perCap) {\n perCap = new Map()\n this.stateMirror.set(deviceId, perCap)\n }\n for (const [capName, raw] of Object.entries(blob)) {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) continue\n perCap.set(capName, { ...raw as Record<string, unknown> })\n }\n }\n\n private snapshotForDevice(deviceId: number): Record<string, Record<string, unknown>> {\n const perCap = this.stateMirror.get(deviceId)\n if (!perCap) return {}\n const out: Record<string, Record<string, unknown>> = {}\n for (const [k, v] of perCap) out[k] = { ...v }\n return out\n }\n\n private emitStateChanged(deviceId: number, capName: string, slice: Record<string, unknown>): void {\n this.ctx.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'device', id: deviceId },\n category: EventCategory.DeviceStateChanged,\n data: { deviceId, capName, slice },\n })\n }\n\n protected async onShutdown(): Promise<void> {\n this.propagator?.stop()\n this.propagator = null\n // Flush any pending debounced runtime-state disk writes so a\n // graceful shutdown doesn't drop the latest mirror state.\n const settings = this.ctx.settings\n const pending: Promise<void>[] = []\n for (const [deviceId, slot] of this.runtimeStateDebounce) {\n if (slot.timer) {\n clearTimeout(slot.timer)\n slot.timer = null\n if (settings) {\n const blob = this.snapshotForDevice(deviceId)\n pending.push(settings.writeDeviceRuntimeState(deviceId, blob).catch((err: unknown) => {\n this.ctx.logger.warn('shutdown writeDeviceRuntimeState failed', {\n tags: { deviceId },\n meta: { error: err instanceof Error ? err.message : String(err) },\n })\n }))\n }\n }\n if (slot.inFlight) pending.push(slot.inFlight)\n }\n await Promise.all(pending)\n this.runtimeStateDebounce.clear()\n }\n}\n\nexport default DeviceManagerAddon\n","import type { IEventBus, EventSource, SystemEvent } from '@camstack/types'\n\n/**\n * Walks the parent chain for every device-sourced event and re-emits a\n * copy on each ancestor scope with `via[]` populated.\n *\n * Design goals:\n * - Transparent: drivers emit once on their own device scope; the\n * framework handles fan-out. Zero provider boilerplate.\n * - Anti-loop: events that already carry `via[]` are skipped (we only\n * propagate ORIGINAL emissions).\n * - Anti-cycle: the parent chain is bounded — if the device registry\n * is corrupt and has a cycle, the walker caps at `MAX_CHAIN_DEPTH`\n * and logs a warning.\n * - Lazy: parent chain is resolved on-demand per event (no cached\n * topology). The lookup is O(depth) which is ≤2 in practice.\n *\n * `via` contract (from SystemEvent.via JSDoc):\n * - `via[0]` is the originating source (the device that produced the\n * event). Subsequent entries walk up the parent chain.\n * - On the re-emission, `source` is the ancestor at that level and\n * `via[0..i]` is the prefix of the chain up to and including the\n * first N ancestors below the current one.\n *\n * Example (grandchild → parent → grandparent):\n * Original: { source: {id: 7}, data: {...}, via: undefined }\n * Re-emit 1: { source: {id: 4}, data: {...}, via: [{id: 7}] }\n * Re-emit 2: { source: {id: 1}, data: {...}, via: [{id: 7}, {id: 4}] }\n *\n * A consumer listening at `source.id === 1` receives re-emit 2 (with\n * `via` showing the chain). A consumer listening at `source.id === 7`\n * with `via === undefined` receives the original only.\n */\n\n/** Bounded walk — paranoia against corrupt device registries with cycles. */\nconst MAX_CHAIN_DEPTH = 16\n\nexport interface DeviceEventPropagatorOptions {\n readonly eventBus: IEventBus\n /**\n * Resolve the numeric parent id of a device, or `null` when the\n * device has no parent (or was deleted). The propagator injects a\n * closure over the hub's `DeviceRegistry` so the lookup is in-\n * process and O(1) per call.\n */\n readonly getParentOf: (deviceId: number) => number | null\n /** Structured logger for anti-cycle + anti-loop diagnostics. */\n readonly logger: {\n warn: (msg: string, meta?: Record<string, unknown>) => void\n debug: (msg: string, meta?: Record<string, unknown>) => void\n }\n}\n\nexport class DeviceEventPropagator {\n private unsubscribe: (() => void) | null = null\n\n constructor(private readonly opts: DeviceEventPropagatorOptions) {}\n\n start(): void {\n if (this.unsubscribe) return\n // Subscribe to ALL events — the filter is applied inline per event\n // so we can short-circuit non-device sources without walking the\n // event bus's glob engine every time.\n const unsub = this.opts.eventBus.subscribe({}, (ev) => this.handle(ev))\n this.unsubscribe = unsub\n }\n\n stop(): void {\n if (!this.unsubscribe) return\n this.unsubscribe()\n this.unsubscribe = null\n }\n\n /** Exposed for tests — lets them inject events without the full bus. */\n handle(ev: SystemEvent): void {\n if (ev.via !== undefined) return // skip propagated\n if (ev.source.type !== 'device') return // skip non-device scopes\n const rawId = ev.source.id\n const deviceId = typeof rawId === 'number' ? rawId : Number(rawId)\n if (!Number.isFinite(deviceId)) return\n\n const chain = this.resolveParentChain(deviceId)\n if (chain.length === 0) return\n\n // Build `via[]` incrementally: for the first ancestor, via = [origin];\n // for the second, via = [origin, firstAncestor]; etc.\n const origin: EventSource = ev.source\n const via: EventSource[] = [origin]\n for (const ancestorId of chain) {\n const reEmission: SystemEvent = {\n ...ev,\n source: { type: 'device', id: ancestorId },\n via: [...via],\n }\n this.opts.eventBus.emit(reEmission)\n via.push({ type: 'device', id: ancestorId })\n }\n }\n\n private resolveParentChain(deviceId: number): readonly number[] {\n const chain: number[] = []\n const seen = new Set<number>([deviceId])\n let current = this.opts.getParentOf(deviceId)\n while (current != null) {\n if (seen.has(current)) {\n this.opts.logger.warn(\n 'device-event-propagator: cycle detected in parent chain — aborting propagation',\n { tags: { deviceId }, meta: { cycleAt: current, chainSoFar: [...chain] } },\n )\n return chain\n }\n seen.add(current)\n chain.push(current)\n if (chain.length >= MAX_CHAIN_DEPTH) {\n this.opts.logger.warn(\n 'device-event-propagator: chain depth limit hit — truncating',\n { tags: { deviceId }, meta: { depth: chain.length, max: MAX_CHAIN_DEPTH } },\n )\n break\n }\n current = this.opts.getParentOf(current)\n }\n return chain\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { IScopedLogger, IEventBus } from '@camstack/types'\n\nexport type ElementState = 'stopped' | 'starting' | 'running' | 'stopping' | 'error' | 'disabled'\n\nexport interface ElementStatus {\n state: ElementState\n error?: string\n startedAt?: number\n stoppedAt?: number\n restartCount: number\n uptime: number\n}\n\nconst VALID_TRANSITIONS: Readonly<Record<ElementState, readonly ElementState[]>> = {\n stopped: ['starting', 'disabled'],\n starting: ['running', 'error', 'stopping'],\n running: ['stopping', 'error'],\n stopping: ['stopped', 'error'],\n error: ['starting', 'stopped', 'disabled'],\n disabled: ['stopped'],\n}\n\nexport class LifecycleStateMachine {\n private _state: ElementState = 'stopped'\n private _error?: string\n private _startedAt?: number\n private _stoppedAt?: number\n private _restartCount = 0\n private _hasStartedOnce = false\n\n constructor(\n private readonly elementId: string,\n private readonly elementType: 'provider' | 'device' | 'addon' | 'process',\n private readonly eventBus: IEventBus,\n private readonly logger: IScopedLogger,\n ) {}\n\n get state(): ElementState {\n return this._state\n }\n\n getStatus(): ElementStatus {\n return {\n state: this._state,\n error: this._error,\n startedAt: this._startedAt,\n stoppedAt: this._stoppedAt,\n restartCount: this._restartCount,\n uptime:\n this._state === 'running' && this._startedAt\n ? Date.now() - this._startedAt\n : 0,\n }\n }\n\n transition(to: ElementState, error?: string): boolean {\n const from = this._state\n\n if (!this.isValidTransition(from, to)) {\n this.logger.warn('Invalid state transition', { meta: { from, to } })\n return false\n }\n\n this._state = to\n this._error = error\n\n if (to === 'running') {\n if (this._hasStartedOnce) {\n this._restartCount++\n }\n this._hasStartedOnce = true\n this._startedAt = Date.now()\n this._stoppedAt = undefined\n }\n\n if (to === 'stopped' || to === 'error' || to === 'disabled') {\n this._stoppedAt = Date.now()\n }\n\n this.logger.info('State transition', { meta: { from, to, error } })\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: this.elementType, id: this.elementId },\n category: `${this.elementType}.state.${to}`,\n data: { from, to, error, elementId: this.elementId },\n })\n\n return true\n }\n\n incrementRestartCount(): void {\n this._restartCount++\n }\n\n private isValidTransition(from: ElementState, to: ElementState): boolean {\n return VALID_TRANSITIONS[from]?.includes(to) ?? false\n }\n}\n","import type { FeatureManifest, FeatureFlag } from '@camstack/types'\n\nexport type { FeatureManifest, FeatureFlag }\n\nexport type FeatureConfigReader = {\n readonly features: FeatureManifest\n}\n\nexport class FeatureManager {\n constructor(private readonly configReader: FeatureConfigReader) {}\n\n isEnabled(flag: FeatureFlag): boolean {\n return this.configReader.features[flag]\n }\n\n getManifest(): FeatureManifest {\n return { ...this.configReader.features }\n }\n}\n","import type {\n EventSource,\n SystemEvent,\n EventFilter,\n IEventBus,\n} from '@camstack/types'\n\nexport type { EventSource, SystemEvent, EventFilter }\n\ninterface Subscriber {\n readonly filter: EventFilter\n readonly callback: (event: SystemEvent) => void\n}\n\nclass EventRingBuffer {\n private readonly buffer: Array<SystemEvent | undefined>\n private head = 0\n private count = 0\n\n constructor(private readonly capacity: number) {\n this.buffer = Array.from<SystemEvent | undefined>({ length: capacity })\n }\n\n push(event: SystemEvent): void {\n this.buffer[this.head] = event\n this.head = (this.head + 1) % this.capacity\n if (this.count < this.capacity) {\n this.count++\n }\n }\n\n getAll(): readonly SystemEvent[] {\n const result: SystemEvent[] = []\n for (let i = 0; i < this.count; i++) {\n const index = (this.head - 1 - i + this.capacity) % this.capacity\n result.push(this.buffer[index]!)\n }\n return result\n }\n\n query(filter?: EventFilter, limit?: number): readonly SystemEvent[] {\n let result = [...this.getAll()]\n\n if (filter) {\n result = result.filter((event) => matchesFilter(event, filter))\n }\n\n if (limit !== undefined && limit > 0) {\n return result.slice(0, limit)\n }\n\n return result\n }\n}\n\nfunction matchesCategory(eventCategory: string, filterCategory: string): boolean {\n if (filterCategory.endsWith('.*')) {\n const prefix = filterCategory.slice(0, -2)\n return eventCategory.startsWith(prefix + '.') || eventCategory === prefix\n }\n return eventCategory === filterCategory\n}\n\nfunction matchesFilter(event: SystemEvent, filter: EventFilter): boolean {\n if (filter.category) {\n const raw = filter.category\n const categories: string[] = Array.isArray(raw) ? raw.map(String) : [String(raw)]\n if (!categories.some((cat) => matchesCategory(event.category, cat))) {\n return false\n }\n }\n\n if (filter.source) {\n if (event.source.type !== filter.source.type || event.source.id !== filter.source.id) {\n return false\n }\n }\n\n if (filter.agentId) {\n const eventNodeId = event.source.nodeId\n // Prefix match: 'hub' matches 'hub', 'hub/pipeline', etc.\n if (!eventNodeId || !eventNodeId.startsWith(filter.agentId)) {\n return false\n }\n }\n\n if (filter.addonId) {\n const eventAddonId = event.source.addonId\n ?? (event.source.type === 'addon' ? String(event.source.id) : undefined)\n if (eventAddonId !== filter.addonId) {\n return false\n }\n }\n\n if (filter.deviceId !== undefined) {\n const eventDeviceId = event.source.deviceId\n ?? (event.source.type === 'device' ? Number(event.source.id) : undefined)\n if (eventDeviceId !== filter.deviceId) {\n return false\n }\n }\n\n if (filter.since && event.timestamp < filter.since) {\n return false\n }\n\n return true\n}\n\nexport class SystemEventBus implements IEventBus {\n private readonly ringBuffer: EventRingBuffer\n private readonly subscribers: Subscriber[] = []\n\n constructor(bufferSize: number = 10000) {\n this.ringBuffer = new EventRingBuffer(bufferSize)\n }\n\n emit(event: SystemEvent): void {\n this.ringBuffer.push(event)\n\n for (const subscriber of this.subscribers) {\n if (matchesFilter(event, subscriber.filter)) {\n queueMicrotask(() => {\n try {\n subscriber.callback(event)\n } catch (err) {\n console.error(`[EventBus] Subscriber error for ${event.category}:`, err)\n }\n })\n }\n }\n }\n\n /**\n * Subscribe to events matching a filter.\n * When called with a typed category filter, the handler receives typed event data.\n */\n subscribe(filter: EventFilter, handler: (event: SystemEvent) => void): () => void {\n const subscriber: Subscriber = { filter, callback: handler }\n this.subscribers.push(subscriber)\n\n return () => {\n const index = this.subscribers.indexOf(subscriber)\n if (index !== -1) {\n this.subscribers.splice(index, 1)\n }\n }\n }\n\n getRecent(filter?: EventFilter, limit?: number): readonly SystemEvent[] {\n return this.ringBuffer.query(filter, limit)\n }\n}\n","import type { LogLevel, LogEntry, LogFilter, LogTags } from '@camstack/types'\n\nexport type { LogLevel, LogEntry, LogFilter }\n\n/**\n * Per-tag filter matcher with semantic-aware comparisons:\n *\n * `addonId` — matches the entry's bare addon id (strips any `@<workerId>`\n * qualifier added by the cap-router for remote providers).\n * So a UI filter for `audio-classifier` matches both the\n * addon's own log lines and bridge management lines whose\n * addonId is logged as `audio-classifier@dev-agent-0/audio-classifier`.\n *\n * `agentId` — matches when ANY of these hold:\n * * the entry was emitted by that agent (`agentId` exact)\n * * the entry's `nodeId` IS that agent (single-node case)\n * * the entry's `nodeId` starts with `<agent>/` (worker\n * inside that agent — e.g. `dev-agent-0/audio-classifier`)\n * Captures all the log emission paths for an addon hosted\n * on the agent regardless of who actually emitted the line.\n *\n * any other key — exact match (legacy semantics).\n *\n * Returns `true` when ALL filter keys match (AND), `false` otherwise.\n * `undefined` filter values are skipped.\n */\nexport function matchesLogTags(\n entryTags: LogTags | undefined,\n filterTags: Partial<LogTags>,\n): boolean {\n if (!entryTags) return false\n for (const [key, value] of Object.entries(filterTags)) {\n if (value === undefined) continue\n const entryValue = entryTags[key as keyof LogTags]\n if (key === 'addonId') {\n const bare = typeof entryValue === 'string' ? entryValue.split('@')[0] : entryValue\n if (bare !== value) return false\n } else if (key === 'agentId') {\n const nodeId = entryTags['nodeId']\n const matchEmitter = entryValue === value\n const matchExactNode = nodeId === value\n const matchWorker = typeof nodeId === 'string' && nodeId.startsWith(`${value}/`)\n if (!matchEmitter && !matchExactNode && !matchWorker) return false\n } else {\n if (entryValue !== value) return false\n }\n }\n return true\n}\n\nexport class LogRingBuffer {\n private readonly buffer: Array<LogEntry | undefined>\n private head = 0\n private count = 0\n\n constructor(private readonly capacity: number = 10000) {\n this.buffer = Array.from<LogEntry | undefined>({ length: capacity })\n }\n\n push(entry: LogEntry): void {\n this.buffer[this.head] = entry\n this.head = (this.head + 1) % this.capacity\n if (this.count < this.capacity) {\n this.count++\n }\n }\n\n getAll(): LogEntry[] {\n const result: LogEntry[] = []\n\n for (let i = 0; i < this.count; i++) {\n const index = (this.head - 1 - i + this.capacity) % this.capacity\n result.push(this.buffer[index]!)\n }\n\n return result\n }\n\n query(filter: LogFilter): LogEntry[] {\n const all = this.getAll()\n let result = all\n\n if (filter.level) {\n result = result.filter((entry) => entry.level === filter.level)\n }\n\n if (filter.since) {\n result = result.filter((entry) => entry.timestamp >= filter.since!)\n }\n\n if (filter.until) {\n result = result.filter((entry) => entry.timestamp <= filter.until!)\n }\n\n if (filter.tags) {\n const filterTags = filter.tags\n result = result.filter((entry) => matchesLogTags(entry.tags, filterTags))\n }\n\n if (filter.limit !== undefined && filter.limit > 0) {\n result = result.slice(0, filter.limit)\n }\n\n return result\n }\n\n /**\n * Drop entries that match `filter`. Returns the number of entries\n * removed. Triggered by the UI's \"Clear logs\" button so the operator\n * can wipe the historical buffer for a specific scope (per-device,\n * per-addon, per-agent) — without it, closing and reopening the\n * panel re-populates the cleared rows from the server's ring buffer.\n *\n * Filter semantics mirror `query` (same level / since / until / tags\n * handling) — whatever you'd see listed by `query(filter)` is what\n * gets removed.\n */\n clear(filter: LogFilter = {}): number {\n if (this.count === 0) return 0\n const survivors: LogEntry[] = []\n for (let i = 0; i < this.count; i++) {\n // Same iteration order as getAll (newest first), but we'll\n // re-insert oldest-first to preserve push semantics.\n const index = (this.head - 1 - i + this.capacity) % this.capacity\n const entry = this.buffer[index]!\n let matches = true\n if (filter.level !== undefined && entry.level !== filter.level) matches = false\n if (matches && filter.since !== undefined && entry.timestamp < filter.since) matches = false\n if (matches && filter.until !== undefined && entry.timestamp > filter.until) matches = false\n if (matches && filter.tags !== undefined && !matchesLogTags(entry.tags, filter.tags)) matches = false\n if (!matches) survivors.push(entry)\n }\n const removed = this.count - survivors.length\n if (removed === 0) return 0\n // Re-seed the buffer in original push order (oldest first → newest last).\n this.buffer.fill(undefined)\n this.head = 0\n this.count = 0\n for (let i = survivors.length - 1; i >= 0; i--) {\n this.push(survivors[i]!)\n }\n return removed\n }\n}\n","import type { IScopedLogger, LogExtras, LogTags } from '@camstack/types'\nimport type { LogEntry, LogLevel } from './log-ring-buffer.js'\n\nexport type { IScopedLogger }\n\nexport class ScopedLogger implements IScopedLogger {\n constructor(\n private readonly scope: string | undefined,\n private readonly writeFn: (entry: LogEntry) => void,\n private readonly tags?: LogTags,\n ) {}\n\n debug(message: string, extras?: LogExtras): void {\n this.write('debug', message, extras)\n }\n\n info(message: string, extras?: LogExtras): void {\n this.write('info', message, extras)\n }\n\n warn(message: string, extras?: LogExtras): void {\n this.write('warn', message, extras)\n }\n\n error(message: string, extras?: LogExtras): void {\n this.write('error', message, extras)\n }\n\n child(childScope: string): IScopedLogger {\n return new ScopedLogger(childScope, this.writeFn, this.tags)\n }\n\n withTags(tags: LogTags): IScopedLogger {\n const merged = this.tags ? { ...this.tags, ...tags } : tags\n return new ScopedLogger(this.scope, this.writeFn, merged)\n }\n\n private write(level: LogLevel, message: string, extras?: LogExtras): void {\n const mergedTags = this.mergeTags(extras?.tags)\n const entry: LogEntry = {\n timestamp: new Date(),\n level,\n message,\n ...(this.scope !== undefined ? { scope: this.scope } : {}),\n ...(extras?.meta !== undefined ? { meta: extras.meta } : {}),\n ...(mergedTags ? { tags: mergedTags } : {}),\n }\n this.writeFn(entry)\n }\n\n private mergeTags(extraTags?: LogTags): LogTags | undefined {\n if (!this.tags && !extraTags) return undefined\n if (!this.tags) return extraTags\n if (!extraTags) return this.tags\n return { ...this.tags, ...extraTags }\n }\n}\n","import { LogRingBuffer, matchesLogTags, type LogEntry, type LogFilter } from './log-ring-buffer.js'\nimport { ScopedLogger, type IScopedLogger } from './scoped-logger.js'\n\nexport interface ILogDestination {\n initialize(): Promise<void>\n shutdown(): Promise<void>\n write(entry: LogEntry): void\n query?(filter: LogFilter): Promise<readonly LogEntry[]>\n}\n\nexport class LogManager {\n private readonly ringBuffer: LogRingBuffer\n private readonly destinations: ILogDestination[] = []\n private readonly subscribers = new Map<string, { filter: Partial<LogFilter>; callback: (entry: LogEntry) => void }>()\n private deviceNameLookup: ((deviceId: number) => string | null) | null = null\n\n constructor(bufferSize: number = 10000) {\n this.ringBuffer = new LogRingBuffer(bufferSize)\n }\n\n /**\n * Register a callback that resolves `deviceId → deviceName`. Called\n * for every emitted entry that carries `tags.deviceId` but no\n * explicit `tags.deviceName` — the LogManager injects the resolved\n * name directly into the entry's tags BEFORE ring-buffer / destination\n * write, so every destination (local console, file, remote forwarder,\n * addon-bundled copies of core) sees the enriched shape regardless of\n * which module instance the destination was built from.\n */\n setDeviceNameLookup(lookup: ((deviceId: number) => string | null) | null): void {\n this.deviceNameLookup = lookup\n }\n\n createLogger(scope?: string): IScopedLogger {\n return new ScopedLogger(scope, (entry: LogEntry) => {\n const enriched = this.enrichDeviceName(entry)\n this.ringBuffer.push(enriched)\n for (const dest of this.destinations) {\n dest.write(enriched)\n }\n // Notify real-time subscribers\n for (const [, sub] of this.subscribers) {\n if (this.matchesFilter(enriched, sub.filter)) {\n try { sub.callback(enriched) } catch { /* subscriber error — ignore */ }\n }\n }\n })\n }\n\n private enrichDeviceName(entry: LogEntry): LogEntry {\n if (!this.deviceNameLookup) return entry\n const tags = entry.tags\n if (!tags) return entry\n const deviceId = (tags as { deviceId?: unknown }).deviceId\n if (typeof deviceId !== 'number' || !Number.isFinite(deviceId)) return entry\n if (typeof (tags as { deviceName?: unknown }).deviceName === 'string') return entry\n const name = this.deviceNameLookup(deviceId)\n if (!name) return entry\n return { ...entry, tags: { ...tags, deviceName: name } }\n }\n\n /** Subscribe to live logs matching a filter. Returns an unsubscribe function. */\n subscribe(filter: Partial<LogFilter>, callback: (entry: LogEntry) => void): () => void {\n const id = Math.random().toString(36).slice(2)\n this.subscribers.set(id, { filter, callback })\n return () => { this.subscribers.delete(id) }\n }\n\n private matchesFilter(entry: LogEntry, filter: Partial<LogFilter>): boolean {\n if (filter.level) {\n const levels: string[] = ['debug', 'info', 'warn', 'error']\n const minIdx = levels.indexOf(filter.level)\n const entryIdx = levels.indexOf(entry.level)\n if (entryIdx < minIdx) return false\n }\n if (filter.tags) {\n if (!matchesLogTags(entry.tags, filter.tags)) return false\n }\n return true\n }\n\n /**\n * Register a log destination.\n *\n * @param opts.replay If true (default), replay every entry currently in\n * the ring buffer to the new destination before live\n * traffic starts. Lets a destination added mid-boot\n * still receive boot-time log entries.\n */\n addDestination(dest: ILogDestination, opts: { replay?: boolean } = {}): void {\n const replay = opts.replay ?? true\n this.destinations.push(dest)\n if (replay) {\n for (const entry of this.ringBuffer.query({})) {\n try { dest.write(entry) } catch { /* destination replay error — ignore */ }\n }\n }\n }\n\n removeDestination(dest: ILogDestination): void {\n const index = this.destinations.indexOf(dest)\n if (index !== -1) {\n this.destinations.splice(index, 1)\n }\n }\n\n query(filter: LogFilter): LogEntry[] {\n return this.ringBuffer.query(filter)\n }\n\n /**\n * Drop ring-buffer entries matching `filter`. Returns the count\n * removed. Backs the UI's \"Clear logs\" admin action so an operator\n * can wipe the historical window for a scope (per-device, per-addon,\n * agent-level) without restarting the server. External destinations\n * (file, forwarder) are NOT touched — only the in-memory ring.\n */\n clear(filter: LogFilter = {}): number {\n return this.ringBuffer.clear(filter)\n }\n}\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { StorageLocationManager, StorageLocationName } from './storage-location-manager.js'\nimport type {\n IStorageProvider as INewStorageProvider,\n ISettingsBackend,\n} from '@camstack/types'\n\n// Legacy interfaces — still used by consumers during migration\nexport interface IStorageProvider {\n initialize(): Promise<void>\n shutdown(): Promise<void>\n getLocation(name: StorageLocationName): IStorageLocation\n export?(locationName: StorageLocationName): Promise<Buffer>\n import?(locationName: StorageLocationName, data: Buffer): Promise<void>\n}\n\nexport interface QueryFilter {\n where?: Record<string, unknown>\n whereIn?: Record<string, unknown[]>\n whereBetween?: Record<string, [unknown, unknown]>\n orderBy?: { field: string; direction: 'asc' | 'desc' }\n limit?: number\n offset?: number\n}\n\nexport interface StorageRecord {\n collection: string\n id: string\n data: Record<string, unknown>\n}\n\nexport interface IStructuredStorage {\n query(collection: string, filter?: QueryFilter): Promise<readonly StorageRecord[]>\n insert(record: StorageRecord): Promise<StorageRecord>\n update(collection: string, id: string, data: Record<string, unknown>): Promise<StorageRecord>\n delete(collection: string, id: string): Promise<void>\n count(collection: string, filter?: QueryFilter): Promise<number>\n}\n\nexport interface IFileStorage {\n readFile(path: string): Promise<Buffer>\n writeFile(path: string, data: Buffer): Promise<void>\n deleteFile(path: string): Promise<void>\n listFiles(prefix?: string): Promise<readonly string[]>\n getFileUrl(path: string): Promise<string>\n exists(path: string): Promise<boolean>\n}\n\nexport interface IStorageLocation {\n structured?: IStructuredStorage\n files?: IFileStorage\n}\n\n/**\n * StorageManager — bridge between legacy code (getLocation/getLocationPath)\n * and the new capability-based storage system.\n *\n * Legacy consumers call getLocation('addon', namespace) to get structured + file storage.\n * This manager builds the response from:\n * - SettingsBackend (for structured queries) — provided by sqlite-settings addon\n * - LocationManager (for file paths) — set during Phase 2 boot\n */\nexport class StorageManager {\n private legacyProvider: IStorageProvider | null = null\n private locationManager: StorageLocationManager | null = null\n private newStorageProvider: INewStorageProvider | null = null\n private settingsBackend: ISettingsBackend | null = null\n\n /** @deprecated Set by legacy capability consumer — use setNewStorageProvider instead */\n setProvider(provider: IStorageProvider | INewStorageProvider): void {\n // Check if it's the new provider (has 'supportedLocations') or legacy (has 'getLocation')\n if ('getLocation' in provider) {\n this.legacyProvider = provider\n } else {\n this.newStorageProvider = provider\n }\n }\n\n setNewStorageProvider(provider: INewStorageProvider): void {\n this.newStorageProvider = provider\n }\n\n setSettingsBackend(backend: ISettingsBackend): void {\n this.settingsBackend = backend\n }\n\n getSettingsBackend(): ISettingsBackend {\n if (!this.settingsBackend) {\n throw new Error('SettingsBackend not initialized — storage addon not yet loaded')\n }\n return this.settingsBackend\n }\n\n getProvider(): IStorageProvider {\n if (this.legacyProvider) return this.legacyProvider\n if (!this.newStorageProvider && !this.settingsBackend && !this.locationManager) {\n throw new Error('No storage provider configured')\n }\n // Return a shim that wraps new providers\n return this.createLegacyShim()\n }\n\n setLocationManager(manager: StorageLocationManager): void {\n this.locationManager = manager\n }\n\n getLocationManager(): StorageLocationManager {\n if (!this.locationManager) {\n throw new Error('StorageLocationManager not initialized')\n }\n return this.locationManager\n }\n\n async initializeLocations(dataPath: string): Promise<void> {\n const { StorageLocationManager } = await import('./storage-location-manager.js')\n const manager = new StorageLocationManager(dataPath)\n await manager.initializeDefaults()\n this.locationManager = manager\n }\n\n getLocationPath(name: StorageLocationName): string {\n return this.getLocationManager().getBackend(name).basePath\n }\n\n /**\n * Get a storage location with optional namespace scoping.\n * Builds IStorageLocation from settingsBackend (structured) + locationManager (files).\n */\n getLocation(name: StorageLocationName | string, namespace?: string): IStorageLocation {\n if (!this.legacyProvider && !this.newStorageProvider && !this.settingsBackend && !this.locationManager) {\n throw new Error('No storage provider configured')\n }\n // Try legacy provider first\n if (this.legacyProvider) {\n try {\n // Legacy alias → new location name mapping. `name` may be any string\n // coming from addon code; the final narrowing cast is the single\n // boundary between the public API (string) and the internal union.\n const LEGACY_MAP = { config: 'data', events: 'data', addon: 'data' } as const satisfies Record<string, StorageLocationName>\n const mapped = name in LEGACY_MAP ? LEGACY_MAP[name as keyof typeof LEGACY_MAP] : (name as StorageLocationName)\n const mappedName: StorageLocationName = mapped\n const location = this.legacyProvider.getLocation(mappedName)\n return namespace ? this.createNamespacedLocation(location, namespace) : location\n } catch {\n // Fall through to new approach\n }\n }\n\n // Build from new providers\n const location: IStorageLocation = {}\n\n // Structured storage from settingsBackend\n if (this.settingsBackend) {\n const backend = this.settingsBackend\n location.structured = {\n async query(collection: string, filter?: QueryFilter) {\n const results = await backend.query({ collection, filter })\n return results.map(r => ({ collection, id: r.id, data: r.data }))\n },\n async insert(record: StorageRecord) {\n const id = record.id || (await import('node:crypto')).randomUUID()\n await backend.insert({ collection: record.collection, record: { id, data: record.data } })\n return { ...record, id }\n },\n async update(collection: string, id: string, data: Record<string, unknown>) {\n await backend.update({ collection, id, data })\n return { collection, id, data }\n },\n async delete(collection: string, id: string) {\n await backend.delete({ collection, key: id })\n },\n async count(collection: string, filter?: QueryFilter) {\n return backend.count({ collection, filter })\n },\n }\n }\n\n // File storage from locationManager\n if (this.locationManager) {\n const LEGACY_MAP = { config: 'data', events: 'data', addon: 'data' } as const satisfies Record<string, StorageLocationName>\n const mappedName: StorageLocationName = name in LEGACY_MAP\n ? LEGACY_MAP[name as keyof typeof LEGACY_MAP]\n : (name as StorageLocationName)\n try {\n const basePath = this.locationManager.getBackend(mappedName).basePath\n location.files = {\n async readFile(p: string) { return fs.promises.readFile(path.join(basePath, p)) },\n async writeFile(p: string, data: Buffer) {\n const full = path.join(basePath, p)\n await fs.promises.mkdir(path.dirname(full), { recursive: true })\n await fs.promises.writeFile(full, data)\n },\n async deleteFile(p: string) { await fs.promises.rm(path.join(basePath, p), { force: true }) },\n async listFiles(prefix?: string) {\n const dir = prefix ? path.join(basePath, prefix) : basePath\n try { return (await fs.promises.readdir(dir)).map(f => prefix ? `${prefix}/${f}` : f) } catch { return [] }\n },\n async getFileUrl(p: string) { return path.join(basePath, p) },\n async exists(p: string) { try { await fs.promises.access(path.join(basePath, p)); return true } catch { return false } },\n }\n } catch {\n // Location not available\n }\n }\n\n return namespace ? this.createNamespacedLocation(location, namespace) : location\n }\n\n private createLegacyShim(): IStorageProvider {\n const self = this\n return {\n async initialize() {},\n async shutdown() {},\n getLocation(name: StorageLocationName) { return self.getLocation(name) },\n }\n }\n\n private createNamespacedLocation(location: IStorageLocation, namespace: string): IStorageLocation {\n const prefix = namespace.endsWith('/') ? namespace : `${namespace}/`\n\n return {\n structured: location.structured ? {\n async query(collection: string, filter?: QueryFilter) {\n return location.structured!.query(`${prefix}${collection}`, filter)\n },\n async insert(record: StorageRecord) {\n return location.structured!.insert({ ...record, collection: `${prefix}${record.collection}` })\n },\n async update(collection: string, id: string, data: Record<string, unknown>) {\n return location.structured!.update(`${prefix}${collection}`, id, data)\n },\n async delete(collection: string, id: string) {\n return location.structured!.delete(`${prefix}${collection}`, id)\n },\n async count(collection: string, filter?: QueryFilter) {\n return location.structured!.count(`${prefix}${collection}`, filter)\n },\n } : undefined,\n\n files: location.files ? {\n async readFile(p: string) { return location.files!.readFile(`${prefix}${p}`) },\n async writeFile(p: string, data: Buffer) { return location.files!.writeFile(`${prefix}${p}`, data) },\n async deleteFile(p: string) { return location.files!.deleteFile(`${prefix}${p}`) },\n async listFiles(filePrefix?: string) { return location.files!.listFiles(`${prefix}${filePrefix ?? ''}`) },\n async getFileUrl(p: string) { return location.files!.getFileUrl(`${prefix}${p}`) },\n async exists(p: string) { return location.files!.exists(`${prefix}${p}`) },\n } : undefined,\n }\n }\n}\n","import type { INotificationOutput, Notification, ICapabilityRegistry } from '@camstack/types'\nimport type { IScopedLogger } from '../logging/scoped-logger.js'\nimport { errMsg } from '@camstack/types'\n\n/**\n * Central notification service that routes notifications to configured outputs.\n * Framework-agnostic — dependencies injected via constructor.\n *\n * Outputs are resolved from the ICapabilityRegistry's 'notification-output'\n * collection on each call (proxy pattern). Falls back to a local map\n * when no registry is provided (backward compat).\n */\nexport class NotificationService {\n private readonly localOutputs = new Map<string, INotificationOutput>()\n private readonly routing = new Map<string, string[]>()\n private readonly rateLimits = new Map<string, number>()\n private readonly lastSent = new Map<string, number>()\n private registry: ICapabilityRegistry | null = null\n\n constructor(private readonly logger: IScopedLogger) {}\n\n /** Set the registry for live output lookup. Called once during boot. */\n setRegistry(registry: ICapabilityRegistry): void {\n this.registry = registry\n }\n\n /** Resolve all outputs — prefers registry, falls back to local map */\n private get outputs(): ReadonlyMap<string, INotificationOutput> {\n if (this.registry) {\n const collection = this.registry.getCollection<INotificationOutput>('notification-output')\n const map = new Map<string, INotificationOutput>()\n for (const output of collection) {\n map.set(output.id, output)\n }\n return map\n }\n return this.localOutputs\n }\n\n /** Register an output in the local fallback map (used when no registry is set). */\n registerLocalOutput(output: INotificationOutput): void {\n this.localOutputs.set(output.id, output)\n this.logger.info('Notification output added', { meta: { name: output.name, outputId: output.id } })\n }\n\n /** Remove an output from the local fallback map. */\n unregisterLocalOutput(id: string): void {\n this.localOutputs.delete(id)\n this.logger.info('Notification output removed', { meta: { outputId: id } })\n }\n\n setRouting(category: string, outputIds: string[]): void {\n this.routing.set(category, [...outputIds])\n }\n\n setRateLimit(category: string, minIntervalMs: number): void {\n this.rateLimits.set(category, minIntervalMs)\n }\n\n async notify(notification: Notification): Promise<void> {\n const { category, deviceId } = notification\n\n // Rate limit check\n const rateLimitKey = deviceId ? `${category}:${deviceId}` : category\n const minInterval = this.rateLimits.get(category) ?? 0\n if (minInterval > 0) {\n const last = this.lastSent.get(rateLimitKey) ?? 0\n if (notification.timestamp - last < minInterval) {\n this.logger.debug('Rate limited', { meta: { rateLimitKey } })\n return\n }\n }\n\n // Determine target outputs\n const targetIds = this.routing.get(category) ?? this.routing.get('*') ?? []\n if (targetIds.length === 0) {\n this.logger.debug('No routing configured for category', { meta: { category } })\n return\n }\n\n const currentOutputs = this.outputs\n\n // Update last-sent timestamp\n this.lastSent.set(rateLimitKey, notification.timestamp)\n\n // Send to all targets in parallel with error isolation\n await Promise.allSettled(\n targetIds\n .map((id) => currentOutputs.get(id))\n .filter((output): output is INotificationOutput => output !== undefined)\n .map(async (output) => {\n try {\n await output.send(notification)\n } catch (err) {\n const msg = errMsg(err)\n this.logger.error('Notification output failed', { meta: { outputId: output.id, error: msg } })\n }\n }),\n )\n\n return undefined\n }\n\n getOutputs(): ReadonlyArray<{ id: string; name: string; icon: string }> {\n return Array.from(this.outputs.values()).map(({ id, name, icon }) => ({ id, name, icon }))\n }\n\n getRouting(): ReadonlyMap<string, string[]> {\n return this.routing\n }\n\n getOutput(id: string): INotificationOutput | undefined {\n return this.outputs.get(id)\n }\n}\n","import type { Toast } from '@camstack/types'\n\nexport type Unsubscribe = () => void\n\ninterface ListenerEntry {\n readonly userId: string\n readonly callback: (toast: Toast) => void\n}\n\n/**\n * Service for broadcasting toast notifications to connected UI clients.\n * Framework-agnostic — integrates with tRPC subscriptions via subscribe().\n */\nexport class ToastService {\n private readonly listeners = new Map<string, ListenerEntry>()\n\n /**\n * Subscribe to toast events for a specific user.\n * Returns an unsubscribe function.\n */\n subscribe(connectionId: string, userId: string, callback: (toast: Toast) => void): Unsubscribe {\n this.listeners.set(connectionId, { userId, callback })\n return () => {\n this.listeners.delete(connectionId)\n }\n }\n\n /**\n * Broadcast a toast to all connected clients.\n */\n broadcast(toast: Toast): void {\n for (const entry of this.listeners.values()) {\n entry.callback(toast)\n }\n }\n\n /**\n * Send a toast to a specific user's connections only.\n */\n sendToUser(userId: string, toast: Toast): void {\n for (const entry of this.listeners.values()) {\n if (entry.userId === userId) {\n entry.callback(toast)\n }\n }\n }\n}\n","import type { IAddonHttpRoute, IAddonRouteProvider } from '@camstack/types'\n\ninterface RouteMatch {\n readonly route: IAddonHttpRoute\n readonly addonId: string\n readonly params: Record<string, string>\n}\n\ninterface RegisteredRoute {\n readonly addonId: string\n readonly route: IAddonHttpRoute\n /** Full path including /addon/{addonId}/ prefix */\n readonly fullPath: string\n}\n\n/**\n * Registry for dynamic HTTP routes registered by addons.\n * Framework-agnostic — the server HTTP layer queries this registry to dispatch requests.\n */\nexport class AddonRouteRegistry {\n private readonly routes = new Map<string, RegisteredRoute[]>()\n\n /**\n * Register all routes from an addon's route provider.\n */\n registerRoutes(addonId: string, provider: IAddonRouteProvider): void {\n const addonRoutes = provider.getRoutes()\n const registered: RegisteredRoute[] = addonRoutes.map((route) => {\n const normalizedPath = route.path.startsWith('/') ? route.path : `/${route.path}`\n return {\n addonId,\n route,\n fullPath: `/addon/${addonId}${normalizedPath}`,\n }\n })\n this.routes.set(addonId, registered)\n }\n\n /**\n * Unregister all routes for an addon.\n */\n unregisterRoutes(addonId: string): void {\n this.routes.delete(addonId)\n }\n\n /**\n * Match an incoming request method + path to a registered route.\n * Supports simple path parameters (e.g., /items/:id).\n */\n matchRoute(method: string, path: string): RouteMatch | null {\n const normalizedMethod = method.toUpperCase()\n\n for (const registeredRoutes of this.routes.values()) {\n for (const entry of registeredRoutes) {\n if (entry.route.method !== normalizedMethod) continue\n\n const params = matchPath(entry.fullPath, path)\n if (params !== null) {\n return {\n route: entry.route,\n addonId: entry.addonId,\n params,\n }\n }\n }\n }\n\n return null\n }\n\n /**\n * List all registered routes across all addons.\n */\n listRoutes(): ReadonlyArray<{ addonId: string; method: string; path: string; access: string; description?: string }> {\n const result: Array<{ addonId: string; method: string; path: string; access: string; description?: string }> = []\n for (const registeredRoutes of this.routes.values()) {\n for (const entry of registeredRoutes) {\n result.push({\n addonId: entry.addonId,\n method: entry.route.method,\n path: entry.fullPath,\n access: entry.route.access,\n description: entry.route.description,\n })\n }\n }\n return result\n }\n}\n\n/**\n * Match a route pattern against an actual path.\n * Supports :param segments (e.g., /addon/:addonId/items/:id).\n * Returns extracted params or null if no match.\n */\nfunction matchPath(pattern: string, path: string): Record<string, string> | null {\n const patternParts = pattern.split('/').filter(Boolean)\n const pathParts = path.split('/').filter(Boolean)\n\n if (patternParts.length !== pathParts.length) {\n return null\n }\n\n const params: Record<string, string> = {}\n\n for (let i = 0; i < patternParts.length; i++) {\n const patternPart = patternParts[i]!\n const pathPart = pathParts[i]!\n\n if (patternPart.startsWith(':')) {\n params[patternPart.slice(1)] = pathPart\n } else if (patternPart !== pathPart) {\n return null\n }\n }\n\n return params\n}\n","import { X509Certificate } from 'node:crypto'\nimport { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { existsSync, mkdirSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport * as os from 'node:os'\n\nconst execFileAsync = promisify(execFile)\n\nexport interface TlsCertPair {\n readonly cert: Buffer\n readonly key: Buffer\n}\n\nexport interface EnsureTlsResult {\n readonly certPath: string\n readonly keyPath: string\n readonly generated: boolean\n}\n\nexport interface CertOptions {\n /** Common Name for the cert (default: 'camstack.local') */\n readonly commonName?: string\n /** Validity in days (default: 825 — max for browsers) */\n readonly validDays?: number\n /** Additional SANs (DNS names or IPs) */\n readonly extraSans?: readonly string[]\n}\n\n/**\n * Ensure a self-signed TLS certificate exists in the given directory.\n * Generates one if missing. Returns paths to cert and key files.\n */\nexport async function ensureTlsCert(\n dataDir: string,\n options?: CertOptions,\n): Promise<EnsureTlsResult> {\n const tlsDir = join(dataDir, 'tls')\n const certPath = join(tlsDir, 'camstack.crt')\n const keyPath = join(tlsDir, 'camstack.key')\n\n // Already exists — reuse\n if (existsSync(certPath) && existsSync(keyPath)) {\n try {\n const certPem = readFileSync(certPath)\n const x509 = new X509Certificate(certPem)\n const validTo = new Date(x509.validTo)\n if (validTo > new Date()) {\n return { certPath, keyPath, generated: false }\n }\n // Expired — regenerate below\n } catch {\n // Corrupted — regenerate below\n }\n }\n\n mkdirSync(tlsDir, { recursive: true })\n\n const cn = options?.commonName ?? 'camstack.local'\n const validDays = options?.validDays ?? 825\n\n // Collect SANs: localhost, 127.0.0.1, all local IPs, hostname\n const sanDns = new Set<string>(['localhost', cn, os.hostname()])\n const sanIps = new Set<string>(['127.0.0.1', '::1'])\n\n // Add all local network IPs\n const interfaces = os.networkInterfaces()\n for (const addrs of Object.values(interfaces)) {\n if (!addrs) continue\n for (const addr of addrs) {\n if (!addr.internal) {\n sanIps.add(addr.address)\n }\n }\n }\n\n // Add extra SANs\n for (const san of options?.extraSans ?? []) {\n if (san.match(/^\\d+\\.\\d+\\.\\d+\\.\\d+$/) || san.includes(':')) {\n sanIps.add(san)\n } else {\n sanDns.add(san)\n }\n }\n\n // Build SAN string for openssl\n const sanParts: string[] = []\n for (const dns of sanDns) {\n sanParts.push(`DNS:${dns}`)\n }\n for (const ip of sanIps) {\n sanParts.push(`IP:${ip}`)\n }\n const sanString = sanParts.join(',')\n\n // Generate self-signed certificate using openssl CLI\n await execFileAsync('openssl', [\n 'req', '-x509',\n '-newkey', 'rsa:2048',\n '-keyout', keyPath,\n '-out', certPath,\n '-days', String(validDays),\n '-nodes',\n '-subj', `/CN=${cn}`,\n '-addext', `subjectAltName=${sanString}`,\n ])\n\n // Set restrictive permissions on the key file\n const { chmod } = await import('node:fs/promises')\n await chmod(keyPath, 0o600)\n\n return { certPath, keyPath, generated: true }\n}\n\n/**\n * Load TLS cert+key from files. Returns Buffers suitable for Node.js TLS options.\n */\nexport function loadTlsCert(certPath: string, keyPath: string): TlsCertPair {\n return {\n cert: readFileSync(certPath),\n key: readFileSync(keyPath),\n }\n}\n","/**\n * Factory for creating tRPC clients for addons.\n *\n * In-process only: `createDirectCaller()` uses tRPC's `createCallerFactory`\n * to call procedures directly (zero network overhead) and wraps the raw\n * caller in a proxy so it matches `CreateTRPCClient<AppRouter>` shape —\n * addons use `context.api.namespace.method.query(input)` identically to\n * the cross-process path.\n *\n * Cross-process calls (forked workers, remote agents) ride the Moleculer\n * broker via `brokerTransportLink` in the kernel — not this factory.\n */\n\nexport interface DirectCallerOptions {\n /** The tRPC router instance (from buildAppRouter) */\n readonly router: unknown\n /** Context for the caller (user identity, etc.) */\n readonly context: { readonly user: { readonly id: string; readonly username: string; readonly role: string } }\n}\n\n/**\n * Wrap a raw tRPC caller (from `createCallerFactory`) in a proxy that\n * exposes each leaf procedure as `{ query, mutate, subscribe }`, matching\n * the shape of `CreateTRPCClient<AppRouter>`.\n *\n * The tricky part: tRPC v11 callers expose nested routers as callable\n * no-op functions (e.g. `caller.greet` is `typeof === 'function'`), so\n * we can't use `typeof` to tell namespace from leaf. Instead, we return\n * a unified proxy that handles BOTH behaviours:\n *\n * - Accessing `.query` / `.mutate` treats the current node as a leaf\n * procedure and invokes `caller(input)` when called.\n * - Accessing `.subscribe` throws (not supported on direct caller).\n * - Accessing any other property descends into `caller[prop]` and\n * returns a nested proxy.\n */\nfunction wrapCallerAsClient<T>(caller: unknown): T {\n return new Proxy(Object.create(null) as Record<string, unknown>, {\n get(_target, prop) {\n if (typeof prop !== 'string') return undefined\n\n if (prop === 'query' || prop === 'mutate') {\n // Leaf-mode: the current `caller` is expected to be a procedure\n // function. The tRPC caller accepts the raw input as its first\n // argument and returns `Promise<output>`.\n if (typeof caller !== 'function') {\n throw new Error(\n `Cannot call .${prop}() — this tRPC node is not a procedure`,\n )\n }\n const fn = caller as (input?: unknown) => Promise<unknown>\n return (input?: unknown) => fn(input)\n }\n\n if (prop === 'subscribe') {\n return () => {\n throw new Error(\n `subscribe() is not supported on direct caller — use the WSS client for subscriptions`,\n )\n }\n }\n\n // Namespace descent — keep walking the caller tree.\n const child = (caller as Record<string, unknown> | null | undefined)?.[prop]\n if (child === undefined || child === null) return undefined\n return wrapCallerAsClient<unknown>(child)\n },\n }) as T\n}\n\nexport class AddonApiFactory {\n /**\n * Create a direct caller -- calls tRPC procedures directly in-process.\n * Zero network overhead. Used for in-process addons and dev mode.\n *\n * Returns `AddonApi` — the same tRPC client surface that broker-routed\n * callers get. Callers treat it uniformly as `context.api` regardless\n * of the underlying transport.\n */\n async createDirectCaller(options: DirectCallerOptions): Promise<import('@camstack/types').AddonApi> {\n const { initTRPC } = await import('@trpc/server')\n const t = initTRPC.create()\n type RouterLike = Parameters<typeof t.createCallerFactory>[0]\n const callerFactory = t.createCallerFactory(options.router as RouterLike)\n type CallerContext = Parameters<ReturnType<typeof t.createCallerFactory>>[0]\n const caller = callerFactory(options.context as CallerContext)\n return wrapCallerAsClient<import('@camstack/types').AddonApi>(caller)\n }\n}\n","import type {\n Integration, PersistedDevice,\n CreateIntegrationInput, CreateDeviceInput,\n IIntegrationRegistry,\n ISettingsBackend,\n TableSchema,\n} from '@camstack/types'\nimport { parseJsonObject } from '@camstack/types'\n\nfunction serializeSetting(value: unknown): { value: string; valueType: string } {\n if (typeof value === 'number') return { value: String(value), valueType: 'number' }\n if (typeof value === 'boolean') return { value: String(value), valueType: 'boolean' }\n if (typeof value === 'string') return { value, valueType: 'string' }\n return { value: JSON.stringify(value), valueType: 'json' }\n}\n\nfunction deserializeSetting(value: string, valueType: string): unknown {\n switch (valueType) {\n case 'number': return Number(value)\n case 'boolean': return value === 'true'\n case 'json': try { return JSON.parse(value) } catch { return value }\n default: return value\n }\n}\n\nlet integrationCounter = 0\nlet deviceCounter = 0\n\nfunction nextIntegrationId(): string {\n return `int_${String(++integrationCounter).padStart(4, '0')}`\n}\n\nfunction nextDeviceId(): string {\n return `dev_${String(++deviceCounter).padStart(4, '0')}`\n}\n\nconst INTEGRATIONS_SCHEMA: TableSchema = {\n columns: [\n { name: 'id', type: 'TEXT', primaryKey: true },\n { name: 'addon_id', type: 'TEXT', notNull: true },\n { name: 'name', type: 'TEXT', notNull: true },\n { name: 'enabled', type: 'INTEGER', notNull: true, defaultValue: 1 },\n { name: 'info', type: 'TEXT', notNull: true, defaultValue: '{}' },\n { name: 'created_at', type: 'INTEGER', notNull: true },\n { name: 'updated_at', type: 'INTEGER', notNull: true },\n ],\n indexes: [\n { name: 'idx_integrations_addon', columns: ['addon_id'] },\n ],\n}\n\nconst INTEGRATION_SETTINGS_SCHEMA: TableSchema = {\n columns: [\n { name: 'integration_id', type: 'TEXT', notNull: true },\n { name: 'key', type: 'TEXT', notNull: true },\n { name: 'value', type: 'TEXT', notNull: true },\n { name: 'value_type', type: 'TEXT', notNull: true, defaultValue: 'string' },\n ],\n}\n\nconst DEVICES_SCHEMA: TableSchema = {\n columns: [\n { name: 'id', type: 'TEXT', primaryKey: true },\n { name: 'integration_id', type: 'TEXT', notNull: true },\n { name: 'stable_id', type: 'TEXT', notNull: true, unique: true },\n { name: 'type', type: 'TEXT', notNull: true, defaultValue: 'camera' },\n { name: 'name', type: 'TEXT', notNull: true },\n { name: 'enabled', type: 'INTEGER', notNull: true, defaultValue: 1 },\n { name: 'info', type: 'TEXT', notNull: true, defaultValue: '{}' },\n { name: 'created_at', type: 'INTEGER', notNull: true },\n { name: 'updated_at', type: 'INTEGER', notNull: true },\n ],\n indexes: [\n { name: 'idx_devices_integration', columns: ['integration_id'] },\n { name: 'idx_devices_stable', columns: ['stable_id'], unique: true },\n { name: 'idx_devices_type', columns: ['type'] },\n ],\n}\n\nconst DEVICE_SETTINGS_SCHEMA: TableSchema = {\n columns: [\n { name: 'device_id', type: 'TEXT', notNull: true },\n { name: 'key', type: 'TEXT', notNull: true },\n { name: 'value', type: 'TEXT', notNull: true },\n { name: 'value_type', type: 'TEXT', notNull: true, defaultValue: 'string' },\n ],\n}\n\nexport class IntegrationRegistry implements IIntegrationRegistry {\n private readonly backend: ISettingsBackend\n\n constructor(backend: ISettingsBackend) {\n this.backend = backend\n }\n\n async initialize(): Promise<void> {\n await this.backend.ensureTable?.('integrations', INTEGRATIONS_SCHEMA)\n await this.backend.ensureTable?.('integration_settings', INTEGRATION_SETTINGS_SCHEMA)\n await this.backend.ensureTable?.('devices', DEVICES_SCHEMA)\n await this.backend.ensureTable?.('device_settings_kv', DEVICE_SETTINGS_SCHEMA)\n\n // Resume counters from max existing IDs\n const ints = await this.backend.tableQuery?.('integrations', { orderBy: { field: 'id', direction: 'desc' }, limit: 1 }) ?? []\n if (ints[0]) {\n const num = parseInt(String(ints[0]['id']).replace('int_', ''), 10)\n if (!isNaN(num)) integrationCounter = num\n }\n const devs = await this.backend.tableQuery?.('devices', { orderBy: { field: 'id', direction: 'desc' }, limit: 1 }) ?? []\n if (devs[0]) {\n const num = parseInt(String(devs[0]['id']).replace('dev_', ''), 10)\n if (!isNaN(num)) deviceCounter = num\n }\n }\n\n // --- Integrations ---\n\n async createIntegration(input: CreateIntegrationInput): Promise<Integration> {\n const id = nextIntegrationId()\n const now = Math.floor(Date.now() / 1000)\n\n await this.backend.tableInsert?.('integrations', {\n id,\n addon_id: input.addonId,\n name: input.name,\n enabled: input.enabled !== false ? 1 : 0,\n info: JSON.stringify(input.info ?? {}),\n created_at: now,\n updated_at: now,\n })\n\n if (input.settings) {\n await this.setIntegrationSettings(id, input.settings)\n }\n\n return {\n id,\n addonId: input.addonId,\n name: input.name,\n enabled: input.enabled !== false,\n info: input.info ?? {},\n createdAt: now,\n updatedAt: now,\n }\n }\n\n async getIntegration(id: string): Promise<Integration | null> {\n const row = await this.backend.tableGet?.('integrations', { id })\n return row ? this.mapIntegration(row) : null\n }\n\n async getIntegrationByAddonId(addonId: string): Promise<Integration | null> {\n const row = await this.backend.tableGet?.('integrations', { addon_id: addonId })\n return row ? this.mapIntegration(row) : null\n }\n\n async listIntegrations(): Promise<readonly Integration[]> {\n const rows = await this.backend.tableQuery?.('integrations', { orderBy: { field: 'created_at', direction: 'asc' } }) ?? []\n return rows.map(r => this.mapIntegration(r))\n }\n\n async updateIntegration(id: string, updates: Partial<Pick<Integration, 'name' | 'enabled' | 'info'>>): Promise<Integration | null> {\n const updateRow: Record<string, unknown> = { updated_at: Math.floor(Date.now() / 1000) }\n if (updates.name !== undefined) updateRow['name'] = updates.name\n if (updates.enabled !== undefined) updateRow['enabled'] = updates.enabled ? 1 : 0\n if (updates.info !== undefined) updateRow['info'] = JSON.stringify(updates.info)\n\n await this.backend.tableUpdate?.('integrations', { id }, updateRow)\n return this.getIntegration(id)\n }\n\n async deleteIntegration(id: string): Promise<boolean> {\n const devices = await this.listDevices(id)\n for (const d of devices) {\n await this.backend.tableDelete?.('device_settings_kv', { device_id: d.id })\n }\n await this.backend.tableDelete?.('devices', { integration_id: id })\n await this.backend.tableDelete?.('integration_settings', { integration_id: id })\n await this.backend.tableDelete?.('integrations', { id })\n return true\n }\n\n // --- Integration Settings ---\n\n async getIntegrationSettings(integrationId: string): Promise<Record<string, unknown>> {\n const result: Record<string, unknown> = {}\n const rows = await this.backend.tableQuery?.('integration_settings', { where: { integration_id: integrationId } }) ?? []\n for (const row of rows) {\n result[String(row['key'])] = deserializeSetting(String(row['value']), String(row['value_type']))\n }\n return result\n }\n\n async setIntegrationSetting(integrationId: string, key: string, value: unknown): Promise<void> {\n const s = serializeSetting(value)\n await this.backend.tableDelete?.('integration_settings', { integration_id: integrationId, key })\n await this.backend.tableInsert?.('integration_settings', {\n integration_id: integrationId,\n key,\n value: s.value,\n value_type: s.valueType,\n })\n }\n\n async setIntegrationSettings(integrationId: string, settings: Record<string, unknown>): Promise<void> {\n for (const [key, value] of Object.entries(settings)) {\n await this.setIntegrationSetting(integrationId, key, value)\n }\n }\n\n // --- Devices ---\n\n async createDevice(input: CreateDeviceInput): Promise<PersistedDevice> {\n const id = nextDeviceId()\n const now = Math.floor(Date.now() / 1000)\n\n await this.backend.tableInsert?.('devices', {\n id,\n integration_id: input.integrationId,\n stable_id: input.stableId,\n type: input.type,\n name: input.name,\n enabled: input.enabled !== false ? 1 : 0,\n info: JSON.stringify(input.info ?? {}),\n created_at: now,\n updated_at: now,\n })\n\n if (input.settings) {\n await this.setDeviceSettings(id, input.settings)\n }\n\n return {\n id,\n integrationId: input.integrationId,\n stableId: input.stableId,\n type: input.type,\n name: input.name,\n enabled: input.enabled !== false,\n info: input.info ?? {},\n createdAt: now,\n updatedAt: now,\n }\n }\n\n async getDevice(id: string): Promise<PersistedDevice | null> {\n const row = await this.backend.tableGet?.('devices', { id })\n return row ? this.mapDevice(row) : null\n }\n\n async getDeviceByStableId(stableId: string): Promise<PersistedDevice | null> {\n const row = await this.backend.tableGet?.('devices', { stable_id: stableId })\n return row ? this.mapDevice(row) : null\n }\n\n async listDevices(integrationId?: string): Promise<readonly PersistedDevice[]> {\n const options = integrationId\n ? { where: { integration_id: integrationId }, orderBy: { field: 'created_at' as const, direction: 'asc' as const } }\n : { orderBy: { field: 'created_at' as const, direction: 'asc' as const } }\n const rows = await this.backend.tableQuery?.('devices', options) ?? []\n return rows.map(r => this.mapDevice(r))\n }\n\n async listCameras(): Promise<readonly PersistedDevice[]> {\n const rows = await this.backend.tableQuery?.('devices', { where: { type: 'camera' }, orderBy: { field: 'created_at', direction: 'asc' } }) ?? []\n return rows.map(r => this.mapDevice(r))\n }\n\n async updateDevice(id: string, updates: Partial<Pick<PersistedDevice, 'name' | 'enabled' | 'info'>>): Promise<PersistedDevice | null> {\n const updateRow: Record<string, unknown> = { updated_at: Math.floor(Date.now() / 1000) }\n if (updates.name !== undefined) updateRow['name'] = updates.name\n if (updates.enabled !== undefined) updateRow['enabled'] = updates.enabled ? 1 : 0\n if (updates.info !== undefined) updateRow['info'] = JSON.stringify(updates.info)\n\n await this.backend.tableUpdate?.('devices', { id }, updateRow)\n return this.getDevice(id)\n }\n\n async deleteDevice(id: string): Promise<boolean> {\n await this.backend.tableDelete?.('device_settings_kv', { device_id: id })\n await this.backend.tableDelete?.('devices', { id })\n return true\n }\n\n // --- Device Settings ---\n\n async getDeviceSettings(deviceId: string): Promise<Record<string, unknown>> {\n const result: Record<string, unknown> = {}\n const rows = await this.backend.tableQuery?.('device_settings_kv', { where: { device_id: deviceId } }) ?? []\n for (const row of rows) {\n result[String(row['key'])] = deserializeSetting(String(row['value']), String(row['value_type']))\n }\n return result\n }\n\n async setDeviceSetting(deviceId: string, key: string, value: unknown): Promise<void> {\n const s = serializeSetting(value)\n await this.backend.tableDelete?.('device_settings_kv', { device_id: deviceId, key })\n await this.backend.tableInsert?.('device_settings_kv', {\n device_id: deviceId,\n key,\n value: s.value,\n value_type: s.valueType,\n })\n }\n\n async setDeviceSettings(deviceId: string, settings: Record<string, unknown>): Promise<void> {\n for (const [key, value] of Object.entries(settings)) {\n await this.setDeviceSetting(deviceId, key, value)\n }\n }\n\n // --- Mappers ---\n\n private mapIntegration(row: Record<string, unknown>): Integration {\n return {\n id: String(row['id']),\n addonId: String(row['addon_id']),\n name: String(row['name']),\n enabled: row['enabled'] === 1,\n info: typeof row['info'] === 'string' ? (parseJsonObject(row['info']) ?? {}) : {},\n createdAt: Number(row['created_at']),\n updatedAt: Number(row['updated_at']),\n }\n }\n\n private mapDevice(row: Record<string, unknown>): PersistedDevice {\n return {\n id: String(row['id']),\n integrationId: String(row['integration_id']),\n stableId: String(row['stable_id']),\n type: String(row['type']),\n name: String(row['name']),\n enabled: row['enabled'] === 1,\n info: typeof row['info'] === 'string' ? (parseJsonObject(row['info']) ?? {}) : {},\n createdAt: Number(row['created_at']),\n updatedAt: Number(row['updated_at']),\n }\n }\n}\n"],"mappings":"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","names":["resolve","import_node_child_process","import_node_path","path","import_node","resolve","hash","format","fs","path","format","fs","path","import_node_crypto","promises","import_node","import_types","import_node_crypto","import_types","fs","Database","import_types","fs","import_better_sqlite3","import_types","Database","import_types","path","DailyRotateFile","resolve","import_types","import_types","import_node_crypto","import_types","path","import_types","import_types","import_node_child_process","import_node_util","fs","import_node_child_process","getPidStats","cpus","resolve","util","execFileAsync","stats","import_types","import_types","import_types","crypto","hash","crypto","import_types","crypto","import_types","hash","crypto","import_types","USERS_COLLECTION","API_KEYS_COLLECTION","path","import_node_crypto","import_types","import_types","resolve","registry","key","map","metadata","sources","settings","import_node_crypto","fs","path","StorageLocationManager","location","import_types","path","import_node_crypto","import_node_child_process","import_node_util","import_node_fs","import_node_path","os","execFileAsync","import_types"]}