@camstack/server 1.1.41 → 1.1.43

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.
@@ -25,7 +25,6 @@ exports.createCapRouterPrimitives = createCapRouterPrimitives;
25
25
  exports.createCapRouterServices = createCapRouterServices;
26
26
  exports.buildRuntimeCapRouters = buildRuntimeCapRouters;
27
27
  const system_1 = require("@camstack/system");
28
- const types_1 = require("@camstack/types");
29
28
  const server_1 = require("@trpc/server");
30
29
  const cap_mount_helpers_js_1 = require("./cap-mount-helpers.js");
31
30
  const trpc_middleware_js_1 = require("./trpc.middleware.js");
@@ -38,7 +37,7 @@ const trpc_middleware_js_1 = require("./trpc.middleware.js");
38
37
  exports.COLLECTION_ARRAY_METHODS = computeArrayMethods();
39
38
  function computeArrayMethods() {
40
39
  const out = new Map();
41
- for (const def of types_1.ALL_CAPABILITY_DEFINITIONS) {
40
+ for (const def of system_1.ALL_CAPABILITY_DEFINITIONS) {
42
41
  if (def.mode !== 'collection')
43
42
  continue;
44
43
  const names = [];
@@ -46,7 +45,7 @@ function computeArrayMethods() {
46
45
  const m = schema;
47
46
  if (m.kind === 'subscription')
48
47
  continue;
49
- if ((0, types_1.isArrayOutputSchema)(m.output))
48
+ if ((0, system_1.isArrayOutputSchema)(m.output))
50
49
  names.push(name);
51
50
  }
52
51
  if (names.length > 0)
@@ -5006,14 +5006,14 @@ function createCapRouter_pipelineExecutor(getProvider, createRemoteProxy) {
5006
5006
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5007
5007
  return p.setVideoPipelineSteps(methodInput);
5008
5008
  }),
5009
- resetToDefault: trpc_middleware_js_1.adminProcedure
5010
- .input(types_76.pipelineExecutorCapability.methods.resetToDefault.input.loose())
5011
- .output(types_76.pipelineExecutorCapability.methods.resetToDefault.output)
5009
+ clearDeviceOverrides: trpc_middleware_js_1.adminProcedure
5010
+ .input(types_76.pipelineExecutorCapability.methods.clearDeviceOverrides.input.loose())
5011
+ .output(types_76.pipelineExecutorCapability.methods.clearDeviceOverrides.output)
5012
5012
  .mutation(async ({ input, ctx }) => {
5013
5013
  const { nodeId, ...methodInput } = input;
5014
5014
  const p = resolveProvider('pipeline-executor', nodeId, () => getProvider(ctx), createRemoteProxy);
5015
5015
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5016
- return p.resetToDefault(methodInput);
5016
+ return p.clearDeviceOverrides(methodInput);
5017
5017
  }),
5018
5018
  getSchema: trpc_middleware_js_1.protectedProcedure
5019
5019
  .input(zod_1.z.object({ nodeId: zod_1.z.string().optional() }).optional())
@@ -5120,15 +5120,6 @@ function createCapRouter_pipelineExecutor(getProvider, createRemoteProxy) {
5120
5120
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5121
5121
  return p.deleteModel(methodInput);
5122
5122
  }),
5123
- detect: trpc_middleware_js_1.protectedProcedure
5124
- .input(types_76.pipelineExecutorCapability.methods.detect.input.loose())
5125
- .output(types_76.pipelineExecutorCapability.methods.detect.output)
5126
- .query(async ({ input, ctx }) => {
5127
- const { nodeId, ...methodInput } = input;
5128
- const p = resolveProvider('pipeline-executor', nodeId, () => getProvider(ctx), createRemoteProxy);
5129
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5130
- return p.detect(methodInput);
5131
- }),
5132
5123
  runPipeline: trpc_middleware_js_1.protectedProcedure
5133
5124
  .input(types_76.pipelineExecutorCapability.methods.runPipeline.input.loose())
5134
5125
  .output(types_76.pipelineExecutorCapability.methods.runPipeline.output)
@@ -5377,30 +5368,6 @@ function createCapRouter_pipelineOrchestrator(getProvider, _createRemoteProxy) {
5377
5368
  const p = requireCapProvider('pipeline-orchestrator', () => getProvider(ctx));
5378
5369
  return p.getIngestOwner();
5379
5370
  }),
5380
- assignDecoder: trpc_middleware_js_1.adminProcedure
5381
- .input(types_77.pipelineOrchestratorCapability.methods.assignDecoder.input.loose())
5382
- .output(types_77.pipelineOrchestratorCapability.methods.assignDecoder.output)
5383
- .mutation(async ({ input, ctx }) => {
5384
- const p = requireCapProvider('pipeline-orchestrator', () => getProvider(ctx));
5385
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5386
- return p.assignDecoder(input);
5387
- }),
5388
- unassignDecoder: trpc_middleware_js_1.adminProcedure
5389
- .input(types_77.pipelineOrchestratorCapability.methods.unassignDecoder.input.loose())
5390
- .output(types_77.pipelineOrchestratorCapability.methods.unassignDecoder.output)
5391
- .mutation(async ({ input, ctx }) => {
5392
- const p = requireCapProvider('pipeline-orchestrator', () => getProvider(ctx));
5393
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5394
- return p.unassignDecoder(input);
5395
- }),
5396
- getDecoderAssignments: trpc_middleware_js_1.protectedProcedure
5397
- .input(zod_1.z.object({ nodeId: zod_1.z.string().optional() }).optional())
5398
- .output(types_77.pipelineOrchestratorCapability.methods.getDecoderAssignments.output)
5399
- .query(async ({ input, ctx }) => {
5400
- void input;
5401
- const p = requireCapProvider('pipeline-orchestrator', () => getProvider(ctx));
5402
- return p.getDecoderAssignments();
5403
- }),
5404
5371
  assignAudio: trpc_middleware_js_1.adminProcedure
5405
5372
  .input(types_77.pipelineOrchestratorCapability.methods.assignAudio.input.loose())
5406
5373
  .output(types_77.pipelineOrchestratorCapability.methods.assignAudio.output)
@@ -5441,14 +5408,6 @@ function createCapRouter_pipelineOrchestrator(getProvider, _createRemoteProxy) {
5441
5408
  const p = requireCapProvider('pipeline-orchestrator', () => getProvider(ctx));
5442
5409
  return p.getAudioAssignments();
5443
5410
  }),
5444
- getDecoderAssignment: trpc_middleware_js_1.protectedProcedure
5445
- .input(types_77.pipelineOrchestratorCapability.methods.getDecoderAssignment.input.loose())
5446
- .output(types_77.pipelineOrchestratorCapability.methods.getDecoderAssignment.output)
5447
- .query(async ({ input, ctx }) => {
5448
- const p = requireCapProvider('pipeline-orchestrator', () => getProvider(ctx));
5449
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5450
- return p.getDecoderAssignment(input);
5451
- }),
5452
5411
  getAgentSettings: trpc_middleware_js_1.protectedProcedure
5453
5412
  .input(types_77.pipelineOrchestratorCapability.methods.getAgentSettings.input.loose())
5454
5413
  .output(types_77.pipelineOrchestratorCapability.methods.getAgentSettings.output)
@@ -5513,6 +5472,14 @@ function createCapRouter_pipelineOrchestrator(getProvider, _createRemoteProxy) {
5513
5472
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5514
5473
  return p.setAgentReachableHost(input);
5515
5474
  }),
5475
+ resetNodePipelineDefaults: trpc_middleware_js_1.adminProcedure
5476
+ .input(types_77.pipelineOrchestratorCapability.methods.resetNodePipelineDefaults.input.loose())
5477
+ .output(types_77.pipelineOrchestratorCapability.methods.resetNodePipelineDefaults.output)
5478
+ .mutation(async ({ input, ctx }) => {
5479
+ const p = requireCapProvider('pipeline-orchestrator', () => getProvider(ctx));
5480
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5481
+ return p.resetNodePipelineDefaults(input);
5482
+ }),
5516
5483
  getCameraSettings: trpc_middleware_js_1.protectedProcedure
5517
5484
  .input(types_77.pipelineOrchestratorCapability.methods.getCameraSettings.input.loose())
5518
5485
  .output(types_77.pipelineOrchestratorCapability.methods.getCameraSettings.output)
@@ -24,7 +24,7 @@ exports.checkScopeAccess = checkScopeAccess;
24
24
  * method's required `access` flavour.
25
25
  * 4. No matching scope → FORBIDDEN with a human-readable reason.
26
26
  */
27
- const types_1 = require("@camstack/types");
27
+ const system_1 = require("@camstack/system");
28
28
  /**
29
29
  * Pull `deviceId` off a tRPC request input. Device-scope cap methods
30
30
  * uniformly take `{deviceId: number, ...}` per the DeviceProxy contract,
@@ -51,7 +51,7 @@ function effectiveDeviceIds(deviceId, getAncestors) {
51
51
  return [...out];
52
52
  }
53
53
  function checkScopeAccess(scopes, path, input, getDeviceAncestors) {
54
- const meta = types_1.METHOD_ACCESS_MAP[path];
54
+ const meta = system_1.METHOD_ACCESS_MAP[path];
55
55
  if (!meta) {
56
56
  return { ok: false, reason: `Unknown method '${path}' — codegen drift` };
57
57
  }
@@ -8,7 +8,7 @@ exports.iterableSubscription = iterableSubscription;
8
8
  exports.iterableInterval = iterableInterval;
9
9
  const server_1 = require("@trpc/server");
10
10
  const superjson_1 = __importDefault(require("superjson"));
11
- const types_1 = require("@camstack/types");
11
+ const system_1 = require("@camstack/system");
12
12
  const scope_access_js_1 = require("./scope-access.js");
13
13
  const cap_route_error_formatter_js_1 = require("./cap-route-error-formatter.js");
14
14
  const t = server_1.initTRPC.context().create({
@@ -102,7 +102,7 @@ exports.protectedProcedure = t.procedure.use(async ({ ctx, next, path, getRawInp
102
102
  // Hand-written core route — no cap entry. Authentication has already
103
103
  // passed; defer further gating to any explicit `adminProcedure`
104
104
  // chained on top of this one.
105
- if (!(path in types_1.METHOD_ACCESS_MAP)) {
105
+ if (!(path in system_1.METHOD_ACCESS_MAP)) {
106
106
  return next({ ctx: { ...ctx, user: ctx.user } });
107
107
  }
108
108
  // Device-scope caps may be gated by a `device:N` scope. Resolve the
@@ -50,8 +50,8 @@ const fs = __importStar(require("node:fs"));
50
50
  const node_url_1 = require("node:url");
51
51
  const addon_settings_provider_js_1 = require("./addon-settings-provider.js");
52
52
  const addon_call_gateway_js_1 = require("./addon-call-gateway.js");
53
+ const system_5 = require("@camstack/system");
53
54
  const types_2 = require("@camstack/types");
54
- const types_3 = require("@camstack/types");
55
55
  /**
56
56
  * Type predicate: true when an `ISettingsBackend` also satisfies the
57
57
  * sync `ISettingsStore` contract (system/addon/device key-value ops)
@@ -355,7 +355,7 @@ class AddonRegistryService {
355
355
  // Register the addon-settings singleton provider — replaces the
356
356
  // former `$addonHost` Moleculer service. The provider resolves
357
357
  // addonId → local addon instance (hub) or remote Moleculer call.
358
- this.capabilityRegistry.declareCapability(types_2.addonSettingsCapability);
358
+ this.capabilityRegistry.declareCapability(system_5.addonSettingsCapability);
359
359
  // The SINGLE router for addon-level calls (routes / custom / settings).
360
360
  // It classifies in-process | hub-local-child (UDS) | remote-agent
361
361
  // (Moleculer) in ONE place — `resolveNode` reports only the BASE node
@@ -2592,7 +2592,7 @@ class AddonRegistryService {
2592
2592
  let chain = this.disposerChains.get(addonId);
2593
2593
  if (chain == null) {
2594
2594
  const log = this.loggingService.createLogger().withTags({ addonId });
2595
- chain = new types_3.DisposerChain({
2595
+ chain = new types_2.DisposerChain({
2596
2596
  onError: (err, index) => {
2597
2597
  log.error(`Disposer #${index} threw during teardown`, {
2598
2598
  meta: { error: (0, types_1.errMsg)(err) },
@@ -30,6 +30,7 @@ function buildCapCallFn(deps) {
30
30
  method,
31
31
  args: params,
32
32
  ...(deviceId !== undefined ? { deviceId } : {}),
33
+ ...(deps.addonId !== undefined ? { addonId: deps.addonId } : {}),
33
34
  };
34
35
  return registry.callCapOnChild(deps.udsChildId, input);
35
36
  }
@@ -704,6 +704,7 @@ class MoleculerService {
704
704
  // - resolver not yet built (pre-init) → legacy Moleculer call.
705
705
  const callFn = (0, cap_call_fn_js_1.buildCapCallFn)({
706
706
  capName,
707
+ addonId,
707
708
  nodeId,
708
709
  udsChildId,
709
710
  getLocalChildRegistry: () => this.localChildRegistry,
@@ -717,7 +718,7 @@ class MoleculerService {
717
718
  },
718
719
  });
719
720
  const proxy = { id: addonId, nodeId };
720
- for (const methodName of Object.keys((0, types_1.expandCapMethods)(capDef))) {
721
+ for (const methodName of Object.keys((0, system_1.expandCapMethods)(capDef))) {
721
722
  proxy[methodName] = (methodParams) => callFn(methodName, methodParams);
722
723
  }
723
724
  registry.registerProvider(capName, registryKey, proxy);
@@ -954,39 +955,44 @@ exports.MoleculerService = MoleculerService;
954
955
  // Module-level helpers
955
956
  // ---------------------------------------------------------------------------
956
957
  /**
957
- * E1: Adapt a child's UDS `ChildCapDescriptor[]` (which has no `addonId`) into
958
- * a `RegisterNodeParams` that `onRegisterNode` / `applyNodeManifest` can consume.
958
+ * E1: Adapt a child's UDS `ChildCapDescriptor[]` into a `RegisterNodeParams`
959
+ * that `onRegisterNode` / `applyNodeManifest` can consume.
959
960
  *
960
- * Strategy: use `childId` as the synthetic `addonId`. For currently-shipped addons
961
- * `childId = runnerId = addonId` (one-addon-one-process, no shared group), so the
962
- * `registryKey = childId` produced here matches what the Moleculer `$hub.registerNode`
963
- * path uses making double-apply via both paths fully idempotent.
961
+ * Multi-addon manifest support (co-location): descriptors are grouped by the
962
+ * `addonId` each one carries, producing ONE `RegisteredAddonManifest` entry
963
+ * per hosted addon. A GROUPED runner (`execution.group`, e.g. `net-access`
964
+ * hosting cloudflare-tunnel + cloudflare-turn + tailscale-*) therefore
965
+ * registers each addon's caps under its REAL addon id — real provider
966
+ * registryKeys, per-addon settings/logs/restart, correct admin-UI display
967
+ * names. Before this, all of a group's caps collapsed under one synthetic
968
+ * `addonId = childId` (the group name) — the "@camstack/addon-net-access"
969
+ * admin-UI bug. A legacy child that omits `addonId` falls back to `childId`,
970
+ * which is identical to the historical single-addon behaviour
971
+ * (childId = runnerId = addonId when no group is declared).
964
972
  *
965
973
  * Singleton vs. device-scoped caps: `ChildCapDescriptor.deviceId` is present only
966
974
  * for device-scoped native caps. The `addons` array carries system (singleton/collection)
967
975
  * cap names; device-scoped native caps are handled separately via `nativeCaps` in the
968
- * full `RegisterNodeParams`. For the parallel-window phase (E1), we populate only
969
- * the `addons` portion — the Moleculer path carries `nativeCaps` on the re-handshake.
970
- *
971
- * TODO(co-location): This function synthesises ONE manifest entry with `addonId = childId`
972
- * (the runner id). This is correct under the current one-addon-one-process invariant
973
- * where `childId = runnerId = addonId`. If `execution.group` co-location is ever
974
- * activated (multiple addons sharing one runner), a single runner would host multiple
975
- * addonIds but this function would register all their caps under one synthetic addonId —
976
- * collapsing distinct provider registryKeys into one and breaking per-addon routing.
977
- * Multi-addon manifest support (splitting the `ChildCapDescriptor[]` by addonId once the
978
- * protocol carries addonId) would be needed here before enabling co-location post-Phase-F.
976
+ * full `RegisterNodeParams`.
979
977
  */
980
978
  function buildChildUdsManifest(nodeId, childId, caps) {
981
- // Collect unique system (non-device-scoped) cap names.
982
- const systemCapNames = new Set();
979
+ // Group unique system (non-device-scoped) cap names per hosted addon.
980
+ // Insertion order preserves the child's registration order.
981
+ const capsByAddon = new Map();
983
982
  for (const cap of caps) {
984
- if (cap.deviceId === undefined) {
985
- systemCapNames.add(cap.capName);
986
- }
983
+ if (cap.deviceId !== undefined)
984
+ continue;
985
+ const addonId = cap.addonId ?? childId;
986
+ const set = capsByAddon.get(addonId) ?? new Set();
987
+ set.add(cap.capName);
988
+ capsByAddon.set(addonId, set);
989
+ }
990
+ // A child with no system caps still registers an (empty) entry under its
991
+ // childId so node bookkeeping (previous-manifest diffing, disconnect
992
+ // cleanup) keeps a record for the node.
993
+ if (capsByAddon.size === 0) {
994
+ capsByAddon.set(childId, new Set());
987
995
  }
988
- const addons = [
989
- { addonId: childId, capabilities: [...systemCapNames] },
990
- ];
996
+ const addons = [...capsByAddon.entries()].map(([addonId, capNames]) => ({ addonId, capabilities: [...capNames] }));
991
997
  return { nodeId, addons };
992
998
  }
package/dist/main.js CHANGED
@@ -57,7 +57,10 @@ const auth_service_1 = require("./core/auth/auth.service");
57
57
  // `npx tsx scripts/generate-capability-router-types.ts`. The previous
58
58
  // hand-curated list silently dropped caps (zones, zone-rules,
59
59
  // zone-analytics, audio-metrics — see git for the regression).
60
- const types_1 = require("@camstack/types");
60
+ // Sourced from `@camstack/system` (not `@camstack/types`) so the hub's
61
+ // capability surface refreshes on `camstack deploy packages/system` with no new
62
+ // server image. `@camstack/types` is never deployed to the hub.
63
+ const system_1 = require("@camstack/system");
61
64
  const stream_probe_service_1 = require("./core/streaming/stream-probe.service");
62
65
  const feature_service_1 = require("./core/feature/feature.service");
63
66
  const agent_registry_service_1 = require("./core/agent/agent-registry.service");
@@ -79,7 +82,7 @@ const auth_whoami_1 = require("./api/auth-whoami");
79
82
  const session_cookie_js_1 = require("./auth/session-cookie.js");
80
83
  const health_routes_1 = require("./api/health/health.routes");
81
84
  const oauth2_routes_js_1 = require("./api/oauth2/oauth2-routes.js");
82
- const system_1 = require("@camstack/system");
85
+ const system_2 = require("@camstack/system");
83
86
  const boot_config_1 = require("./boot/boot-config");
84
87
  const manual_boot_1 = require("./manual-boot");
85
88
  const post_boot_service_1 = require("./boot/post-boot.service");
@@ -238,8 +241,8 @@ async function bootstrap() {
238
241
  // If registration fails, start in degraded mode: serve a health warning endpoint.
239
242
  // Instantiate new core services
240
243
  const loggingService = app.get(logging_service_1.LoggingService);
241
- const addonRouteRegistry = new system_1.AddonRouteRegistry();
242
- const dataPlaneRegistry = new system_1.DataPlaneRegistry();
244
+ const addonRouteRegistry = new system_2.AddonRouteRegistry();
245
+ const dataPlaneRegistry = new system_2.DataPlaneRegistry();
243
246
  // Use Fastify-managed notification/toast wrappers (globally provided by NotificationModule)
244
247
  const { NotificationServiceWrapper } = await Promise.resolve().then(() => __importStar(require('./core/notification/notification-wrapper.service')));
245
248
  const { ToastServiceWrapper } = await Promise.resolve().then(() => __importStar(require('./core/notification/toast-wrapper.service')));
@@ -260,7 +263,7 @@ async function bootstrap() {
260
263
  // from forked workers / agents) find their definition during
261
264
  // onModuleInit. The list comes from the codegen — see the import
262
265
  // comment above for the rationale.
263
- for (const capDef of types_1.ALL_CAPABILITY_DEFINITIONS) {
266
+ for (const capDef of system_1.ALL_CAPABILITY_DEFINITIONS) {
264
267
  capabilityRegistry.declareCapability(capDef);
265
268
  }
266
269
  // Hub-internal `sso-bridge` provider — gives auth-provider addons
@@ -730,7 +733,7 @@ async function bootstrap() {
730
733
  const upstreamPath = `/${subPath}${queryString}`;
731
734
  // Take over the socket — `proxyToUpstream` drives the raw response.
732
735
  reply.hijack();
733
- (0, system_1.proxyToUpstream)({
736
+ (0, system_2.proxyToUpstream)({
734
737
  baseUrl: dpMatch.endpoint.baseUrl,
735
738
  secret: dpMatch.endpoint.secret,
736
739
  upstreamPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.1.41",
3
+ "version": "1.1.43",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist",
@@ -24,6 +24,7 @@
24
24
  "dependencies": {
25
25
  "@camstack/addon-admin-ui": "*",
26
26
  "@camstack/addon-advanced-notifier": "*",
27
+ "@camstack/addon-auth": "*",
27
28
  "@camstack/addon-decoder-nodeav": "*",
28
29
  "@camstack/addon-notifiers": "*",
29
30
  "@camstack/addon-pipeline": "*",