@camstack/server 0.2.2 → 1.0.1

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 (234) hide show
  1. package/{src/agent-status-page.ts → dist/agent-status-page.js} +30 -45
  2. package/dist/api/addon-upload.js +441 -0
  3. package/dist/api/addons-custom.router.js +91 -0
  4. package/dist/api/auth-whoami.js +55 -0
  5. package/dist/api/bridge-addons.router.js +109 -0
  6. package/dist/api/capabilities.router.js +229 -0
  7. package/dist/api/core/addon-settings.router.js +117 -0
  8. package/dist/api/core/agents.router.js +73 -0
  9. package/dist/api/core/auth.router.js +286 -0
  10. package/dist/api/core/bulk-update-coordinator.js +229 -0
  11. package/dist/api/core/cap-providers.js +1124 -0
  12. package/dist/api/core/capabilities.router.js +138 -0
  13. package/dist/api/core/collection-preference.js +17 -0
  14. package/dist/api/core/event-bus-proxy.router.js +45 -0
  15. package/dist/api/core/hwaccel.router.js +91 -0
  16. package/dist/api/core/live-events.router.js +61 -0
  17. package/dist/api/core/logs.router.js +172 -0
  18. package/dist/api/core/notifications.router.js +67 -0
  19. package/dist/api/core/repl.router.js +35 -0
  20. package/dist/api/core/settings-backend.router.js +121 -0
  21. package/dist/api/core/stream-probe.router.js +58 -0
  22. package/dist/api/core/system-events.router.js +100 -0
  23. package/dist/api/health/health.routes.js +68 -0
  24. package/{src/api/oauth2/consent-page.ts → dist/api/oauth2/consent-page.js} +11 -20
  25. package/dist/api/oauth2/oauth2-routes.js +219 -0
  26. package/dist/api/trpc/cap-mount-helpers.js +194 -0
  27. package/dist/api/trpc/cap-route-error-formatter.js +133 -0
  28. package/dist/api/trpc/client-ip.js +147 -0
  29. package/dist/api/trpc/core-cap-bridge.js +115 -0
  30. package/dist/api/trpc/generated-cap-mounts.js +388 -0
  31. package/dist/api/trpc/generated-cap-routers.js +7635 -0
  32. package/dist/api/trpc/scope-access.js +93 -0
  33. package/dist/api/trpc/trpc.context.js +184 -0
  34. package/dist/api/trpc/trpc.middleware.js +139 -0
  35. package/dist/api/trpc/trpc.router.js +188 -0
  36. package/dist/auth/session-cookie.js +47 -0
  37. package/dist/boot/boot-config.js +241 -0
  38. package/dist/boot/integration-id-backfill.js +76 -0
  39. package/dist/boot/post-boot.service.js +85 -0
  40. package/dist/core/addon/addon-call-gateway.js +99 -0
  41. package/dist/core/addon/addon-package.service.js +1560 -0
  42. package/dist/core/addon/addon-registry.service.js +2739 -0
  43. package/{src/core/addon/addon-row-manifest.ts → dist/core/addon/addon-row-manifest.js} +5 -5
  44. package/dist/core/addon/addon-search.service.js +62 -0
  45. package/dist/core/addon/addon-settings-provider.js +102 -0
  46. package/dist/core/addon/addon.tokens.js +5 -0
  47. package/dist/core/addon-bridge/addon-bridge.service.js +145 -0
  48. package/dist/core/addon-pages/addon-pages.service.js +107 -0
  49. package/dist/core/addon-widgets/addon-widgets.service.js +120 -0
  50. package/dist/core/agent/agent-registry.service.js +477 -0
  51. package/dist/core/auth/auth.service.js +10 -0
  52. package/dist/core/capability/capability.service.js +58 -0
  53. package/dist/core/config/config.schema.js +7 -0
  54. package/dist/core/config/config.service.js +10 -0
  55. package/dist/core/events/event-bus.service.js +83 -0
  56. package/dist/core/feature/feature.service.js +10 -0
  57. package/dist/core/lifecycle/lifecycle-state-machine.js +6 -0
  58. package/dist/core/logging/log-ring-buffer.js +6 -0
  59. package/dist/core/logging/logging.service.js +130 -0
  60. package/dist/core/logging/scoped-logger.js +6 -0
  61. package/dist/core/moleculer/cap-call-fn.js +50 -0
  62. package/dist/core/moleculer/cap-route-authority.js +122 -0
  63. package/dist/core/moleculer/moleculer.service.js +898 -0
  64. package/dist/core/network/network-quality.service.js +7 -0
  65. package/dist/core/notification/notification-wrapper.service.js +33 -0
  66. package/dist/core/notification/toast-wrapper.service.js +25 -0
  67. package/dist/core/provider/provider.tokens.js +4 -0
  68. package/dist/core/repl/repl-engine.service.js +140 -0
  69. package/dist/core/storage/fs-storage-backend.js +6 -0
  70. package/dist/core/storage/storage-location-manager.js +6 -0
  71. package/dist/core/storage/storage.service.js +7 -0
  72. package/dist/core/streaming/stream-probe.service.js +209 -0
  73. package/dist/core/topology/topology-emitter.service.js +106 -0
  74. package/dist/launcher.js +325 -0
  75. package/dist/main.js +1098 -0
  76. package/dist/manual-boot.js +227 -0
  77. package/package.json +5 -1
  78. package/src/__tests__/addon-install-e2e.test.ts +0 -74
  79. package/src/__tests__/addon-pages-e2e.test.ts +0 -200
  80. package/src/__tests__/addon-route-session.test.ts +0 -17
  81. package/src/__tests__/addon-settings-router.spec.ts +0 -67
  82. package/src/__tests__/addon-upload.spec.ts +0 -475
  83. package/src/__tests__/agent-registry.spec.ts +0 -179
  84. package/src/__tests__/agent-status-page.spec.ts +0 -82
  85. package/src/__tests__/auth-session-cookie.test.ts +0 -48
  86. package/src/__tests__/bulk-update-coordinator.spec.ts +0 -303
  87. package/src/__tests__/cap-ownership-authority.spec.ts +0 -431
  88. package/src/__tests__/cap-providers/cap-providers-location-import.spec.ts +0 -206
  89. package/src/__tests__/cap-providers/cap-usage-graph.spec.ts +0 -37
  90. package/src/__tests__/cap-providers/compute-topology-categories.spec.ts +0 -110
  91. package/src/__tests__/cap-providers/integrations-delete-cascade.spec.ts +0 -292
  92. package/src/__tests__/cap-providers-bulk-update.spec.ts +0 -408
  93. package/src/__tests__/cap-route-adapter.spec.ts +0 -302
  94. package/src/__tests__/cap-routers/_meta.spec.ts +0 -199
  95. package/src/__tests__/cap-routers/addon-settings.router.spec.ts +0 -115
  96. package/src/__tests__/cap-routers/broker-routing.router.spec.ts +0 -177
  97. package/src/__tests__/cap-routers/cap-route-error-formatter.spec.ts +0 -125
  98. package/src/__tests__/cap-routers/capabilities-node.spec.ts +0 -68
  99. package/src/__tests__/cap-routers/device-link-overlay.spec.ts +0 -137
  100. package/src/__tests__/cap-routers/device-manager-aggregate.router.spec.ts +0 -194
  101. package/src/__tests__/cap-routers/harness.ts +0 -163
  102. package/src/__tests__/cap-routers/metrics-provider.router.spec.ts +0 -133
  103. package/src/__tests__/cap-routers/null-provider-guard.spec.ts +0 -64
  104. package/src/__tests__/cap-routers/pipeline-executor.router.spec.ts +0 -159
  105. package/src/__tests__/cap-routers/settings-store.router.spec.ts +0 -291
  106. package/src/__tests__/capability-e2e.test.ts +0 -384
  107. package/src/__tests__/cli-e2e.test.ts +0 -150
  108. package/src/__tests__/core-cap-bridge.spec.ts +0 -91
  109. package/src/__tests__/dev-bootstrap-shm-ring.spec.ts +0 -40
  110. package/src/__tests__/device-settings-contribution-dispatch.spec.ts +0 -280
  111. package/src/__tests__/embedded-deps-e2e.test.ts +0 -125
  112. package/src/__tests__/event-bus-proxy-router.spec.ts +0 -75
  113. package/src/__tests__/fixtures/mock-analysis-addon-a.ts +0 -37
  114. package/src/__tests__/fixtures/mock-analysis-addon-b.ts +0 -37
  115. package/src/__tests__/fixtures/mock-log-addon.ts +0 -37
  116. package/src/__tests__/fixtures/mock-storage-addon.ts +0 -40
  117. package/src/__tests__/framework-allowlist.spec.ts +0 -96
  118. package/src/__tests__/framework-installer-defer-restart.spec.ts +0 -165
  119. package/src/__tests__/https-e2e.test.ts +0 -124
  120. package/src/__tests__/lifecycle-e2e.test.ts +0 -189
  121. package/src/__tests__/live-events-subscription.spec.ts +0 -149
  122. package/src/__tests__/moleculer/uds-readiness.spec.ts +0 -150
  123. package/src/__tests__/moleculer/uds-topology.spec.ts +0 -418
  124. package/src/__tests__/moleculer/uds-unowned-call.spec.ts +0 -383
  125. package/src/__tests__/moleculer-register-node-idempotency.spec.ts +0 -273
  126. package/src/__tests__/native-cap-route.spec.ts +0 -427
  127. package/src/__tests__/oauth2-account-linking.spec.ts +0 -867
  128. package/src/__tests__/post-boot-restart.spec.ts +0 -161
  129. package/src/__tests__/singleton-contention.test.ts +0 -499
  130. package/src/__tests__/streaming-diagnostic.test.ts +0 -615
  131. package/src/__tests__/streaming-scale.test.ts +0 -314
  132. package/src/__tests__/uds-addon-call-wiring.spec.ts +0 -242
  133. package/src/__tests__/uds-log-ingest.spec.ts +0 -183
  134. package/src/api/__tests__/addons-custom.spec.ts +0 -148
  135. package/src/api/__tests__/capabilities.router.test.ts +0 -56
  136. package/src/api/addon-upload.ts +0 -529
  137. package/src/api/addons-custom.router.ts +0 -101
  138. package/src/api/auth-whoami.ts +0 -101
  139. package/src/api/bridge-addons.router.ts +0 -122
  140. package/src/api/capabilities.router.ts +0 -265
  141. package/src/api/core/__tests__/auth-router-totp.spec.ts +0 -297
  142. package/src/api/core/__tests__/integration-markers.spec.ts +0 -10
  143. package/src/api/core/addon-settings.router.ts +0 -127
  144. package/src/api/core/agents.router.ts +0 -86
  145. package/src/api/core/auth.router.ts +0 -322
  146. package/src/api/core/bulk-update-coordinator.ts +0 -305
  147. package/src/api/core/cap-providers.ts +0 -1339
  148. package/src/api/core/capabilities.router.ts +0 -149
  149. package/src/api/core/collection-preference.ts +0 -40
  150. package/src/api/core/event-bus-proxy.router.ts +0 -45
  151. package/src/api/core/hwaccel.router.ts +0 -108
  152. package/src/api/core/live-events.router.ts +0 -67
  153. package/src/api/core/logs.router.ts +0 -195
  154. package/src/api/core/notifications.router.ts +0 -66
  155. package/src/api/core/repl.router.ts +0 -39
  156. package/src/api/core/settings-backend.router.ts +0 -140
  157. package/src/api/core/stream-probe.router.ts +0 -57
  158. package/src/api/core/system-events.router.ts +0 -125
  159. package/src/api/health/health.routes.ts +0 -117
  160. package/src/api/oauth2/__tests__/oauth2-routes.spec.ts +0 -62
  161. package/src/api/oauth2/oauth2-routes.ts +0 -281
  162. package/src/api/trpc/__tests__/client-ip.spec.ts +0 -146
  163. package/src/api/trpc/__tests__/scope-access-device.spec.ts +0 -268
  164. package/src/api/trpc/__tests__/scope-access.spec.ts +0 -102
  165. package/src/api/trpc/__tests__/webrtc-session-ua-enrich.spec.ts +0 -136
  166. package/src/api/trpc/cap-mount-helpers.ts +0 -245
  167. package/src/api/trpc/cap-route-error-formatter.ts +0 -171
  168. package/src/api/trpc/client-ip.ts +0 -147
  169. package/src/api/trpc/core-cap-bridge.ts +0 -154
  170. package/src/api/trpc/generated-cap-mounts.ts +0 -1240
  171. package/src/api/trpc/generated-cap-routers.ts +0 -11523
  172. package/src/api/trpc/scope-access.ts +0 -110
  173. package/src/api/trpc/trpc.context.ts +0 -258
  174. package/src/api/trpc/trpc.middleware.ts +0 -146
  175. package/src/api/trpc/trpc.router.ts +0 -389
  176. package/src/auth/session-cookie.ts +0 -54
  177. package/src/boot/__tests__/integration-id-backfill.spec.ts +0 -131
  178. package/src/boot/boot-config.ts +0 -259
  179. package/src/boot/integration-id-backfill.ts +0 -109
  180. package/src/boot/post-boot.service.ts +0 -105
  181. package/src/core/addon/__tests__/addon-registry-capability.test.ts +0 -62
  182. package/src/core/addon/__tests__/addon-row-manifest.spec.ts +0 -62
  183. package/src/core/addon/addon-call-gateway.ts +0 -171
  184. package/src/core/addon/addon-package.service.ts +0 -1787
  185. package/src/core/addon/addon-registry.service.ts +0 -3130
  186. package/src/core/addon/addon-search.service.ts +0 -91
  187. package/src/core/addon/addon-settings-provider.ts +0 -220
  188. package/src/core/addon/addon.tokens.ts +0 -2
  189. package/src/core/addon-bridge/addon-bridge.service.ts +0 -130
  190. package/src/core/addon-pages/addon-pages.service.spec.ts +0 -117
  191. package/src/core/addon-pages/addon-pages.service.ts +0 -82
  192. package/src/core/addon-widgets/addon-widgets.service.ts +0 -95
  193. package/src/core/agent/agent-registry.service.ts +0 -529
  194. package/src/core/auth/auth.service.spec.ts +0 -86
  195. package/src/core/auth/auth.service.ts +0 -8
  196. package/src/core/capability/capability.service.ts +0 -66
  197. package/src/core/config/config.schema.ts +0 -3
  198. package/src/core/config/config.service.spec.ts +0 -175
  199. package/src/core/config/config.service.ts +0 -7
  200. package/src/core/events/event-bus.service.spec.ts +0 -235
  201. package/src/core/events/event-bus.service.ts +0 -89
  202. package/src/core/feature/feature.service.spec.ts +0 -99
  203. package/src/core/feature/feature.service.ts +0 -8
  204. package/src/core/lifecycle/lifecycle-state-machine.spec.ts +0 -166
  205. package/src/core/lifecycle/lifecycle-state-machine.ts +0 -3
  206. package/src/core/logging/log-ring-buffer.ts +0 -3
  207. package/src/core/logging/logging.service.spec.ts +0 -287
  208. package/src/core/logging/logging.service.ts +0 -143
  209. package/src/core/logging/scoped-logger.ts +0 -3
  210. package/src/core/moleculer/cap-call-fn.spec.ts +0 -173
  211. package/src/core/moleculer/cap-call-fn.ts +0 -107
  212. package/src/core/moleculer/cap-route-authority.ts +0 -194
  213. package/src/core/moleculer/moleculer.service.ts +0 -1072
  214. package/src/core/network/network-quality.service.spec.ts +0 -53
  215. package/src/core/network/network-quality.service.ts +0 -5
  216. package/src/core/notification/notification-wrapper.service.ts +0 -34
  217. package/src/core/notification/toast-wrapper.service.ts +0 -27
  218. package/src/core/provider/provider.tokens.ts +0 -1
  219. package/src/core/repl/repl-engine.service.spec.ts +0 -444
  220. package/src/core/repl/repl-engine.service.ts +0 -155
  221. package/src/core/storage/fs-storage-backend.spec.ts +0 -70
  222. package/src/core/storage/fs-storage-backend.ts +0 -3
  223. package/src/core/storage/storage-location-manager.spec.ts +0 -130
  224. package/src/core/storage/storage-location-manager.ts +0 -3
  225. package/src/core/storage/storage.service.spec.ts +0 -73
  226. package/src/core/storage/storage.service.ts +0 -3
  227. package/src/core/streaming/stream-probe.service.ts +0 -221
  228. package/src/core/topology/topology-emitter.service.ts +0 -105
  229. package/src/launcher.ts +0 -314
  230. package/src/main.ts +0 -1245
  231. package/src/manual-boot.ts +0 -301
  232. package/tsconfig.build.json +0 -8
  233. package/tsconfig.json +0 -33
  234. package/vitest.config.ts +0 -26
@@ -1,149 +0,0 @@
1
- /**
2
- * Live events subscription — unit + in-process e2e test.
3
- *
4
- * Proves that an event emitted on `EventBusService` is delivered to a
5
- * consumer that went through `live.onEvent` → `iterableSubscription`.
6
- * This is the same path UI components use via the WS client (AlertBell,
7
- * EngineTab). If this test passes but the UI still doesn't receive
8
- * events, the bug is downstream in the WS adapter, not in the routing.
9
- */
10
- import { describe, it, expect, vi } from 'vitest'
11
- import { SystemEventBus } from '@camstack/core'
12
- import { createLiveEventsRouter } from '../api/core/live-events.router.js'
13
- import { makeCtx } from './cap-routers/harness.js'
14
- import type { EventBusService } from '../core/events/event-bus.service.js'
15
-
16
- function sleep(ms: number): Promise<void> {
17
- return new Promise((resolve) => setTimeout(resolve, ms))
18
- }
19
-
20
- function makeEvent(category: string, data: Record<string, unknown> = {}) {
21
- return {
22
- id: `evt-${Math.random().toString(36).slice(2, 8)}`,
23
- timestamp: new Date(),
24
- source: { type: 'pipeline' as const, id: 'benchmark' },
25
- category,
26
- data: { type: `pipeline.${category}`, ...data },
27
- }
28
- }
29
-
30
- describe('live events subscription', () => {
31
- it('delivers events emitted AFTER subscription', async () => {
32
- const bus = new SystemEventBus() as unknown as EventBusService
33
- const router = createLiveEventsRouter(bus, {
34
- getDeviceRegistry: () => ({ getAll: () => [], getAllForAddon: () => [] }),
35
- } as never)
36
- const caller = router.createCaller(makeCtx('admin'))
37
-
38
- const iter = await caller.onEvent({ category: 'benchmark.progress' })
39
-
40
- // Collect received events concurrently while emitting.
41
- const received: Array<{ category: string; data: Record<string, unknown> }> = []
42
- const collector = (async () => {
43
- for await (const ev of iter) {
44
- received.push({ category: ev.category, data: ev.data })
45
- if (received.length >= 3) return
46
- }
47
- })()
48
-
49
- // Give the async generator a tick to wire up its internal promise.
50
- await sleep(10)
51
-
52
- bus.emit(makeEvent('benchmark.progress', { iteration: 1, totalMs: 50 }))
53
- bus.emit(makeEvent('benchmark.progress', { iteration: 2, totalMs: 48 }))
54
- bus.emit(makeEvent('other.category', { ignored: true }))
55
- bus.emit(makeEvent('benchmark.progress', { iteration: 3, totalMs: 52 }))
56
-
57
- await collector
58
-
59
- expect(received).toHaveLength(3)
60
- expect(received.map((r) => r.data.iteration)).toEqual([1, 2, 3])
61
- })
62
-
63
- it('filters events that do not match the requested category', async () => {
64
- const bus = new SystemEventBus() as unknown as EventBusService
65
- const router = createLiveEventsRouter(bus, {
66
- getDeviceRegistry: () => ({ getAll: () => [], getAllForAddon: () => [] }),
67
- } as never)
68
- const caller = router.createCaller(makeCtx('admin'))
69
-
70
- const iter = await caller.onEvent({ category: 'benchmark.progress' })
71
-
72
- const received: string[] = []
73
- const stop = vi.fn()
74
- const collector = (async () => {
75
- for await (const ev of iter) {
76
- received.push(ev.category)
77
- if (received.length >= 2) {
78
- stop()
79
- return
80
- }
81
- }
82
- })()
83
-
84
- await sleep(10)
85
-
86
- // Emit a mix — only 'benchmark.progress' should pass.
87
- bus.emit(makeEvent('alert.created', {}))
88
- bus.emit(makeEvent('benchmark.progress', { iteration: 1 }))
89
- bus.emit(makeEvent('benchmark.heartbeat', {}))
90
- bus.emit(makeEvent('alert.updated', {}))
91
- bus.emit(makeEvent('benchmark.progress', { iteration: 2 }))
92
-
93
- await collector
94
-
95
- expect(received).toEqual(['benchmark.progress', 'benchmark.progress'])
96
- expect(stop).toHaveBeenCalledOnce()
97
- })
98
-
99
- it('receives recent events via recentSystemEvents query', async () => {
100
- const bus = new SystemEventBus() as unknown as EventBusService
101
- const router = createLiveEventsRouter(bus, {
102
- getDeviceRegistry: () => ({ getAll: () => [], getAllForAddon: () => [] }),
103
- } as never)
104
- const caller = router.createCaller(makeCtx('admin'))
105
-
106
- bus.emit(makeEvent('benchmark.progress', { iteration: 1 }))
107
- bus.emit(makeEvent('alert.created', {}))
108
- bus.emit(makeEvent('benchmark.progress', { iteration: 2 }))
109
-
110
- const recent = await caller.recentSystemEvents({ category: 'benchmark.progress', limit: 10 })
111
- expect(recent).toHaveLength(2)
112
- // recentSystemEvents returns newest-first
113
- const iterations = recent.map((e) => e.data.iteration as number).toSorted((a, b) => a - b)
114
- expect(iterations).toEqual([1, 2])
115
- })
116
-
117
- it('delivers bursts — multiple events queued before the consumer drains', async () => {
118
- // Reproduces the benchmark scenario where runBenchmark emits 3 events
119
- // back-to-back; the subscription should buffer them and deliver all 3.
120
- const bus = new SystemEventBus() as unknown as EventBusService
121
- const router = createLiveEventsRouter(bus, {
122
- getDeviceRegistry: () => ({ getAll: () => [], getAllForAddon: () => [] }),
123
- } as never)
124
- const caller = router.createCaller(makeCtx('admin'))
125
-
126
- const iter = await caller.onEvent({ category: 'benchmark.progress' })
127
-
128
- const received: number[] = []
129
- const collector = (async () => {
130
- for await (const ev of iter) {
131
- received.push(ev.data.iteration as number)
132
- if (received.length >= 5) return
133
- }
134
- })()
135
-
136
- // Let the generator body run through its first `await`, registering the
137
- // bus subscription. Without this tick subscribe() hasn't attached yet.
138
- await sleep(20)
139
-
140
- // Emit 5 events synchronously — no awaits between.
141
- for (let i = 1; i <= 5; i++) {
142
- bus.emit(makeEvent('benchmark.progress', { iteration: i }))
143
- }
144
-
145
- await collector
146
-
147
- expect(received).toEqual([1, 2, 3, 4, 5])
148
- })
149
- })
@@ -1,150 +0,0 @@
1
- /**
2
- * UDS readiness snapshot wiring — unit test for Task D1.
3
- *
4
- * Verifies that:
5
- * 1. The hub's `LocalChildRegistry.onReadinessSnapshotRequest` is wired to
6
- * return `readinessRegistry.getSnapshotForTransport()` — the same records
7
- * `$readiness.getSnapshot` returns, now also reachable over UDS.
8
- * 2. The agent's `agentUdsRegistry.onReadinessSnapshotRequest` is wired to
9
- * return its own registry's snapshot.
10
- *
11
- * We do NOT spin up a full broker — instead we test the wiring function
12
- * `wireReadinessSnapshotHandler` which is extracted from the hub/agent setup
13
- * so the glue code is unit-testable.
14
- */
15
- import { describe, it, expect, vi } from 'vitest'
16
- import type { IReadinessRegistryRecord } from '@camstack/types'
17
-
18
- // --------------------------------------------------------------------------
19
- // Helpers
20
- // --------------------------------------------------------------------------
21
-
22
- interface FakeReadinessRegistry {
23
- getSnapshotForTransport(): readonly IReadinessRegistryRecord[]
24
- }
25
-
26
- interface FakeLocalChildRegistry {
27
- onReadinessSnapshotRequest(handler: () => readonly IReadinessRegistryRecord[]): void
28
- }
29
-
30
- /**
31
- * Minimal wiring function — production code calls exactly this at the same
32
- * site in moleculer.service.ts and agent-bootstrap.ts.
33
- */
34
- function wireReadinessSnapshotHandler(
35
- childRegistry: FakeLocalChildRegistry,
36
- readinessRegistry: FakeReadinessRegistry,
37
- ): void {
38
- childRegistry.onReadinessSnapshotRequest(() => readinessRegistry.getSnapshotForTransport())
39
- }
40
-
41
- // --------------------------------------------------------------------------
42
- // Tests
43
- // --------------------------------------------------------------------------
44
-
45
- describe('D1 — wireReadinessSnapshotHandler', () => {
46
- it('registers a handler on the child registry', () => {
47
- const childReg: FakeLocalChildRegistry = {
48
- onReadinessSnapshotRequest: vi.fn(),
49
- }
50
- const readinessReg: FakeReadinessRegistry = {
51
- getSnapshotForTransport: () => [],
52
- }
53
-
54
- wireReadinessSnapshotHandler(childReg, readinessReg)
55
-
56
- expect(childReg.onReadinessSnapshotRequest).toHaveBeenCalledOnce()
57
- })
58
-
59
- it('the registered handler returns getSnapshotForTransport() records', () => {
60
- const records: IReadinessRegistryRecord[] = [
61
- {
62
- capName: 'pipeline-executor',
63
- scope: { type: 'global' },
64
- state: 'ready',
65
- generation: 'gen-abc',
66
- epoch: 1,
67
- lastChange: 1_000_000,
68
- sourceNodeId: 'hub/pipeline-executor',
69
- },
70
- ]
71
-
72
- let capturedHandler: (() => readonly IReadinessRegistryRecord[]) | null = null
73
- const childReg: FakeLocalChildRegistry = {
74
- onReadinessSnapshotRequest: (h) => {
75
- capturedHandler = h
76
- },
77
- }
78
- const readinessReg: FakeReadinessRegistry = {
79
- getSnapshotForTransport: () => records,
80
- }
81
-
82
- wireReadinessSnapshotHandler(childReg, readinessReg)
83
-
84
- expect(capturedHandler).not.toBeNull()
85
- const result = capturedHandler!()
86
- expect(result).toBe(records)
87
- })
88
-
89
- it('handler calls getSnapshotForTransport on every invocation (live snapshot)', () => {
90
- const getSnapshot = vi
91
- .fn<[], readonly IReadinessRegistryRecord[]>()
92
- .mockReturnValueOnce([])
93
- .mockReturnValueOnce([
94
- {
95
- capName: 'stream-broker',
96
- scope: { type: 'node', nodeId: 'hub' },
97
- state: 'ready',
98
- generation: 'gen-1',
99
- epoch: 1,
100
- lastChange: 1_000,
101
- sourceNodeId: 'hub',
102
- },
103
- ])
104
-
105
- let capturedHandler: (() => readonly IReadinessRegistryRecord[]) | null = null
106
- const childReg: FakeLocalChildRegistry = {
107
- onReadinessSnapshotRequest: (h) => {
108
- capturedHandler = h
109
- },
110
- }
111
- const readinessReg: FakeReadinessRegistry = { getSnapshotForTransport: getSnapshot }
112
-
113
- wireReadinessSnapshotHandler(childReg, readinessReg)
114
-
115
- expect(capturedHandler!()).toHaveLength(0)
116
- expect(capturedHandler!()).toHaveLength(1)
117
- expect(getSnapshot).toHaveBeenCalledTimes(2)
118
- })
119
-
120
- it('handler snapshot reflects current registry state (not a frozen copy)', () => {
121
- const mutableRecords: IReadinessRegistryRecord[] = []
122
- const readinessReg: FakeReadinessRegistry = {
123
- getSnapshotForTransport: () => [...mutableRecords],
124
- }
125
-
126
- let capturedHandler: (() => readonly IReadinessRegistryRecord[]) | null = null
127
- const childReg: FakeLocalChildRegistry = {
128
- onReadinessSnapshotRequest: (h) => {
129
- capturedHandler = h
130
- },
131
- }
132
-
133
- wireReadinessSnapshotHandler(childReg, readinessReg)
134
-
135
- expect(capturedHandler!()).toHaveLength(0)
136
-
137
- mutableRecords.push({
138
- capName: 'motion-detector',
139
- scope: { type: 'device', deviceId: 7 },
140
- state: 'starting',
141
- generation: 'gen-2',
142
- epoch: 0,
143
- lastChange: 2_000,
144
- sourceNodeId: 'hub/provider-reolink',
145
- })
146
-
147
- expect(capturedHandler!()).toHaveLength(1)
148
- expect(capturedHandler!()[0]!.capName).toBe('motion-detector')
149
- })
150
- })