@camstack/server 1.2.9 → 1.2.11

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.
@@ -1225,11 +1225,11 @@ class AddonRegistryService {
1225
1225
  if (initResult?.customActions && initResult.actionHandlers) {
1226
1226
  const handlers = initResult.actionHandlers;
1227
1227
  try {
1228
- this.customActionRegistry.registerAddon(id, initResult.customActions, (action, input) => {
1228
+ this.customActionRegistry.registerAddon(id, initResult.customActions, (action, input, caller) => {
1229
1229
  const fn = handlers[action];
1230
1230
  if (!fn)
1231
1231
  throw new Error(`addon '${id}' has no handler for custom action '${action}'`);
1232
- return fn(input);
1232
+ return fn(input, caller);
1233
1233
  });
1234
1234
  }
1235
1235
  catch (err) {
@@ -2987,7 +2987,7 @@ class AddonRegistryService {
2987
2987
  });
2988
2988
  return;
2989
2989
  }
2990
- this.customActionRegistry.registerAddon(addonId, catalog, (action, input) => this.dispatchForkedCustomAction(addonId, action, input));
2990
+ this.customActionRegistry.registerAddon(addonId, catalog, (action, input, caller) => this.dispatchForkedCustomAction(addonId, action, input, caller));
2991
2991
  this.logger.info('Runner addon custom actions registered', {
2992
2992
  tags: { addonId },
2993
2993
  meta: { runnerId },
@@ -2999,11 +2999,15 @@ class AddonRegistryService {
2999
2999
  * routing + the child-availability error; there is no broker fallback after
3000
3000
  * the per-addon Moleculer broker was removed.
3001
3001
  */
3002
- async dispatchForkedCustomAction(addonId, action, input) {
3002
+ async dispatchForkedCustomAction(addonId, action, input, caller) {
3003
3003
  return this.addonCallGateway.callForked(addonId, {
3004
3004
  target: 'custom',
3005
3005
  action,
3006
3006
  args: input,
3007
+ // Additive: only carry `caller` when the hub actually forwarded one (the
3008
+ // router populates it exclusively for a `caller:'required'` action of an
3009
+ // authenticated request). Never blanket; never from client input.
3010
+ ...(caller ? { caller } : {}),
3007
3011
  });
3008
3012
  }
3009
3013
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.2.9",
3
+ "version": "1.2.11",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist",
@@ -33,20 +33,19 @@
33
33
  ]
34
34
  },
35
35
  "dependencies": {
36
- "@camstack/addon-admin-ui": "1.2.6",
37
- "@camstack/addon-advanced-notifier": "1.2.4",
38
- "@camstack/addon-agent-ui": "1.2.4",
39
- "@camstack/addon-auth": "1.2.4",
40
- "@camstack/addon-decoder-nodeav": "1.2.4",
41
- "@camstack/addon-notifiers": "1.2.4",
42
- "@camstack/addon-pipeline": "1.2.7",
43
- "@camstack/addon-pipeline-orchestrator": "1.2.8",
44
- "@camstack/addon-post-analysis": "1.2.7",
45
- "@camstack/sdk": "1.2.4",
46
- "@camstack/shm-ring": "1.1.4",
47
- "@camstack/system": "1.2.8",
48
- "@camstack/types": "1.2.8",
49
- "@camstack/ui-library": "1.2.5",
36
+ "@camstack/addon-admin-ui": "1.2.9",
37
+ "@camstack/addon-agent-ui": "1.2.5",
38
+ "@camstack/addon-auth": "1.2.5",
39
+ "@camstack/addon-decoder-nodeav": "1.2.5",
40
+ "@camstack/addon-notifiers": "1.2.6",
41
+ "@camstack/addon-pipeline": "1.2.9",
42
+ "@camstack/addon-pipeline-orchestrator": "1.2.10",
43
+ "@camstack/addon-post-analysis": "1.2.9",
44
+ "@camstack/sdk": "1.2.5",
45
+ "@camstack/shm-ring": "1.1.5",
46
+ "@camstack/system": "1.2.13",
47
+ "@camstack/types": "1.2.10",
48
+ "@camstack/ui-library": "1.2.8",
50
49
  "@fastify/compress": "^9.0.0",
51
50
  "@fastify/cookie": "^11.0.2",
52
51
  "@fastify/cors": "^11.2.0",
@@ -1,91 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createAddonsCustomProcedures = createAddonsCustomProcedures;
4
- /**
5
- * `api.addons.custom` — generic dispatcher for addon-defined custom actions.
6
- *
7
- * Task 7.2 of the device-proxy redesign. Addons declare a catalog of
8
- * custom actions at boot via `AddonInitResult.customActions` + a single
9
- * `handleCustomAction(action, input)` handler. The catalog is registered
10
- * with a per-process `CustomActionRegistry` (Task 7.1). This endpoint is
11
- * the single tRPC entry point that resolves an `(addonId, action)` pair,
12
- * validates input + output against the action's Zod schemas, enforces the
13
- * action's declared auth level, and dispatches to the addon handler.
14
- *
15
- * The factory returns a record of procedures (not a router) so the caller
16
- * can spread it into the existing `addons` namespace:
17
- *
18
- * trpcRouter({
19
- * ...existingAddonsProcedures,
20
- * ...createAddonsCustomProcedures({ getCustomActionRegistry: ... }),
21
- * })
22
- *
23
- * This avoids `mergeRouters` (which requires sharing the `t` instance
24
- * across modules) while still mounting the procedure at `api.addons.custom`.
25
- */
26
- const zod_1 = require("zod");
27
- const server_1 = require("@trpc/server");
28
- const trpc_middleware_js_1 = require("./trpc/trpc.middleware.js");
29
- /**
30
- * Build the procedure record for the `custom` endpoint.
31
- *
32
- * The OUTER procedure is `protectedProcedure` — every caller must be
33
- * authenticated. The INNER per-action auth declared in `spec.auth` is
34
- * enforced manually by `ensureAuth` because the auth level is not known
35
- * until after the registry lookup.
36
- */
37
- function createAddonsCustomProcedures(deps) {
38
- return {
39
- custom: trpc_middleware_js_1.protectedProcedure
40
- .input(zod_1.z.object({
41
- addonId: zod_1.z.string().min(1),
42
- action: zod_1.z.string().min(1),
43
- input: zod_1.z.unknown(),
44
- }))
45
- .output(zod_1.z.unknown())
46
- .mutation(async ({ input, ctx }) => {
47
- const registry = deps.getCustomActionRegistry();
48
- const entry = registry.resolve(input.addonId, input.action);
49
- if (!entry) {
50
- throw new server_1.TRPCError({
51
- code: 'NOT_FOUND',
52
- message: `addon '${input.addonId}' has no custom action '${input.action}'`,
53
- });
54
- }
55
- // Per-action authorization. The outer procedure already requires
56
- // authentication; here we additionally enforce the declared role
57
- // when it's stricter than 'protected'.
58
- ensureAuth(ctx, entry.spec.auth);
59
- // Validate input against the action's declared Zod schema.
60
- const parsedInput = entry.spec.input.parse(input.input);
61
- // Dispatch through the addon handler.
62
- const result = await entry.handler(parsedInput);
63
- // Validate the addon's output. Crash-early on misbehaving addons.
64
- return entry.spec.output.parse(result);
65
- }),
66
- };
67
- }
68
- /**
69
- * Enforce the action's declared auth level.
70
- *
71
- * Mirrors the role checks performed by `protectedProcedure` and
72
- * `adminProcedure` in trpc.middleware.ts:
73
- * - public: no auth
74
- * - protected: any authenticated user
75
- * - admin: isAdmin only (scoped tokens bounce)
76
- */
77
- function ensureAuth(ctx, level) {
78
- if (level === 'public')
79
- return;
80
- if (!ctx.user) {
81
- throw new server_1.TRPCError({ code: 'UNAUTHORIZED' });
82
- }
83
- if (level === 'protected')
84
- return;
85
- if (level === 'admin') {
86
- if (!ctx.user.isAdmin) {
87
- throw new server_1.TRPCError({ code: 'FORBIDDEN', message: 'custom action requires admin' });
88
- }
89
- return;
90
- }
91
- }