@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
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoggingService = void 0;
4
+ const core_1 = require("@camstack/core");
5
+ const types_1 = require("@camstack/types");
6
+ /** Baseline tags every hub-local logger gets, so console output never
7
+ * falls back to `?` for the agent slot. Hub-local addons already
8
+ * re-tag with their addonId; this ensures non-addon scopes (core
9
+ * services like `AddonRegistry`, `StreamProbeService`, `moleculer`)
10
+ * render as `hub` in the agent column.
11
+ *
12
+ * `pid` is the hub renderer's own OS pid. Entries forwarded from
13
+ * forked workers via `$hub.log` carry their own `tags.pid` which
14
+ * wins over this baseline (right-biased merge in `writeFromWorker`). */
15
+ const HUB_BASELINE_TAGS = { agentId: 'hub', nodeId: 'hub', pid: process.pid };
16
+ class LoggingService extends core_1.LogManager {
17
+ /**
18
+ * Device-name cache consulted by the formatter when a log line
19
+ * carries `tags.deviceId` but no explicit `deviceName`. Populated
20
+ * by `setDeviceNames` whenever device-manager emits registered /
21
+ * updated / removed events. Missing entries fall back to `#<id>`.
22
+ */
23
+ deviceNames = new Map();
24
+ constructor(configService) {
25
+ // The log buffer is now partitioned per addonId (see PartitionedLogBuffer):
26
+ // this value caps EACH addon's bucket, not the total. A chatty addon evicts
27
+ // only its own lines, so quiet addons (e.g. a HomeAssistant `image` entity)
28
+ // keep their sparse history. `eventBus.ringBufferSize` still sizes the
29
+ // separate system-event ring; logs get their own per-addon cap.
30
+ const perAddonCapacity = configService.get('eventBus.perAddonLogBufferSize') ?? 5000;
31
+ super(perAddonCapacity);
32
+ // Enriches every emitted LogEntry with `tags.deviceName` before
33
+ // destinations / subscribers see it — works across bundled copies
34
+ // of `@camstack/core` (addon packages) because the mutation
35
+ // happens upstream of their formatters.
36
+ this.setDeviceNameLookup((id) => this.deviceNames.get(id) ?? null);
37
+ }
38
+ /** Bulk-refresh from device-manager snapshot. Replaces every entry. */
39
+ setDeviceNames(entries) {
40
+ this.deviceNames.clear();
41
+ for (const { id, name } of entries) {
42
+ if (typeof id === 'number' &&
43
+ Number.isFinite(id) &&
44
+ typeof name === 'string' &&
45
+ name.length > 0) {
46
+ this.deviceNames.set(id, name);
47
+ }
48
+ }
49
+ }
50
+ /** Incremental update — called from DeviceRegistered / DeviceUpdated. */
51
+ upsertDeviceName(id, name) {
52
+ if (!Number.isFinite(id))
53
+ return;
54
+ if (typeof name === 'string' && name.length > 0)
55
+ this.deviceNames.set(id, name);
56
+ else
57
+ this.deviceNames.delete(id);
58
+ }
59
+ /** Drop on DeviceRemoved. */
60
+ removeDeviceName(id) {
61
+ this.deviceNames.delete(id);
62
+ }
63
+ /**
64
+ * Subscribe to `device.*` events so the cache stays live: every
65
+ * DeviceRegistered / updated emit carries `{deviceId, name}` — we
66
+ * upsert, and DeviceUnregistered clears. Call once at boot.
67
+ */
68
+ attachDeviceNameStream(eventBus) {
69
+ const selfLogger = this.createLogger('logging').withTags({ addonId: 'logging' });
70
+ eventBus.subscribe({ category: types_1.EventCategory.DeviceRegistered }, (event) => {
71
+ const data = event.data;
72
+ if (data && typeof data.deviceId === 'number') {
73
+ this.upsertDeviceName(data.deviceId, data.name);
74
+ selfLogger.info('device-name cache upserted', {
75
+ meta: {
76
+ deviceId: data.deviceId,
77
+ name: data.name ?? null,
78
+ cacheSize: this.deviceNames.size,
79
+ },
80
+ });
81
+ }
82
+ });
83
+ eventBus.subscribe({ category: types_1.EventCategory.DeviceUnregistered }, (event) => {
84
+ const data = event.data;
85
+ if (data && typeof data.deviceId === 'number')
86
+ this.removeDeviceName(data.deviceId);
87
+ });
88
+ }
89
+ /**
90
+ * Override — every logger created hub-side comes pre-tagged with
91
+ * `agentId: 'hub'`. Callers that need per-addon identity chain
92
+ * `.withTags({ addonId })` on top (the merge is right-biased, so
93
+ * the explicit tag wins).
94
+ */
95
+ createLogger(scope) {
96
+ return super.createLogger(scope).withTags(HUB_BASELINE_TAGS);
97
+ }
98
+ /**
99
+ * Write a log entry received from a forked worker / remote agent.
100
+ * Called by the `$hub.log` action and `log-receiver.ingest` action.
101
+ *
102
+ * Tags propagated by the worker (including `deviceId`, `deviceName`,
103
+ * `integrationId`, `streamId`, etc.) are preserved via `withTags`;
104
+ * baseline tags (`addonId`, `nodeId`, `agentId`) are always ensured
105
+ * even if the worker didn't set them explicitly.
106
+ */
107
+ writeFromWorker(entry) {
108
+ // Scope is a single optional sub-component label; addon/node identity
109
+ // lives in tags, not in scope. Pass through whatever the worker set.
110
+ let logger = this.createLogger(entry.scope);
111
+ const nodeId = entry.nodeId;
112
+ const agentId = nodeId?.includes('/') ? nodeId.split('/')[0] : nodeId;
113
+ const mergedTags = {
114
+ ...entry.tags,
115
+ addonId: entry.addonId,
116
+ ...(nodeId !== undefined ? { nodeId } : {}),
117
+ ...(agentId !== undefined ? { agentId } : {}),
118
+ };
119
+ logger = logger.withTags(mergedTags);
120
+ const level = entry.level;
121
+ const extras = entry.meta !== undefined ? { meta: entry.meta } : undefined;
122
+ if (typeof logger[level] === 'function') {
123
+ logger[level](entry.message, extras);
124
+ }
125
+ else {
126
+ logger.info(entry.message, extras);
127
+ }
128
+ }
129
+ }
130
+ exports.LoggingService = LoggingService;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ScopedLogger = void 0;
4
+ // Re-export from @camstack/core
5
+ var core_1 = require("@camstack/core");
6
+ Object.defineProperty(exports, "ScopedLogger", { enumerable: true, get: function () { return core_1.ScopedLogger; } });
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildCapCallFn = buildCapCallFn;
4
+ /** Extract a numeric `deviceId` routing hint out of arbitrary method args. */
5
+ function extractDeviceId(params) {
6
+ if (params === null || typeof params !== 'object')
7
+ return undefined;
8
+ const raw = Reflect.get(params, 'deviceId');
9
+ return typeof raw === 'number' ? raw : undefined;
10
+ }
11
+ /**
12
+ * Build the `CallFn` (`(method, params, targetNodeId?) => Promise`) for one
13
+ * registered provider. See module docs for the routing rationale.
14
+ */
15
+ function buildCapCallFn(deps) {
16
+ return async (method, params, targetNodeId) => {
17
+ const deviceId = extractDeviceId(params);
18
+ // ── Hub-local child: route per-child over UDS (collection-safe — keyed by
19
+ // the specific child, not by capName which would collapse a collection
20
+ // cap onto the first child). NEVER fall back to Moleculer: a hub-local
21
+ // child is not a Moleculer service, so a broker call would wait the full
22
+ // discovery timeout for a node that never appears. If the child isn't
23
+ // currently providing the cap, fail fast.
24
+ if (deps.udsChildId !== null && targetNodeId === undefined) {
25
+ const registry = deps.getLocalChildRegistry();
26
+ if (registry !== null && registry.childProvides(deps.udsChildId, deps.capName, deviceId)) {
27
+ deps.onUdsRoute?.(deps.capName);
28
+ const input = {
29
+ capName: deps.capName,
30
+ method,
31
+ args: params,
32
+ ...(deviceId !== undefined ? { deviceId } : {}),
33
+ };
34
+ return registry.callCapOnChild(deps.udsChildId, input);
35
+ }
36
+ throw new Error(`hub-local child "${deps.udsChildId}" does not currently provide cap "${deps.capName}"`);
37
+ }
38
+ // ── Agent-hosted or explicit remote: delegate to the unified resolver.
39
+ const resolver = deps.getResolver();
40
+ if (resolver !== null) {
41
+ const route = resolver.resolveCapRoute(deps.capName, {
42
+ nodeId: targetNodeId ?? deps.nodeId,
43
+ ...(deviceId !== undefined ? { deviceId } : {}),
44
+ });
45
+ return resolver.dispatch(route, method, params);
46
+ }
47
+ // ── Pre-init window (resolver not yet constructed): legacy Moleculer call.
48
+ return deps.legacyBrokerCall(method, params, targetNodeId ?? deps.nodeId);
49
+ };
50
+ }
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ /**
3
+ * Adapter factories that bridge the server-side registry/service state into the
4
+ * narrow interfaces that CapRouteResolver (in @camstack/kernel) requires.
5
+ *
6
+ * Layer note: this file is in server/backend and may import server-side types.
7
+ * The resolver itself (in @camstack/kernel) must NOT import from here —
8
+ * it depends only on the narrow interfaces (NodeCapAuthority, InProcessProviderLookup)
9
+ * defined in the kernel. These factories are the wiring adapters.
10
+ *
11
+ * nodeIsAgent format rule (from agent-registry.service.ts:74-77):
12
+ * hub → 'hub' → not an agent
13
+ * hub child → 'hub/<runnerId>' → not an agent
14
+ * agent → bare id with no '/' → agent
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.createNodeCapAuthority = createNodeCapAuthority;
18
+ exports.createInProcessProviderLookup = createInProcessProviderLookup;
19
+ /**
20
+ * Build a NodeCapAuthority backed by a HubNodeRegistry.
21
+ *
22
+ * nodeIsAgent rule: a node is an agent when its id is not 'hub' and does not
23
+ * contain '/' (hub children are `hub/<runnerId>`; agents are bare ids).
24
+ *
25
+ * nodeOnline: uses registry membership — per CLAUDE.md "the registry is the
26
+ * union of registerNode manifests minus disconnected nodes" because
27
+ * `removeNode` is called on `$node.disconnected`. Registry membership is the
28
+ * cleanest, cast-free liveness check.
29
+ *
30
+ * getAgentChildId: always returns null — the hub cannot resolve which forked
31
+ * child under an agent provides a cap (the agent flattens its subtree into
32
+ * one merged manifest). The agent resolves its own child locally (Task 6).
33
+ */
34
+ function createNodeCapAuthority(nodeRegistry, resolver) {
35
+ return {
36
+ nodeKnowsCap(nodeId, capName) {
37
+ // Check system (manifest) caps first
38
+ const manifest = nodeRegistry.getNodeManifest(nodeId);
39
+ if (manifest !== undefined &&
40
+ manifest.some((addon) => addon.capabilities.includes(capName))) {
41
+ return true;
42
+ }
43
+ // Also check device-scoped native caps — these are NOT in the addon manifest
44
+ const nativeEntries = nodeRegistry.listNativeCapEntries?.() ?? [];
45
+ return nativeEntries.some((n) => n.nodeId === nodeId && n.capName === capName);
46
+ },
47
+ getAddonId(nodeId, capName) {
48
+ // Check system (manifest) caps first
49
+ const manifest = nodeRegistry.getNodeManifest(nodeId);
50
+ if (manifest !== undefined) {
51
+ const manifestAddons = manifest
52
+ .filter((addon) => addon.capabilities.includes(capName))
53
+ .map((addon) => addon.addonId);
54
+ if (manifestAddons.length > 0) {
55
+ // Per-node override / global-default resolution, constrained to what
56
+ // the node actually hosts. Falls back to the first manifest match.
57
+ const resolved = resolver?.resolveSingleton(capName, nodeId) ?? null;
58
+ if (resolved !== null && manifestAddons.includes(resolved))
59
+ return resolved;
60
+ return manifestAddons[0] ?? null;
61
+ }
62
+ }
63
+ // Check device-scoped native caps (unchanged path)
64
+ const nativeEntries = nodeRegistry.listNativeCapEntries?.() ?? [];
65
+ const nat = nativeEntries.find((n) => n.nodeId === nodeId && n.capName === capName);
66
+ return nat?.addonId ?? null;
67
+ },
68
+ nodeIsAgent(nodeId) {
69
+ return nodeId !== 'hub' && !nodeId.includes('/');
70
+ },
71
+ nodeOnline(nodeId) {
72
+ // O(1) Map lookup — registry membership is the authoritative liveness
73
+ // check: HubNodeRegistry.removeNode is called on $node.disconnected,
74
+ // so a defined manifest means the node is connected.
75
+ return nodeRegistry.getNodeManifest(nodeId) !== undefined;
76
+ },
77
+ listNodeIds() {
78
+ return nodeRegistry.listNodeIds();
79
+ },
80
+ getAgentChildId(_agentNodeId, _capName) {
81
+ // The hub cannot resolve the agent's child — the agent resolves locally (Task 6).
82
+ return null;
83
+ },
84
+ isNativeCap(nodeId, capName, deviceId) {
85
+ const nativeEntries = nodeRegistry.listNativeCapEntries?.() ?? [];
86
+ if (deviceId !== undefined) {
87
+ return nativeEntries.some((n) => n.nodeId === nodeId && n.capName === capName && n.deviceId === deviceId);
88
+ }
89
+ return nativeEntries.some((n) => n.nodeId === nodeId && n.capName === capName);
90
+ },
91
+ };
92
+ }
93
+ // ---------------------------------------------------------------------------
94
+ // createInProcessProviderLookup
95
+ // ---------------------------------------------------------------------------
96
+ /**
97
+ * Build an InProcessProviderLookup backed by a CapabilityService.
98
+ *
99
+ * Cast-free design: `getSingleton<Record<string, unknown>>` makes the provider
100
+ * indexable without any `as` casts. `typeof fn === 'function'` narrows to
101
+ * Function (implicit `any` return); calling via `fn.call(provider, args)` is
102
+ * then safe and the result is captured as `unknown`. No `as` casts anywhere.
103
+ */
104
+ function createInProcessProviderLookup(capabilityService) {
105
+ return (capName) => {
106
+ const provider = capabilityService.getSingletonForNode?.(capName, 'hub') ??
107
+ capabilityService.getSingleton(capName);
108
+ if (provider === null || provider === undefined)
109
+ return null;
110
+ const ref = {
111
+ invoke: (method, args) => {
112
+ const fn = provider[method];
113
+ if (typeof fn !== 'function') {
114
+ return Promise.reject(new Error(`method "${method}" not found on cap "${capName}"`));
115
+ }
116
+ const result = fn.call(provider, args);
117
+ return Promise.resolve(result);
118
+ },
119
+ };
120
+ return ref;
121
+ };
122
+ }