@camstack/server 1.0.0 → 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,408 +0,0 @@
1
- /**
2
- * cap-providers-bulk-update.spec.ts
3
- *
4
- * Verifies the wire-up in buildAddonsProvider for:
5
- * 1. Delegation to BulkUpdateCoordinator (startBulkUpdate / cancelBulkUpdate /
6
- * getBulkUpdateState / listActiveBulkUpdates)
7
- * 2. isSystem field added to listUpdates output
8
- * 3. deferRestart propagated through updateFrameworkPackage
9
- *
10
- * Spec: docs/superpowers/specs/2026-05-21-addons-bulk-update-progress-design.md
11
- * Plan: docs/superpowers/plans/2026-05-21-addons-bulk-update-progress.md (Task 4)
12
- */
13
- import { describe, it, expect, vi, beforeEach } from 'vitest'
14
- import type { IAddonsProvider } from '@camstack/types'
15
- import { FRAMEWORK_PACKAGE_ALLOWLIST } from '../core/addon/addon-package.service.js'
16
-
17
- // ── Module-level mock ─────────────────────────────────────────────────────────
18
- // Must be hoisted before any import that resolves bulk-update-coordinator.
19
- // Uses a real class so `new BulkUpdateCoordinator(...)` works; the instance
20
- // methods are vi.fn stubs shared across all instances created in a test.
21
- const _startFn = vi.fn()
22
- const _getFn = vi.fn()
23
- const _cancelFn = vi.fn()
24
- const _listFn = vi.fn()
25
-
26
- vi.mock('../api/core/bulk-update-coordinator.js', () => {
27
- class MockBulkUpdateCoordinator {
28
- start = _startFn
29
- get = _getFn
30
- cancel = _cancelFn
31
- list = _listFn
32
- }
33
- return { BulkUpdateCoordinator: MockBulkUpdateCoordinator }
34
- })
35
-
36
- // ── Imports that depend on the mocked modules ─────────────────────────────────
37
- import { buildAddonsProvider } from '../api/core/cap-providers.js'
38
- import { makeCtx } from './cap-routers/harness.js'
39
-
40
- // ── Helpers ───────────────────────────────────────────────────────────────────
41
-
42
- function makeLogger() {
43
- const logger = {
44
- info: vi.fn(),
45
- warn: vi.fn(),
46
- error: vi.fn(),
47
- debug: vi.fn(),
48
- trace: vi.fn(),
49
- fatal: vi.fn(),
50
- scope: vi.fn(),
51
- child: vi.fn(),
52
- }
53
- // scope returns a scoped logger with the same shape
54
- logger.scope.mockReturnValue(logger)
55
- logger.child.mockReturnValue(logger)
56
- return logger
57
- }
58
-
59
- type StubStash = {
60
- start: ReturnType<typeof vi.fn>
61
- get: ReturnType<typeof vi.fn>
62
- cancel: ReturnType<typeof vi.fn>
63
- list: ReturnType<typeof vi.fn>
64
- }
65
-
66
- function getCoordinatorStubs(): StubStash {
67
- // The module-level fn references _startFn etc., shared across all mock instances.
68
- return {
69
- start: _startFn,
70
- get: _getFn,
71
- cancel: _cancelFn,
72
- list: _listFn,
73
- }
74
- }
75
-
76
- interface ProviderEnv {
77
- readonly provider: IAddonsProvider
78
- readonly psMock: Record<string, ReturnType<typeof vi.fn>>
79
- }
80
-
81
- function createProviderEnv(): ProviderEnv {
82
- const psMock: Record<string, ReturnType<typeof vi.fn>> = {
83
- getRollbackablePackages: vi.fn().mockReturnValue(new Set()),
84
- getAddonHealthSnapshot: vi.fn().mockReturnValue([]),
85
- listAllAddons: vi.fn().mockReturnValue([]),
86
- listInstalled: vi.fn().mockReturnValue([]),
87
- installAndLoad: vi.fn().mockResolvedValue({ success: true }),
88
- installFromWorkspaceAndLoad: vi.fn().mockResolvedValue({ success: true }),
89
- isWorkspaceAvailable: vi.fn().mockResolvedValue(false),
90
- listWorkspacePackages: vi.fn().mockResolvedValue([]),
91
- uninstallAndReload: vi.fn().mockResolvedValue({ success: true }),
92
- reloadPackages: vi.fn().mockResolvedValue({ success: true }),
93
- searchNpm: vi.fn().mockResolvedValue([]),
94
- checkUpdates: vi.fn().mockResolvedValue([]),
95
- checkUpdatesForInstalled: vi.fn().mockResolvedValue([]),
96
- updatePackage: vi.fn().mockResolvedValue({ success: true }),
97
- rollbackPackage: vi.fn().mockResolvedValue({ success: true }),
98
- restartServer: vi.fn().mockResolvedValue({ success: true }),
99
- listFrameworkPackages: vi.fn().mockResolvedValue([]),
100
- getPackageVersions: vi.fn().mockResolvedValue([]),
101
- getAutoUpdateSettings: vi.fn().mockResolvedValue({ channel: 'stable', intervalSeconds: 3600 }),
102
- setAutoUpdateSettings: vi.fn().mockResolvedValue({ success: true }),
103
- getAddonAutoUpdate: vi.fn().mockResolvedValue({ channel: 'inherit' }),
104
- setAddonAutoUpdate: vi.fn().mockResolvedValue({ success: true }),
105
- updateFrameworkPackage: vi.fn().mockResolvedValue({
106
- packageName: '@camstack/types',
107
- fromVersion: '0.1.38',
108
- toVersion: '0.1.40',
109
- restartingAt: Date.now() + 500,
110
- }),
111
- packPackage: vi.fn().mockResolvedValue({ buffer: Buffer.alloc(0), version: '1.0.0' }),
112
- }
113
-
114
- const arMock = {
115
- listAddons: vi.fn().mockReturnValue([]),
116
- listAllAddons: vi.fn().mockReturnValue([]),
117
- getAddonHealthSnapshot: vi.fn().mockReturnValue([]),
118
- getCapabilityRegistry: vi.fn().mockReturnValue({
119
- listCapabilities: vi.fn().mockReturnValue([]),
120
- }),
121
- getCustomActionRegistry: vi.fn().mockReturnValue({
122
- resolve: vi.fn().mockReturnValue(null),
123
- }),
124
- restartAddon: vi.fn().mockResolvedValue({ success: true }),
125
- retryAddonLoad: vi.fn().mockResolvedValue({ success: true }),
126
- }
127
-
128
- const lsMock = {
129
- createLogger: vi.fn().mockReturnValue(makeLogger()),
130
- query: vi.fn().mockResolvedValue([]),
131
- subscribe: vi.fn().mockReturnValue(() => {}),
132
- }
133
-
134
- const moleculerMock = {
135
- broker: {
136
- call: vi.fn().mockResolvedValue({}),
137
- },
138
- }
139
-
140
- const configServiceMock = {}
141
-
142
- const ebMock = {
143
- emit: vi.fn(),
144
- subscribe: vi.fn().mockReturnValue(() => {}),
145
- }
146
-
147
- const ctx = makeCtx('admin')
148
-
149
- const provider = buildAddonsProvider(
150
- arMock as never,
151
- psMock as never,
152
- lsMock as never,
153
- moleculerMock as never,
154
- configServiceMock as never,
155
- ctx,
156
- ebMock as never,
157
- )
158
-
159
- return { provider, psMock }
160
- }
161
-
162
- // ── Tests ─────────────────────────────────────────────────────────────────────
163
-
164
- describe('buildAddonsProvider — BulkUpdateCoordinator delegation', () => {
165
- let env: ProviderEnv
166
- let stubs: StubStash
167
-
168
- beforeEach(() => {
169
- vi.clearAllMocks()
170
- env = createProviderEnv()
171
- stubs = getCoordinatorStubs()
172
- })
173
-
174
- it('startBulkUpdate delegates to coordinator.start with same args and returns its value', async () => {
175
- const returnValue = { id: 'bulk-abc-123' }
176
- stubs.start.mockReturnValue(returnValue)
177
-
178
- const input = {
179
- nodeId: 'hub',
180
- items: [
181
- { name: '@camstack/addon-stream-broker', version: '1.2.3', isSystem: false },
182
- { name: '@camstack/types', version: '0.1.40', isSystem: true },
183
- ] as const,
184
- }
185
-
186
- const result = await env.provider.startBulkUpdate(input)
187
-
188
- expect(stubs.start).toHaveBeenCalledOnce()
189
- expect(stubs.start).toHaveBeenCalledWith(input)
190
- expect(result).toEqual(returnValue)
191
- })
192
-
193
- it('cancelBulkUpdate delegates to coordinator.cancel with the id and returns its value', async () => {
194
- const returnValue = { cancelled: true }
195
- stubs.cancel.mockReturnValue(returnValue)
196
-
197
- const result = await env.provider.cancelBulkUpdate({ id: 'bulk-xyz' })
198
-
199
- expect(stubs.cancel).toHaveBeenCalledOnce()
200
- expect(stubs.cancel).toHaveBeenCalledWith('bulk-xyz')
201
- expect(result).toEqual(returnValue)
202
- })
203
-
204
- it('getBulkUpdateState delegates to coordinator.get with the id and returns its value', async () => {
205
- const mockState = {
206
- id: 'bulk-abc',
207
- nodeId: 'hub',
208
- startedAtMs: 1000,
209
- total: 2,
210
- completed: 1,
211
- failed: 0,
212
- current: null,
213
- phase: 'regular' as const,
214
- cancelled: false,
215
- items: [],
216
- }
217
- stubs.get.mockReturnValue(mockState)
218
-
219
- const result = await env.provider.getBulkUpdateState({ id: 'bulk-abc' })
220
-
221
- expect(stubs.get).toHaveBeenCalledOnce()
222
- expect(stubs.get).toHaveBeenCalledWith('bulk-abc')
223
- expect(result).toEqual(mockState)
224
- })
225
-
226
- it('getBulkUpdateState returns null when coordinator.get returns null', async () => {
227
- stubs.get.mockReturnValue(null)
228
-
229
- const result = await env.provider.getBulkUpdateState({ id: 'unknown-id' })
230
-
231
- expect(result).toBeNull()
232
- })
233
-
234
- it('listActiveBulkUpdates delegates to coordinator.list with nodeId and returns its value', async () => {
235
- const mockList = [
236
- {
237
- id: 'bulk-1',
238
- nodeId: 'hub',
239
- startedAtMs: 1000,
240
- total: 1,
241
- completed: 0,
242
- failed: 0,
243
- current: 'pkg-a',
244
- phase: 'regular' as const,
245
- cancelled: false,
246
- items: [],
247
- },
248
- ]
249
- stubs.list.mockReturnValue(mockList)
250
-
251
- const result = await env.provider.listActiveBulkUpdates({ nodeId: 'hub' })
252
-
253
- expect(stubs.list).toHaveBeenCalledOnce()
254
- expect(stubs.list).toHaveBeenCalledWith('hub')
255
- expect(result).toEqual(mockList)
256
- })
257
-
258
- it('listActiveBulkUpdates passes undefined when nodeId is omitted', async () => {
259
- stubs.list.mockReturnValue([])
260
-
261
- await env.provider.listActiveBulkUpdates({})
262
-
263
- expect(stubs.list).toHaveBeenCalledWith(undefined)
264
- })
265
- })
266
-
267
- describe('buildAddonsProvider — listUpdates isSystem field', () => {
268
- let env: ProviderEnv
269
-
270
- beforeEach(() => {
271
- vi.clearAllMocks()
272
- env = createProviderEnv()
273
- })
274
-
275
- it('adds isSystem: true for packages in FRAMEWORK_PACKAGE_ALLOWLIST', async () => {
276
- const systemPkg = FRAMEWORK_PACKAGE_ALLOWLIST[0]!
277
- env.psMock['checkUpdates']!.mockResolvedValue([
278
- {
279
- name: systemPkg,
280
- currentVersion: '0.1.38',
281
- latestVersion: '0.1.40',
282
- category: 'core',
283
- requiresRestart: true,
284
- },
285
- ])
286
-
287
- const result = await env.provider.listUpdates({ nodeId: 'hub' })
288
-
289
- expect(result).toHaveLength(1)
290
- expect(result[0]!.name).toBe(systemPkg)
291
- expect(result[0]!.isSystem).toBe(true)
292
- })
293
-
294
- it('adds isSystem: false for non-framework packages', async () => {
295
- env.psMock['checkUpdates']!.mockResolvedValue([
296
- {
297
- name: '@camstack/addon-stream-broker',
298
- currentVersion: '1.0.0',
299
- latestVersion: '1.0.1',
300
- category: 'addon',
301
- requiresRestart: false,
302
- },
303
- ])
304
-
305
- const result = await env.provider.listUpdates({ nodeId: 'hub' })
306
-
307
- expect(result).toHaveLength(1)
308
- expect(result[0]!.isSystem).toBe(false)
309
- })
310
-
311
- it('handles mixed system and non-system packages correctly', async () => {
312
- env.psMock['checkUpdates']!.mockResolvedValue([
313
- {
314
- name: '@camstack/types',
315
- currentVersion: '0.1.38',
316
- latestVersion: '0.1.40',
317
- category: 'core',
318
- requiresRestart: true,
319
- },
320
- {
321
- name: '@camstack/addon-foo',
322
- currentVersion: '1.0.0',
323
- latestVersion: '1.0.1',
324
- category: 'addon',
325
- requiresRestart: false,
326
- },
327
- ])
328
-
329
- const result = await env.provider.listUpdates({ nodeId: 'hub' })
330
-
331
- expect(result).toHaveLength(2)
332
- const typesRow = result.find((r) => r.name === '@camstack/types')
333
- const fooRow = result.find((r) => r.name === '@camstack/addon-foo')
334
- expect(typesRow?.isSystem).toBe(true)
335
- expect(fooRow?.isSystem).toBe(false)
336
- })
337
-
338
- it('all FRAMEWORK_PACKAGE_ALLOWLIST members get isSystem: true', async () => {
339
- env.psMock['checkUpdates']!.mockResolvedValue(
340
- FRAMEWORK_PACKAGE_ALLOWLIST.map((name) => ({
341
- name,
342
- currentVersion: '0.1.0',
343
- latestVersion: '0.1.1',
344
- category: 'core',
345
- requiresRestart: true,
346
- })),
347
- )
348
-
349
- const result = await env.provider.listUpdates({ nodeId: 'hub' })
350
-
351
- expect(result).toHaveLength(FRAMEWORK_PACKAGE_ALLOWLIST.length)
352
- for (const row of result) {
353
- expect(row.isSystem).toBe(true)
354
- }
355
- })
356
- })
357
-
358
- describe('buildAddonsProvider — updateFrameworkPackage deferRestart propagation', () => {
359
- let env: ProviderEnv
360
-
361
- beforeEach(() => {
362
- vi.clearAllMocks()
363
- env = createProviderEnv()
364
- })
365
-
366
- it('forwards deferRestart: true to the service', async () => {
367
- await env.provider.updateFrameworkPackage({
368
- packageName: '@camstack/types',
369
- version: '0.1.40',
370
- deferRestart: true,
371
- })
372
-
373
- expect(env.psMock['updateFrameworkPackage']).toHaveBeenCalledOnce()
374
- const callArg = env.psMock['updateFrameworkPackage']!.mock.calls[0]![0] as Record<
375
- string,
376
- unknown
377
- >
378
- expect(callArg['deferRestart']).toBe(true)
379
- })
380
-
381
- it('forwards deferRestart: false to the service', async () => {
382
- await env.provider.updateFrameworkPackage({
383
- packageName: '@camstack/types',
384
- version: '0.1.40',
385
- deferRestart: false,
386
- })
387
-
388
- const callArg = env.psMock['updateFrameworkPackage']!.mock.calls[0]![0] as Record<
389
- string,
390
- unknown
391
- >
392
- expect(callArg['deferRestart']).toBe(false)
393
- })
394
-
395
- it('does not include deferRestart when it is omitted', async () => {
396
- await env.provider.updateFrameworkPackage({
397
- packageName: '@camstack/types',
398
- version: '0.1.40',
399
- })
400
-
401
- const callArg = env.psMock['updateFrameworkPackage']!.mock.calls[0]![0] as Record<
402
- string,
403
- unknown
404
- >
405
- // Either undefined or not present — both are acceptable
406
- expect(callArg['deferRestart']).toBeUndefined()
407
- })
408
- })