@camstack/server 1.1.39 → 1.1.41

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.
@@ -17,10 +17,8 @@ const repl_router_js_1 = require("../core/repl.router.js");
17
17
  const settings_backend_router_js_1 = require("../core/settings-backend.router.js");
18
18
  const stream_probe_router_js_1 = require("../core/stream-probe.router.js");
19
19
  const system_events_router_js_1 = require("../core/system-events.router.js");
20
- const cap_mount_helpers_js_1 = require("./cap-mount-helpers.js");
21
20
  const cap_router_runtime_js_1 = require("./cap-router-runtime.js");
22
21
  const client_ip_js_1 = require("./client-ip.js");
23
- const generated_cap_routers_1 = require("./generated-cap-routers");
24
22
  const trpc_middleware_1 = require("./trpc.middleware");
25
23
  /**
26
24
  * Merge the server-read User-Agent into a signaling call's
@@ -67,15 +65,18 @@ function wrapWebrtcSessionProviderWithRelay(provider, ctx) {
67
65
  };
68
66
  }
69
67
  /**
70
- * Build the service-backed provider factory map (BIG PLAN 2). Caps marked
71
- * `mount: { kind: 'service-backed' }` have NO addon-registered provider
72
- * the provider is composed from backend services. The runtime builder
73
- * resolves them through this map (keyed by cap NAME) instead of the
74
- * registry, keeping backend composition in `@camstack/server` (the
75
- * self-sufficiency invariant `@camstack/system` never touches a backend
68
+ * Build the `server-provided` provider factory map (BIG PLAN 2). Caps marked
69
+ * `mount: { kind: 'server-provided' }` have their provider supplied by the
70
+ * server, keyed by cap NAME. The factory either composes backend services
71
+ * (`system`, `nodes`, `integrations`, `addons`, `network-quality`, `toast`) or
72
+ * transforms a registry provider (`webrtc-session` wraps the broker to inject
73
+ * the request User-Agent). The runtime builder mounts the route from the live
74
+ * def schemas and resolves the provider through this map instead of the
75
+ * registry — keeping backend composition in `@camstack/server` (the
76
+ * self-sufficiency invariant: `@camstack/system` never touches a backend
76
77
  * service). Each factory receives the per-request tRPC `ctx`.
77
78
  */
78
- function buildServiceProviders(services) {
79
+ function buildServerProviders(services) {
79
80
  const wrap = (fn) => (ctx) => fn(ctx);
80
81
  return {
81
82
  'network-quality': wrap(() => (0, cap_providers_js_1.buildNetworkQualityProvider)(services.networkQualityService)),
@@ -84,6 +85,15 @@ function buildServiceProviders(services) {
84
85
  integrations: wrap(() => (0, cap_providers_js_1.buildIntegrationsProvider)(services.addonRegistry, services.eventBus, services.loggingService, services.capabilityRegistry)),
85
86
  nodes: wrap(() => (0, cap_providers_js_1.buildNodesProvider)(services.agentRegistry, services.moleculer, services.addonRegistry)),
86
87
  addons: wrap((ctx) => (0, cap_providers_js_1.buildAddonsProvider)(services.addonRegistry, services.addonPackageService, services.loggingService, services.moleculer, services.configService, ctx)),
88
+ // webrtc-session — the resolved broker singleton, wrapped per request to
89
+ // inject the server-read User-Agent into signaling attribution (the broker
90
+ // is a forked addon that can't see the HTTP request). Cross-node (agent-
91
+ // hosted broker) calls route through the generic remote-proxy leg and skip
92
+ // this local factory, exactly as the retired custom mount did.
93
+ 'webrtc-session': wrap((ctx) => {
94
+ const provider = services.capabilityRegistry?.getSingleton('webrtc-session') ?? null;
95
+ return provider ? wrapWebrtcSessionProviderWithRelay(provider, ctx) : null;
96
+ }),
87
97
  };
88
98
  }
89
99
  /**
@@ -102,11 +112,10 @@ function buildServiceProviders(services) {
102
112
  * full procedure inference and `generate-api-types.ts` resolves the same
103
113
  * expanded type as before.
104
114
  *
105
- * Override-by-spread is preserved: spread the dynamic caps first, then the
106
- * hand-written core routers + the two `custom`-mount overrides
107
- * (snapshot-provider's probe fan-out, webrtc-session's relay enrichment),
108
- * which the generic builder intentionally leaves unmounted for the server
109
- * to fill.
115
+ * Spread order: the dynamic caps first, then the hand-written core (non-cap)
116
+ * routers. Every cap including the former `custom` ones — is now built by the
117
+ * runtime builder; the server only supplies `server-provided` provider factories
118
+ * (`buildServerProviders`), never a hand-written cap-router override.
110
119
  */
111
120
  function buildCapabilityRouters(services) {
112
121
  // ── Dynamic cap routers (value) → static cap-router map (type). ──────
@@ -120,13 +129,15 @@ function buildCapabilityRouters(services) {
120
129
  const dynamicCaps = (0, cap_router_runtime_js_1.buildRuntimeCapRouters)({
121
130
  capabilityRegistry: services.capabilityRegistry,
122
131
  moleculer: services.moleculer,
123
- serviceProviders: buildServiceProviders(services),
132
+ serverProviders: buildServerProviders(services),
124
133
  });
125
134
  return {
126
- // ── Runtime-built cap routers: every cap whose mount is
127
- // `singleton` / `collection` / `device-native` / `service-backed`
128
- // / `hub-only`. `custom` + `skip` caps are NOT here `skip` is
129
- // never mounted; `custom` is filled by the overrides below. ──────
135
+ // ── Runtime-built cap routers: EVERY cap whose mount is
136
+ // `singleton` / `collection` / `device-native` / `server-provided`
137
+ // / `hub-only`. Only `skip` caps are excluded (never mounted). The
138
+ // former `custom` caps are gone: `snapshot-provider` was dead
139
+ // (deleted); `webrtc-session` is now a `server-provided` cap resolved
140
+ // by `buildServerProviders`. ──────
130
141
  ...dynamicCaps,
131
142
  // ── Non-cap (core) routers — hand-written, single-impl ──────────
132
143
  notifications: (0, notifications_router_js_1.createNotificationsRouter)(services.notificationService),
@@ -153,35 +164,6 @@ function buildCapabilityRouters(services) {
153
164
  // offline-node history (Track A "Forget node"); read side is push-only.
154
165
  clusterNodes: (0, cluster_nodes_router_js_1.createClusterNodesRouter)(services.agentRegistry),
155
166
  auth: (0, auth_router_js_1.createAuthRouter)(services.authService, services.capabilityRegistry),
156
- // ── Cap overrides: `mount: { kind: 'custom' }` ──────────────────
157
- // `snapshot-provider.supportsDevice` is an OR across providers;
158
- // `getSnapshot` picks the first one that claims the device. The
159
- // generic builder's first-provider/concat collection resolver can't
160
- // model this — we hand-write the probe + fan-out logic.
161
- snapshotProvider: (0, generated_cap_routers_1.createCapRouter_snapshotProvider)((_ctx) => {
162
- const reg = services.capabilityRegistry;
163
- if (!reg)
164
- return null;
165
- const providers = reg.getCollection('snapshot-provider');
166
- if (!providers || providers.length === 0)
167
- return null;
168
- const supportsDevice = (0, cap_mount_helpers_js_1.anySupports)(providers, 'supportsDevice');
169
- const getSnapshot = (0, cap_mount_helpers_js_1.firstSupported)(providers, 'supportsDevice', 'getSnapshot');
170
- return { supportsDevice, getSnapshot };
171
- }),
172
- // `webrtc-session` — server-detected remote → relay-only. The broker
173
- // (a forked addon) can't see the HTTP request, so it can't tell a LAN
174
- // viewer from a remote one. We override `getProvider` to return a
175
- // per-request provider whose `createSession` carries a server-computed
176
- // `relayOnly` flag derived from the client IP in `ctx.req`. Remote
177
- // (CGNAT/4G) viewers force TURN-relay-only ICE; LAN viewers keep the
178
- // direct host/srflx path. All other methods delegate straight through,
179
- // and the cross-node remote-proxy routing is preserved (forked/agent-
180
- // hosted brokers).
181
- webrtcSession: (0, generated_cap_routers_1.createCapRouter_webrtcSession)((ctx) => {
182
- const provider = services.capabilityRegistry?.getSingleton('webrtc-session') ?? null;
183
- return provider ? wrapWebrtcSessionProviderWithRelay(provider, ctx) : null;
184
- }, (capName, nodeId) => services.moleculer.createCapabilityProxy(capName, nodeId)),
185
167
  // NOT MOUNTED — `mount: { kind: 'skip' }` legacy provider shapes
186
168
  // (positional args / sync returns) that don't match the codegen
187
169
  // routers' {input}-object + Promise<T> contract. The runtime builder
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.AddonPackageService = exports.SYSTEM_PACKAGE = void 0;
36
+ exports.AddonPackageService = exports.FRAMEWORK_PACKAGES = exports.SYSTEM_PACKAGE = void 0;
37
37
  exports.isFrameworkPackage = isFrameworkPackage;
38
38
  exports.extractTgzStripped = extractTgzStripped;
39
39
  exports.sweepStaleFrameworkBackups = sweepStaleFrameworkBackups;
@@ -49,14 +49,41 @@ const types_1 = require("@camstack/types");
49
49
  const system_1 = require("@camstack/system");
50
50
  const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
51
51
  /**
52
- * The single host-provided framework package. As of 2026-06-22 the framework is
53
- * one bundle: @camstack/system (kernel + core; types/sdk inlined at runtime,
54
- * shm-ring is a private native dep). There is no multi-entry allowlist.
52
+ * The primary host-provided framework package (kernel + core). Kept as a named
53
+ * export because `lifecycle-job-runner` + several tests reference it directly.
55
54
  */
56
55
  exports.SYSTEM_PACKAGE = '@camstack/system';
57
- /** Returns true only for the single host-provided framework package. */
56
+ /**
57
+ * Host-provided framework packages that a `camstack deploy` mirrors into the
58
+ * running hub's live closure via `syncFrameworkDist` (hub-main node_modules +
59
+ * addon-runner overlay) instead of the normal addon-install path, then bounces
60
+ * the server — delivering the new code with NO image rebuild.
61
+ *
62
+ * `@camstack/types` is included so a CAPABILITY change ships live via
63
+ * `camstack deploy packages/types`: the hub-main reads `ALL_CAPABILITY_DEFINITIONS`
64
+ * + `METHOD_ACCESS_MAP` and the runtime cap-router builder reads the cap defs
65
+ * from this single closure copy, so mirroring types' `dist/` refreshes the
66
+ * ENTIRE cap surface (new caps, new methods, AND the per-method auth map)
67
+ * without an image. `@camstack/sdk` rides along as a pure-JS lockstep companion.
68
+ * `@camstack/shm-ring` is deliberately EXCLUDED: it ships a native `.node`
69
+ * prebuild the dist-only mirror cannot rebuild — it must go through the
70
+ * native-aware install path, not this JS-dist swap.
71
+ *
72
+ * Membership is by package NAME, independent of the `camstack.system` manifest
73
+ * flag (`@camstack/types` declares `system: false` yet is a framework package
74
+ * here) — that flag drives Admin-UI grouping; this gate drives live-sync routing.
75
+ */
76
+ exports.FRAMEWORK_PACKAGES = [
77
+ exports.SYSTEM_PACKAGE,
78
+ '@camstack/types',
79
+ '@camstack/sdk',
80
+ ];
81
+ /**
82
+ * Returns true for a host-provided framework package whose `dist/` is mirrored
83
+ * into the live closure by `syncFrameworkDist` (not installed as a normal addon).
84
+ */
58
85
  function isFrameworkPackage(packageName) {
59
- return packageName === exports.SYSTEM_PACKAGE;
86
+ return exports.FRAMEWORK_PACKAGES.includes(packageName);
60
87
  }
61
88
  // ---------------------------------------------------------------------------
62
89
  // Typed JSON helpers
@@ -6,6 +6,7 @@ const node_crypto_1 = require("node:crypto");
6
6
  const system_1 = require("@camstack/system");
7
7
  const types_1 = require("@camstack/types");
8
8
  const cap_router_runtime_js_1 = require("../../api/trpc/cap-router-runtime.js");
9
+ const core_cap_bridge_js_1 = require("../../api/trpc/core-cap-bridge.js");
9
10
  const cap_call_fn_js_1 = require("./cap-call-fn.js");
10
11
  const cap_route_authority_js_1 = require("./cap-route-authority.js");
11
12
  class MoleculerService {
@@ -280,6 +281,16 @@ class MoleculerService {
280
281
  return null;
281
282
  return [];
282
283
  },
284
+ // Hub-core `$`-service discriminant for the general
285
+ // provider-not-yet-registered recovery. A resolver miss on a NON-core
286
+ // cap (any addon-provided system/singleton cap, e.g.
287
+ // `pipeline-orchestrator`) means its broker-less forked provider hasn't
288
+ // registered YET — the unpinned broker fallback is a dead path that
289
+ // 30s-deadlines into `${cap}.${cap}.${method}`. Feeding the handler this
290
+ // predicate lets it retry the resolver + throw a precise error instead.
291
+ // Derived from the already-maintained core-router list, so a new
292
+ // multi-node addon cap is covered with no change here.
293
+ isCoreServiceCap: (capName) => (0, core_cap_bridge_js_1.isCoreServiceCapName)(capName),
283
294
  logger: {
284
295
  warn: (msg, meta) => logger.warn(msg, meta !== null && meta !== undefined
285
296
  ? { meta: meta }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.1.39",
3
+ "version": "1.1.41",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist",