@camstack/server 0.1.3

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 (133) hide show
  1. package/.env.example +17 -0
  2. package/package.json +55 -0
  3. package/src/__tests__/addon-install-e2e.test.ts +75 -0
  4. package/src/__tests__/addon-pages-e2e.test.ts +178 -0
  5. package/src/__tests__/addon-route-session.test.ts +17 -0
  6. package/src/__tests__/addon-settings-router.spec.ts +62 -0
  7. package/src/__tests__/addon-upload.spec.ts +355 -0
  8. package/src/__tests__/agent-registry.spec.ts +162 -0
  9. package/src/__tests__/agent-status-page.spec.ts +84 -0
  10. package/src/__tests__/auth-session-cookie.test.ts +21 -0
  11. package/src/__tests__/cap-providers/cap-usage-graph.spec.ts +23 -0
  12. package/src/__tests__/cap-providers/compute-topology-categories.spec.ts +64 -0
  13. package/src/__tests__/cap-routers/_meta.spec.ts +200 -0
  14. package/src/__tests__/cap-routers/addon-settings.router.spec.ts +106 -0
  15. package/src/__tests__/cap-routers/device-manager-aggregate.router.spec.ts +142 -0
  16. package/src/__tests__/cap-routers/harness.ts +159 -0
  17. package/src/__tests__/cap-routers/metrics-provider.router.spec.ts +119 -0
  18. package/src/__tests__/cap-routers/null-provider-guard.spec.ts +66 -0
  19. package/src/__tests__/cap-routers/pipeline-executor.router.spec.ts +135 -0
  20. package/src/__tests__/cap-routers/settings-store.router.spec.ts +247 -0
  21. package/src/__tests__/capability-e2e.test.ts +386 -0
  22. package/src/__tests__/cli-e2e.test.ts +129 -0
  23. package/src/__tests__/core-cap-bridge.spec.ts +89 -0
  24. package/src/__tests__/embedded-deps-e2e.test.ts +109 -0
  25. package/src/__tests__/event-bus-proxy-router.spec.ts +72 -0
  26. package/src/__tests__/fixtures/mock-analysis-addon-a.ts +37 -0
  27. package/src/__tests__/fixtures/mock-analysis-addon-b.ts +37 -0
  28. package/src/__tests__/fixtures/mock-log-addon.ts +37 -0
  29. package/src/__tests__/fixtures/mock-storage-addon.ts +40 -0
  30. package/src/__tests__/framework-allowlist.spec.ts +95 -0
  31. package/src/__tests__/https-e2e.test.ts +118 -0
  32. package/src/__tests__/lifecycle-e2e.test.ts +140 -0
  33. package/src/__tests__/live-events-subscription.spec.ts +150 -0
  34. package/src/__tests__/moleculer-register-node-idempotency.spec.ts +229 -0
  35. package/src/__tests__/oauth2-account-linking.spec.ts +736 -0
  36. package/src/__tests__/post-boot-restart.spec.ts +161 -0
  37. package/src/__tests__/singleton-contention.test.ts +487 -0
  38. package/src/__tests__/streaming-diagnostic.test.ts +512 -0
  39. package/src/__tests__/streaming-scale.test.ts +280 -0
  40. package/src/agent-status-page.ts +121 -0
  41. package/src/api/__tests__/addons-custom.spec.ts +134 -0
  42. package/src/api/__tests__/capabilities.router.test.ts +47 -0
  43. package/src/api/addon-upload.ts +472 -0
  44. package/src/api/addons-custom.router.ts +100 -0
  45. package/src/api/auth-whoami.ts +99 -0
  46. package/src/api/bridge-addons.router.ts +120 -0
  47. package/src/api/capabilities.router.ts +226 -0
  48. package/src/api/core/__tests__/auth-router-totp.spec.ts +256 -0
  49. package/src/api/core/addon-settings.router.ts +124 -0
  50. package/src/api/core/agents.router.ts +87 -0
  51. package/src/api/core/auth.router.ts +303 -0
  52. package/src/api/core/cap-providers.ts +993 -0
  53. package/src/api/core/capabilities.router.ts +119 -0
  54. package/src/api/core/collection-preference.ts +40 -0
  55. package/src/api/core/event-bus-proxy.router.ts +45 -0
  56. package/src/api/core/hwaccel.router.ts +81 -0
  57. package/src/api/core/live-events.router.ts +60 -0
  58. package/src/api/core/logs.router.ts +162 -0
  59. package/src/api/core/notifications.router.ts +65 -0
  60. package/src/api/core/repl.router.ts +41 -0
  61. package/src/api/core/settings-backend.router.ts +142 -0
  62. package/src/api/core/stream-probe.router.ts +57 -0
  63. package/src/api/core/system-events.router.ts +116 -0
  64. package/src/api/health/health.routes.ts +123 -0
  65. package/src/api/oauth2/__tests__/oauth2-routes.spec.ts +52 -0
  66. package/src/api/oauth2/consent-page.ts +42 -0
  67. package/src/api/oauth2/oauth2-routes.ts +248 -0
  68. package/src/api/trpc/__tests__/scope-access-device.spec.ts +223 -0
  69. package/src/api/trpc/__tests__/scope-access.spec.ts +107 -0
  70. package/src/api/trpc/cap-mount-helpers.ts +225 -0
  71. package/src/api/trpc/core-cap-bridge.ts +152 -0
  72. package/src/api/trpc/generated-cap-mounts.ts +707 -0
  73. package/src/api/trpc/generated-cap-routers.ts +6340 -0
  74. package/src/api/trpc/scope-access.ts +110 -0
  75. package/src/api/trpc/trpc.context.ts +255 -0
  76. package/src/api/trpc/trpc.middleware.ts +140 -0
  77. package/src/api/trpc/trpc.router.ts +275 -0
  78. package/src/auth/session-cookie.ts +44 -0
  79. package/src/boot/boot-config.ts +278 -0
  80. package/src/boot/post-boot.service.ts +103 -0
  81. package/src/core/addon/__tests__/addon-registry-capability.test.ts +53 -0
  82. package/src/core/addon/addon-package.service.ts +1684 -0
  83. package/src/core/addon/addon-registry.service.ts +2926 -0
  84. package/src/core/addon/addon-search.service.ts +90 -0
  85. package/src/core/addon/addon-settings-provider.ts +276 -0
  86. package/src/core/addon/addon.tokens.ts +2 -0
  87. package/src/core/addon-bridge/addon-bridge.service.ts +125 -0
  88. package/src/core/addon-pages/addon-pages.service.spec.ts +117 -0
  89. package/src/core/addon-pages/addon-pages.service.ts +80 -0
  90. package/src/core/addon-widgets/addon-widgets.service.ts +92 -0
  91. package/src/core/agent/agent-registry.service.ts +507 -0
  92. package/src/core/auth/auth.service.spec.ts +88 -0
  93. package/src/core/auth/auth.service.ts +8 -0
  94. package/src/core/capability/capability.service.ts +57 -0
  95. package/src/core/config/config.schema.ts +3 -0
  96. package/src/core/config/config.service.spec.ts +175 -0
  97. package/src/core/config/config.service.ts +7 -0
  98. package/src/core/events/event-bus.service.spec.ts +212 -0
  99. package/src/core/events/event-bus.service.ts +85 -0
  100. package/src/core/feature/feature.service.spec.ts +96 -0
  101. package/src/core/feature/feature.service.ts +8 -0
  102. package/src/core/lifecycle/lifecycle-state-machine.spec.ts +168 -0
  103. package/src/core/lifecycle/lifecycle-state-machine.ts +3 -0
  104. package/src/core/logging/log-ring-buffer.ts +3 -0
  105. package/src/core/logging/logging.service.spec.ts +247 -0
  106. package/src/core/logging/logging.service.ts +129 -0
  107. package/src/core/logging/scoped-logger.ts +3 -0
  108. package/src/core/moleculer/moleculer.service.ts +612 -0
  109. package/src/core/network/network-quality.service.spec.ts +47 -0
  110. package/src/core/network/network-quality.service.ts +5 -0
  111. package/src/core/notification/notification-wrapper.service.ts +36 -0
  112. package/src/core/notification/toast-wrapper.service.ts +31 -0
  113. package/src/core/provider/provider.tokens.ts +1 -0
  114. package/src/core/repl/repl-engine.service.spec.ts +417 -0
  115. package/src/core/repl/repl-engine.service.ts +156 -0
  116. package/src/core/storage/fs-storage-backend.spec.ts +70 -0
  117. package/src/core/storage/fs-storage-backend.ts +3 -0
  118. package/src/core/storage/settings-store.spec.ts +213 -0
  119. package/src/core/storage/settings-store.ts +2 -0
  120. package/src/core/storage/sql-schema.spec.ts +140 -0
  121. package/src/core/storage/sql-schema.ts +3 -0
  122. package/src/core/storage/storage-location-manager.spec.ts +121 -0
  123. package/src/core/storage/storage-location-manager.ts +3 -0
  124. package/src/core/storage/storage.service.spec.ts +73 -0
  125. package/src/core/storage/storage.service.ts +3 -0
  126. package/src/core/streaming/stream-probe.service.ts +212 -0
  127. package/src/core/topology/topology-emitter.service.ts +101 -0
  128. package/src/launcher.ts +309 -0
  129. package/src/main.ts +1049 -0
  130. package/src/manual-boot.ts +322 -0
  131. package/tsconfig.build.json +8 -0
  132. package/tsconfig.json +21 -0
  133. package/vitest.config.ts +26 -0
@@ -0,0 +1,707 @@
1
+ // AUTO-GENERATED by scripts/generate-cap-mounts.ts — DO NOT EDIT
2
+ // Re-run: npx tsx scripts/generate-cap-mounts.ts
3
+ //
4
+ // Mounted: 78 Skipped (legacy): 6
5
+
6
+ /**
7
+ * Single auto-mount entrypoint for every codegen'd cap router.
8
+ * Spread the result into the AppRouter assembly:
9
+ *
10
+ * const router = trpcRouter({
11
+ * ...mountAllCaps(t, services),
12
+ * // … manual overrides + non-cap core routers below
13
+ * })
14
+ *
15
+ * Override-by-spread: a manual `<capName>: createCapRouter_X(...)`
16
+ * entry placed AFTER the spread overrides the auto-mount, which is
17
+ * how service-backed caps (`system`, `nodes`, `integrations`,
18
+ * `addons`, `network-quality`, `toast`) get their non-registry
19
+ * providers wired without dropping out of the auto-mount inventory.
20
+ *
21
+ * Skipped caps (provider has non-canonical legacy shape — task #195):
22
+ * - addon-routes — legacy provider shape (task #195)
23
+ * - auth-provider — legacy provider shape (task #195)
24
+ * - log-destination — legacy provider shape (task #195)
25
+ * - restreamer — legacy provider shape (task #195)
26
+ * - streaming-engine — legacy provider shape (task #195)
27
+ * - webrtc — legacy provider shape (task #195)
28
+ */
29
+
30
+ import type { CapabilityRegistry } from '@camstack/kernel'
31
+ import type { InferProvider } from '@camstack/types'
32
+ import {
33
+ accessoriesCapability,
34
+ addonPagesCapability,
35
+ addonPagesSourceCapability,
36
+ addonSettingsCapability,
37
+ addonWidgetsCapability,
38
+ addonWidgetsSourceCapability,
39
+ addonsCapability,
40
+ adminUiCapability,
41
+ advancedNotifierCapability,
42
+ alertsCapability,
43
+ audioAnalysisCapability,
44
+ audioAnalyzerCapability,
45
+ audioCodecCapability,
46
+ audioMetricsCapability,
47
+ backupCapability,
48
+ batteryCapability,
49
+ brightnessCapability,
50
+ cameraCredentialsCapability,
51
+ cameraStreamsCapability,
52
+ decoderCapability,
53
+ detectionPipelineCapability,
54
+ deviceDiscoveryCapability,
55
+ deviceExportCapability,
56
+ deviceManagerCapability,
57
+ deviceOpsCapability,
58
+ deviceProviderCapability,
59
+ deviceStateCapability,
60
+ deviceStatusCapability,
61
+ doorbellCapability,
62
+ embeddingEncoderCapability,
63
+ eventsCapability,
64
+ featureProbeCapability,
65
+ integrationsCapability,
66
+ intercomCapability,
67
+ localNetworkCapability,
68
+ meshNetworkCapability,
69
+ metricsProviderCapability,
70
+ motionCapability,
71
+ motionDetectionCapability,
72
+ motionTriggerCapability,
73
+ motionZonesCapability,
74
+ mqttBrokerCapability,
75
+ nativeObjectDetectionCapability,
76
+ networkAccessCapability,
77
+ networkQualityCapability,
78
+ nodesCapability,
79
+ notificationOutputCapability,
80
+ oauthIntegrationCapability,
81
+ osdCapability,
82
+ pipelineAnalyticsCapability,
83
+ pipelineExecutorCapability,
84
+ pipelineOrchestratorCapability,
85
+ pipelineRunnerCapability,
86
+ platformProbeCapability,
87
+ ptzAutotrackCapability,
88
+ ptzCapability,
89
+ rebootCapability,
90
+ recordingCapability,
91
+ recordingEngineCapability,
92
+ settingsStoreCapability,
93
+ smtpProviderCapability,
94
+ snapshotCapability,
95
+ snapshotProviderCapability,
96
+ ssoBridgeCapability,
97
+ storageCapability,
98
+ storageProviderCapability,
99
+ streamBrokerCapability,
100
+ streamParamsCapability,
101
+ switchCapability,
102
+ systemCapability,
103
+ toastCapability,
104
+ turnProviderCapability,
105
+ userManagementCapability,
106
+ userPasskeysCapability,
107
+ webrtcSessionCapability,
108
+ zoneAnalyticsCapability,
109
+ zoneRulesCapability,
110
+ zonesCapability,
111
+ } from '@camstack/types'
112
+ import type { MoleculerService } from '../../core/moleculer/moleculer.service.js'
113
+ import { concatCollection, requireDeviceScoped } from './cap-mount-helpers.js'
114
+ import {
115
+ createCapRouter_accessories,
116
+ createCapRouter_addonPages,
117
+ createCapRouter_addonPagesSource,
118
+ createCapRouter_addonSettings,
119
+ createCapRouter_addonWidgets,
120
+ createCapRouter_addonWidgetsSource,
121
+ createCapRouter_addons,
122
+ createCapRouter_adminUi,
123
+ createCapRouter_advancedNotifier,
124
+ createCapRouter_alerts,
125
+ createCapRouter_audioAnalysis,
126
+ createCapRouter_audioAnalyzer,
127
+ createCapRouter_audioCodec,
128
+ createCapRouter_audioMetrics,
129
+ createCapRouter_backup,
130
+ createCapRouter_battery,
131
+ createCapRouter_brightness,
132
+ createCapRouter_cameraCredentials,
133
+ createCapRouter_cameraStreams,
134
+ createCapRouter_decoder,
135
+ createCapRouter_detectionPipeline,
136
+ createCapRouter_deviceDiscovery,
137
+ createCapRouter_deviceExport,
138
+ createCapRouter_deviceManager,
139
+ createCapRouter_deviceOps,
140
+ createCapRouter_deviceProvider,
141
+ createCapRouter_deviceState,
142
+ createCapRouter_deviceStatus,
143
+ createCapRouter_doorbell,
144
+ createCapRouter_embeddingEncoder,
145
+ createCapRouter_events,
146
+ createCapRouter_featureProbe,
147
+ createCapRouter_integrations,
148
+ createCapRouter_intercom,
149
+ createCapRouter_localNetwork,
150
+ createCapRouter_meshNetwork,
151
+ createCapRouter_metricsProvider,
152
+ createCapRouter_motion,
153
+ createCapRouter_motionDetection,
154
+ createCapRouter_motionTrigger,
155
+ createCapRouter_motionZones,
156
+ createCapRouter_mqttBroker,
157
+ createCapRouter_nativeObjectDetection,
158
+ createCapRouter_networkAccess,
159
+ createCapRouter_networkQuality,
160
+ createCapRouter_nodes,
161
+ createCapRouter_notificationOutput,
162
+ createCapRouter_oauthIntegration,
163
+ createCapRouter_osd,
164
+ createCapRouter_pipelineAnalytics,
165
+ createCapRouter_pipelineExecutor,
166
+ createCapRouter_pipelineOrchestrator,
167
+ createCapRouter_pipelineRunner,
168
+ createCapRouter_platformProbe,
169
+ createCapRouter_ptz,
170
+ createCapRouter_ptzAutotrack,
171
+ createCapRouter_reboot,
172
+ createCapRouter_recording,
173
+ createCapRouter_recordingEngine,
174
+ createCapRouter_settingsStore,
175
+ createCapRouter_smtpProvider,
176
+ createCapRouter_snapshot,
177
+ createCapRouter_snapshotProvider,
178
+ createCapRouter_ssoBridge,
179
+ createCapRouter_storage,
180
+ createCapRouter_storageProvider,
181
+ createCapRouter_streamBroker,
182
+ createCapRouter_streamParams,
183
+ createCapRouter_switch,
184
+ createCapRouter_system,
185
+ createCapRouter_toast,
186
+ createCapRouter_turnProvider,
187
+ createCapRouter_userManagement,
188
+ createCapRouter_userPasskeys,
189
+ createCapRouter_webrtcSession,
190
+ createCapRouter_zoneAnalytics,
191
+ createCapRouter_zoneRules,
192
+ createCapRouter_zones,
193
+ } from './generated-cap-routers.js'
194
+
195
+ /**
196
+ * Names of caps whose mount entry is OMITTED here because their
197
+ * provider implementation does not match the canonical
198
+ * `InferProvider<typeof xCap>` contract. Exported so the drift guard
199
+ * in `scripts/codegen.ts` can verify the union of {mounted, skipped}
200
+ * covers every `createCapRouter_X` in `generated-cap-routers.ts`.
201
+ */
202
+ export const LEGACY_SHAPE_SKIP: ReadonlySet<string> = new Set<string>([
203
+ 'addonRoutes',
204
+ 'authProvider',
205
+ 'logDestination',
206
+ 'restreamer',
207
+ 'streamingEngine',
208
+ 'webrtc',
209
+ ])
210
+
211
+ export interface MountAllCapsServices {
212
+ readonly capabilityRegistry: CapabilityRegistry | null
213
+ readonly moleculer: MoleculerService
214
+ }
215
+
216
+ /**
217
+ * Build the auto-mount map. `services` carries the registry handle
218
+ * + Moleculer service so the per-cap remote-proxy factory can route
219
+ * cross-process calls when the incoming request carries `nodeId`.
220
+ */
221
+ export function mountAllCaps(services: MountAllCapsServices) {
222
+ const reg = services.capabilityRegistry
223
+ // Cross-process cap routing: when a request carries a non-'hub'
224
+ // `nodeId` (DeviceProxy injects `entry.providerNodeId` for native
225
+ // device caps on forked workers) the cap-router calls this factory
226
+ // to materialise a Moleculer-bridged proxy. The factory return
227
+ // type is parametric — the runtime Proxy is structurally
228
+ // compatible with every `InferProvider<typeof cap>` shape so a
229
+ // single generic helper covers every mount.
230
+ const remoteCapProxy = <T>(capName: string, nodeId: string): T | null =>
231
+ services.moleculer.createCapabilityProxy(capName, nodeId) as unknown as T | null
232
+ return {
233
+ accessories: createCapRouter_accessories(
234
+ (_ctx) => requireDeviceScoped(reg, 'accessories') as InferProvider<typeof accessoriesCapability> | null,
235
+ remoteCapProxy,
236
+ ),
237
+ addonPages: createCapRouter_addonPages(
238
+ (_ctx) => reg?.getSingleton<InferProvider<typeof addonPagesCapability>>('addon-pages') ?? null,
239
+ remoteCapProxy,
240
+ ),
241
+ addonPagesSource: createCapRouter_addonPagesSource(
242
+ (_ctx, addonId) => {
243
+ if (!reg) return null
244
+ if (addonId !== undefined) {
245
+ return reg.getProviderByAddonId<InferProvider<typeof addonPagesSourceCapability>>('addon-pages-source', addonId)
246
+ }
247
+ const entries = reg.getCollectionEntries<InferProvider<typeof addonPagesSourceCapability>>('addon-pages-source')
248
+ if (entries.length === 0) return null
249
+ const providers = entries.map(([, p]) => p)
250
+ const first = providers[0]!
251
+ return {
252
+ ...first,
253
+ listPages: concatCollection(providers, 'listPages') as InferProvider<typeof addonPagesSourceCapability>['listPages'],
254
+ }
255
+ },
256
+ remoteCapProxy,
257
+ ),
258
+ addonSettings: createCapRouter_addonSettings(
259
+ (_ctx) => reg?.getSingleton<InferProvider<typeof addonSettingsCapability>>('addon-settings') ?? null,
260
+ remoteCapProxy,
261
+ ),
262
+ addonWidgets: createCapRouter_addonWidgets(
263
+ (_ctx) => reg?.getSingleton<InferProvider<typeof addonWidgetsCapability>>('addon-widgets') ?? null,
264
+ remoteCapProxy,
265
+ ),
266
+ addonWidgetsSource: createCapRouter_addonWidgetsSource(
267
+ (_ctx, addonId) => {
268
+ if (!reg) return null
269
+ if (addonId !== undefined) {
270
+ return reg.getProviderByAddonId<InferProvider<typeof addonWidgetsSourceCapability>>('addon-widgets-source', addonId)
271
+ }
272
+ const entries = reg.getCollectionEntries<InferProvider<typeof addonWidgetsSourceCapability>>('addon-widgets-source')
273
+ if (entries.length === 0) return null
274
+ const providers = entries.map(([, p]) => p)
275
+ const first = providers[0]!
276
+ return {
277
+ ...first,
278
+ listWidgets: concatCollection(providers, 'listWidgets') as InferProvider<typeof addonWidgetsSourceCapability>['listWidgets'],
279
+ }
280
+ },
281
+ remoteCapProxy,
282
+ ),
283
+ addons: createCapRouter_addons(
284
+ (_ctx) => reg?.getSingleton<InferProvider<typeof addonsCapability>>('addons') ?? null,
285
+ remoteCapProxy,
286
+ ),
287
+ adminUi: createCapRouter_adminUi(
288
+ (_ctx) => reg?.getSingleton<InferProvider<typeof adminUiCapability>>('admin-ui') ?? null,
289
+ remoteCapProxy,
290
+ ),
291
+ advancedNotifier: createCapRouter_advancedNotifier(
292
+ (_ctx) => reg?.getSingleton<InferProvider<typeof advancedNotifierCapability>>('advanced-notifier') ?? null,
293
+ remoteCapProxy,
294
+ ),
295
+ alerts: createCapRouter_alerts(
296
+ (_ctx) => reg?.getSingleton<InferProvider<typeof alertsCapability>>('alerts') ?? null,
297
+ remoteCapProxy,
298
+ ),
299
+ audioAnalysis: createCapRouter_audioAnalysis(
300
+ (_ctx) => reg?.getSingleton<InferProvider<typeof audioAnalysisCapability>>('audio-analysis') ?? null,
301
+ remoteCapProxy,
302
+ ),
303
+ audioAnalyzer: createCapRouter_audioAnalyzer(
304
+ (_ctx) => reg?.getSingleton<InferProvider<typeof audioAnalyzerCapability>>('audio-analyzer') ?? null,
305
+ remoteCapProxy,
306
+ ),
307
+ audioCodec: createCapRouter_audioCodec(
308
+ (_ctx) => reg?.getSingleton<InferProvider<typeof audioCodecCapability>>('audio-codec') ?? null,
309
+ remoteCapProxy,
310
+ ),
311
+ audioMetrics: createCapRouter_audioMetrics(
312
+ (_ctx) => reg?.getSingleton<InferProvider<typeof audioMetricsCapability>>('audio-metrics') ?? null,
313
+ remoteCapProxy,
314
+ ),
315
+ backup: createCapRouter_backup(
316
+ (_ctx) => reg?.getSingleton<InferProvider<typeof backupCapability>>('backup') ?? null,
317
+ remoteCapProxy,
318
+ ),
319
+ battery: createCapRouter_battery(
320
+ (_ctx) => requireDeviceScoped(reg, 'battery') as InferProvider<typeof batteryCapability> | null,
321
+ remoteCapProxy,
322
+ ),
323
+ brightness: createCapRouter_brightness(
324
+ (_ctx) => requireDeviceScoped(reg, 'brightness') as InferProvider<typeof brightnessCapability> | null,
325
+ remoteCapProxy,
326
+ ),
327
+ cameraCredentials: createCapRouter_cameraCredentials(
328
+ (_ctx) => requireDeviceScoped(reg, 'camera-credentials') as InferProvider<typeof cameraCredentialsCapability> | null,
329
+ remoteCapProxy,
330
+ ),
331
+ cameraStreams: createCapRouter_cameraStreams(
332
+ (_ctx) => reg?.getSingleton<InferProvider<typeof cameraStreamsCapability>>('camera-streams') ?? null,
333
+ remoteCapProxy,
334
+ ),
335
+ decoder: createCapRouter_decoder(
336
+ (_ctx) => reg?.getSingleton<InferProvider<typeof decoderCapability>>('decoder') ?? null,
337
+ remoteCapProxy,
338
+ ),
339
+ detectionPipeline: createCapRouter_detectionPipeline(
340
+ (_ctx) => reg?.getSingleton<InferProvider<typeof detectionPipelineCapability>>('detection-pipeline') ?? null,
341
+ remoteCapProxy,
342
+ ),
343
+ deviceDiscovery: createCapRouter_deviceDiscovery(
344
+ (_ctx) => requireDeviceScoped(reg, 'device-discovery') as InferProvider<typeof deviceDiscoveryCapability> | null,
345
+ remoteCapProxy,
346
+ ),
347
+ deviceExport: createCapRouter_deviceExport(
348
+ (_ctx, addonId) => {
349
+ if (!reg) return null
350
+ if (addonId !== undefined) {
351
+ return reg.getProviderByAddonId<InferProvider<typeof deviceExportCapability>>('device-export', addonId)
352
+ }
353
+ const entries = reg.getCollectionEntries<InferProvider<typeof deviceExportCapability>>('device-export')
354
+ if (entries.length === 0) return null
355
+ const providers = entries.map(([, p]) => p)
356
+ const first = providers[0]!
357
+ return {
358
+ ...first,
359
+ listSupportedDeviceKinds: concatCollection(providers, 'listSupportedDeviceKinds') as InferProvider<typeof deviceExportCapability>['listSupportedDeviceKinds'],
360
+ listExposedDevices: concatCollection(providers, 'listExposedDevices') as InferProvider<typeof deviceExportCapability>['listExposedDevices'],
361
+ }
362
+ },
363
+ remoteCapProxy,
364
+ ),
365
+ deviceManager: createCapRouter_deviceManager(
366
+ (_ctx) => reg?.getSingleton<InferProvider<typeof deviceManagerCapability>>('device-manager') ?? null,
367
+ remoteCapProxy,
368
+ ),
369
+ deviceOps: createCapRouter_deviceOps(
370
+ (_ctx) => reg?.getSingleton<InferProvider<typeof deviceOpsCapability>>('device-ops') ?? null,
371
+ remoteCapProxy,
372
+ ),
373
+ deviceProvider: createCapRouter_deviceProvider(
374
+ (_ctx, addonId) => {
375
+ if (!reg) return null
376
+ if (addonId !== undefined) {
377
+ return reg.getProviderByAddonId<InferProvider<typeof deviceProviderCapability>>('device-provider', addonId)
378
+ }
379
+ const entries = reg.getCollectionEntries<InferProvider<typeof deviceProviderCapability>>('device-provider')
380
+ if (entries.length === 0) return null
381
+ const providers = entries.map(([, p]) => p)
382
+ const first = providers[0]!
383
+ return {
384
+ ...first,
385
+ getDevices: concatCollection(providers, 'getDevices') as InferProvider<typeof deviceProviderCapability>['getDevices'],
386
+ discoverDevices: concatCollection(providers, 'discoverDevices') as InferProvider<typeof deviceProviderCapability>['discoverDevices'],
387
+ }
388
+ },
389
+ remoteCapProxy,
390
+ ),
391
+ deviceState: createCapRouter_deviceState(
392
+ (_ctx) => reg?.getSingleton<InferProvider<typeof deviceStateCapability>>('device-state') ?? null,
393
+ remoteCapProxy,
394
+ ),
395
+ deviceStatus: createCapRouter_deviceStatus(
396
+ (_ctx) => requireDeviceScoped(reg, 'device-status') as InferProvider<typeof deviceStatusCapability> | null,
397
+ remoteCapProxy,
398
+ ),
399
+ doorbell: createCapRouter_doorbell(
400
+ (_ctx) => requireDeviceScoped(reg, 'doorbell') as InferProvider<typeof doorbellCapability> | null,
401
+ remoteCapProxy,
402
+ ),
403
+ embeddingEncoder: createCapRouter_embeddingEncoder(
404
+ (_ctx, addonId) => {
405
+ if (!reg) return null
406
+ if (addonId !== undefined) {
407
+ return reg.getProviderByAddonId<InferProvider<typeof embeddingEncoderCapability>>('embedding-encoder', addonId)
408
+ }
409
+ const entries = reg.getCollectionEntries<InferProvider<typeof embeddingEncoderCapability>>('embedding-encoder')
410
+ return entries[0]?.[1] ?? null
411
+ },
412
+ remoteCapProxy,
413
+ ),
414
+ events: createCapRouter_events(
415
+ (_ctx) => reg?.getSingleton<InferProvider<typeof eventsCapability>>('events') ?? null,
416
+ remoteCapProxy,
417
+ ),
418
+ featureProbe: createCapRouter_featureProbe(
419
+ (_ctx) => requireDeviceScoped(reg, 'feature-probe') as InferProvider<typeof featureProbeCapability> | null,
420
+ remoteCapProxy,
421
+ ),
422
+ integrations: createCapRouter_integrations(
423
+ (_ctx) => reg?.getSingleton<InferProvider<typeof integrationsCapability>>('integrations') ?? null,
424
+ remoteCapProxy,
425
+ ),
426
+ intercom: createCapRouter_intercom(
427
+ (_ctx) => requireDeviceScoped(reg, 'intercom') as InferProvider<typeof intercomCapability> | null,
428
+ remoteCapProxy,
429
+ ),
430
+ localNetwork: createCapRouter_localNetwork(
431
+ (_ctx) => reg?.getSingleton<InferProvider<typeof localNetworkCapability>>('local-network') ?? null,
432
+ remoteCapProxy,
433
+ ),
434
+ meshNetwork: createCapRouter_meshNetwork(
435
+ (_ctx, addonId) => {
436
+ if (!reg) return null
437
+ if (addonId !== undefined) {
438
+ return reg.getProviderByAddonId<InferProvider<typeof meshNetworkCapability>>('mesh-network', addonId)
439
+ }
440
+ const entries = reg.getCollectionEntries<InferProvider<typeof meshNetworkCapability>>('mesh-network')
441
+ return entries[0]?.[1] ?? null
442
+ },
443
+ remoteCapProxy,
444
+ ),
445
+ metricsProvider: createCapRouter_metricsProvider(
446
+ (_ctx) => reg?.getSingleton<InferProvider<typeof metricsProviderCapability>>('metrics-provider') ?? null,
447
+ remoteCapProxy,
448
+ ),
449
+ motion: createCapRouter_motion(
450
+ (_ctx) => reg?.getSingleton<InferProvider<typeof motionCapability>>('motion') ?? null,
451
+ remoteCapProxy,
452
+ ),
453
+ motionDetection: createCapRouter_motionDetection(
454
+ (_ctx) => reg?.getSingleton<InferProvider<typeof motionDetectionCapability>>('motion-detection') ?? null,
455
+ remoteCapProxy,
456
+ ),
457
+ motionTrigger: createCapRouter_motionTrigger(
458
+ (_ctx) => requireDeviceScoped(reg, 'motion-trigger') as InferProvider<typeof motionTriggerCapability> | null,
459
+ remoteCapProxy,
460
+ ),
461
+ motionZones: createCapRouter_motionZones(
462
+ (_ctx) => requireDeviceScoped(reg, 'motion-zones') as InferProvider<typeof motionZonesCapability> | null,
463
+ remoteCapProxy,
464
+ ),
465
+ mqttBroker: createCapRouter_mqttBroker(
466
+ (_ctx, addonId) => {
467
+ if (!reg) return null
468
+ if (addonId !== undefined) {
469
+ return reg.getProviderByAddonId<InferProvider<typeof mqttBrokerCapability>>('mqtt-broker', addonId)
470
+ }
471
+ const entries = reg.getCollectionEntries<InferProvider<typeof mqttBrokerCapability>>('mqtt-broker')
472
+ if (entries.length === 0) return null
473
+ const providers = entries.map(([, p]) => p)
474
+ const first = providers[0]!
475
+ return {
476
+ ...first,
477
+ listBrokers: concatCollection(providers, 'listBrokers') as InferProvider<typeof mqttBrokerCapability>['listBrokers'],
478
+ }
479
+ },
480
+ remoteCapProxy,
481
+ ),
482
+ nativeObjectDetection: createCapRouter_nativeObjectDetection(
483
+ (_ctx) => reg?.getSingleton<InferProvider<typeof nativeObjectDetectionCapability>>('native-object-detection') ?? null,
484
+ remoteCapProxy,
485
+ ),
486
+ networkAccess: createCapRouter_networkAccess(
487
+ (_ctx, addonId) => {
488
+ if (!reg) return null
489
+ if (addonId !== undefined) {
490
+ return reg.getProviderByAddonId<InferProvider<typeof networkAccessCapability>>('network-access', addonId)
491
+ }
492
+ const entries = reg.getCollectionEntries<InferProvider<typeof networkAccessCapability>>('network-access')
493
+ if (entries.length === 0) return null
494
+ const providers = entries.map(([, p]) => p)
495
+ const first = providers[0]!
496
+ return {
497
+ ...first,
498
+ listEndpoints: concatCollection(providers, 'listEndpoints') as InferProvider<typeof networkAccessCapability>['listEndpoints'],
499
+ }
500
+ },
501
+ remoteCapProxy,
502
+ ),
503
+ networkQuality: createCapRouter_networkQuality(
504
+ (_ctx) => reg?.getSingleton<InferProvider<typeof networkQualityCapability>>('network-quality') ?? null,
505
+ remoteCapProxy,
506
+ ),
507
+ nodes: createCapRouter_nodes(
508
+ (_ctx) => reg?.getSingleton<InferProvider<typeof nodesCapability>>('nodes') ?? null,
509
+ remoteCapProxy,
510
+ ),
511
+ notificationOutput: createCapRouter_notificationOutput(
512
+ (_ctx, addonId) => {
513
+ if (!reg) return null
514
+ if (addonId !== undefined) {
515
+ return reg.getProviderByAddonId<InferProvider<typeof notificationOutputCapability>>('notification-output', addonId)
516
+ }
517
+ const entries = reg.getCollectionEntries<InferProvider<typeof notificationOutputCapability>>('notification-output')
518
+ return entries[0]?.[1] ?? null
519
+ },
520
+ remoteCapProxy,
521
+ ),
522
+ oauthIntegration: createCapRouter_oauthIntegration(
523
+ (_ctx, addonId) => {
524
+ if (!reg) return null
525
+ if (addonId !== undefined) {
526
+ return reg.getProviderByAddonId<InferProvider<typeof oauthIntegrationCapability>>('oauth-integration', addonId)
527
+ }
528
+ const entries = reg.getCollectionEntries<InferProvider<typeof oauthIntegrationCapability>>('oauth-integration')
529
+ return entries[0]?.[1] ?? null
530
+ },
531
+ remoteCapProxy,
532
+ ),
533
+ osd: createCapRouter_osd(
534
+ (_ctx) => requireDeviceScoped(reg, 'osd') as InferProvider<typeof osdCapability> | null,
535
+ remoteCapProxy,
536
+ ),
537
+ pipelineAnalytics: createCapRouter_pipelineAnalytics(
538
+ (_ctx) => reg?.getSingleton<InferProvider<typeof pipelineAnalyticsCapability>>('pipeline-analytics') ?? null,
539
+ remoteCapProxy,
540
+ ),
541
+ pipelineExecutor: createCapRouter_pipelineExecutor(
542
+ (_ctx) => reg?.getSingleton<InferProvider<typeof pipelineExecutorCapability>>('pipeline-executor') ?? null,
543
+ remoteCapProxy,
544
+ ),
545
+ pipelineOrchestrator: createCapRouter_pipelineOrchestrator(
546
+ (_ctx) => reg?.getSingleton<InferProvider<typeof pipelineOrchestratorCapability>>('pipeline-orchestrator') ?? null,
547
+ remoteCapProxy,
548
+ ),
549
+ pipelineRunner: createCapRouter_pipelineRunner(
550
+ (_ctx) => reg?.getSingleton<InferProvider<typeof pipelineRunnerCapability>>('pipeline-runner') ?? null,
551
+ remoteCapProxy,
552
+ ),
553
+ platformProbe: createCapRouter_platformProbe(
554
+ (_ctx) => reg?.getSingleton<InferProvider<typeof platformProbeCapability>>('platform-probe') ?? null,
555
+ remoteCapProxy,
556
+ ),
557
+ ptz: createCapRouter_ptz(
558
+ (_ctx) => requireDeviceScoped(reg, 'ptz') as InferProvider<typeof ptzCapability> | null,
559
+ remoteCapProxy,
560
+ ),
561
+ ptzAutotrack: createCapRouter_ptzAutotrack(
562
+ (_ctx) => requireDeviceScoped(reg, 'ptz-autotrack') as InferProvider<typeof ptzAutotrackCapability> | null,
563
+ remoteCapProxy,
564
+ ),
565
+ reboot: createCapRouter_reboot(
566
+ (_ctx) => requireDeviceScoped(reg, 'reboot') as InferProvider<typeof rebootCapability> | null,
567
+ remoteCapProxy,
568
+ ),
569
+ recording: createCapRouter_recording(
570
+ (_ctx) => reg?.getSingleton<InferProvider<typeof recordingCapability>>('recording') ?? null,
571
+ remoteCapProxy,
572
+ ),
573
+ recordingEngine: createCapRouter_recordingEngine(
574
+ (_ctx) => reg?.getSingleton<InferProvider<typeof recordingEngineCapability>>('recording-engine') ?? null,
575
+ remoteCapProxy,
576
+ ),
577
+ settingsStore: createCapRouter_settingsStore(
578
+ (_ctx) => reg?.getSingleton<InferProvider<typeof settingsStoreCapability>>('settings-store') ?? null,
579
+ remoteCapProxy,
580
+ ),
581
+ smtpProvider: createCapRouter_smtpProvider(
582
+ (_ctx, addonId) => {
583
+ if (!reg) return null
584
+ if (addonId !== undefined) {
585
+ return reg.getProviderByAddonId<InferProvider<typeof smtpProviderCapability>>('smtp-provider', addonId)
586
+ }
587
+ const entries = reg.getCollectionEntries<InferProvider<typeof smtpProviderCapability>>('smtp-provider')
588
+ return entries[0]?.[1] ?? null
589
+ },
590
+ remoteCapProxy,
591
+ ),
592
+ snapshot: createCapRouter_snapshot(
593
+ (_ctx) => reg?.getSingleton<InferProvider<typeof snapshotCapability>>('snapshot') ?? null,
594
+ remoteCapProxy,
595
+ ),
596
+ snapshotProvider: createCapRouter_snapshotProvider(
597
+ (_ctx, addonId) => {
598
+ if (!reg) return null
599
+ if (addonId !== undefined) {
600
+ return reg.getProviderByAddonId<InferProvider<typeof snapshotProviderCapability>>('snapshot-provider', addonId)
601
+ }
602
+ const entries = reg.getCollectionEntries<InferProvider<typeof snapshotProviderCapability>>('snapshot-provider')
603
+ return entries[0]?.[1] ?? null
604
+ },
605
+ remoteCapProxy,
606
+ ),
607
+ ssoBridge: createCapRouter_ssoBridge(
608
+ (_ctx) => reg?.getSingleton<InferProvider<typeof ssoBridgeCapability>>('sso-bridge') ?? null,
609
+ remoteCapProxy,
610
+ ),
611
+ storage: createCapRouter_storage(
612
+ (_ctx) => reg?.getSingleton<InferProvider<typeof storageCapability>>('storage') ?? null,
613
+ remoteCapProxy,
614
+ ),
615
+ storageProvider: createCapRouter_storageProvider(
616
+ (_ctx, addonId) => {
617
+ if (!reg) return null
618
+ if (addonId !== undefined) {
619
+ return reg.getProviderByAddonId<InferProvider<typeof storageProviderCapability>>('storage-provider', addonId)
620
+ }
621
+ const entries = reg.getCollectionEntries<InferProvider<typeof storageProviderCapability>>('storage-provider')
622
+ if (entries.length === 0) return null
623
+ const providers = entries.map(([, p]) => p)
624
+ const first = providers[0]!
625
+ return {
626
+ ...first,
627
+ list: concatCollection(providers, 'list') as InferProvider<typeof storageProviderCapability>['list'],
628
+ }
629
+ },
630
+ remoteCapProxy,
631
+ ),
632
+ streamBroker: createCapRouter_streamBroker(
633
+ (_ctx) => reg?.getSingleton<InferProvider<typeof streamBrokerCapability>>('stream-broker') ?? null,
634
+ remoteCapProxy,
635
+ ),
636
+ streamParams: createCapRouter_streamParams(
637
+ (_ctx) => requireDeviceScoped(reg, 'stream-params') as InferProvider<typeof streamParamsCapability> | null,
638
+ remoteCapProxy,
639
+ ),
640
+ switch: createCapRouter_switch(
641
+ (_ctx) => requireDeviceScoped(reg, 'switch') as InferProvider<typeof switchCapability> | null,
642
+ remoteCapProxy,
643
+ ),
644
+ system: createCapRouter_system(
645
+ (_ctx) => reg?.getSingleton<InferProvider<typeof systemCapability>>('system') ?? null,
646
+ remoteCapProxy,
647
+ ),
648
+ toast: createCapRouter_toast(
649
+ (_ctx) => reg?.getSingleton<InferProvider<typeof toastCapability>>('toast') ?? null,
650
+ remoteCapProxy,
651
+ ),
652
+ turnProvider: createCapRouter_turnProvider(
653
+ (_ctx, addonId) => {
654
+ if (!reg) return null
655
+ if (addonId !== undefined) {
656
+ return reg.getProviderByAddonId<InferProvider<typeof turnProviderCapability>>('turn-provider', addonId)
657
+ }
658
+ const entries = reg.getCollectionEntries<InferProvider<typeof turnProviderCapability>>('turn-provider')
659
+ if (entries.length === 0) return null
660
+ const providers = entries.map(([, p]) => p)
661
+ const first = providers[0]!
662
+ return {
663
+ ...first,
664
+ getTurnServers: concatCollection(providers, 'getTurnServers') as InferProvider<typeof turnProviderCapability>['getTurnServers'],
665
+ }
666
+ },
667
+ remoteCapProxy,
668
+ ),
669
+ userManagement: createCapRouter_userManagement(
670
+ (_ctx) => reg?.getSingleton<InferProvider<typeof userManagementCapability>>('user-management') ?? null,
671
+ remoteCapProxy,
672
+ ),
673
+ userPasskeys: createCapRouter_userPasskeys(
674
+ (_ctx, addonId) => {
675
+ if (!reg) return null
676
+ if (addonId !== undefined) {
677
+ return reg.getProviderByAddonId<InferProvider<typeof userPasskeysCapability>>('user-passkeys', addonId)
678
+ }
679
+ const entries = reg.getCollectionEntries<InferProvider<typeof userPasskeysCapability>>('user-passkeys')
680
+ if (entries.length === 0) return null
681
+ const providers = entries.map(([, p]) => p)
682
+ const first = providers[0]!
683
+ return {
684
+ ...first,
685
+ listPasskeys: concatCollection(providers, 'listPasskeys') as InferProvider<typeof userPasskeysCapability>['listPasskeys'],
686
+ }
687
+ },
688
+ remoteCapProxy,
689
+ ),
690
+ webrtcSession: createCapRouter_webrtcSession(
691
+ (_ctx) => reg?.getSingleton<InferProvider<typeof webrtcSessionCapability>>('webrtc-session') ?? null,
692
+ remoteCapProxy,
693
+ ),
694
+ zoneAnalytics: createCapRouter_zoneAnalytics(
695
+ (_ctx) => reg?.getSingleton<InferProvider<typeof zoneAnalyticsCapability>>('zone-analytics') ?? null,
696
+ remoteCapProxy,
697
+ ),
698
+ zoneRules: createCapRouter_zoneRules(
699
+ (_ctx) => reg?.getSingleton<InferProvider<typeof zoneRulesCapability>>('zone-rules') ?? null,
700
+ remoteCapProxy,
701
+ ),
702
+ zones: createCapRouter_zones(
703
+ (_ctx) => reg?.getSingleton<InferProvider<typeof zonesCapability>>('zones') ?? null,
704
+ remoteCapProxy,
705
+ ),
706
+ } as const
707
+ }