@camstack/server 1.2.563 → 1.2.565

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.
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.enrichInputWithUserAgent = enrichInputWithUserAgent;
4
37
  exports.enrichInputWithRelayClass = enrichInputWithRelayClass;
@@ -6,7 +39,10 @@ exports.stripTalkbackFromRequest = stripTalkbackFromRequest;
6
39
  exports.enrichHintsWithClientClass = enrichHintsWithClientClass;
7
40
  exports.wrapWebrtcSessionProviderWithRelay = wrapWebrtcSessionProviderWithRelay;
8
41
  exports.buildAppRouter = buildAppRouter;
42
+ const path = __importStar(require("node:path"));
9
43
  const addon_settings_router_js_1 = require("../core/addon-settings.router.js");
44
+ const certificates_router_js_1 = require("../core/certificates.router.js");
45
+ const node_certificates_client_js_1 = require("../../core/agent/node-certificates-client.js");
10
46
  const auth_router_js_1 = require("../core/auth.router.js");
11
47
  const cap_providers_js_1 = require("../core/cap-providers.js");
12
48
  const capabilities_router_js_1 = require("../core/capabilities.router.js");
@@ -269,11 +305,20 @@ function buildCapabilityRouters(services) {
269
305
  // clusterNodes — fixed core API. Write-side purge for the durable
270
306
  // offline-node history (Track A "Forget node"); read side is push-only.
271
307
  clusterNodes: (0, cluster_nodes_router_js_1.createClusterNodesRouter)(services.agentRegistry),
308
+ // certificates - Identity -> Certificates inventory (HTTPS per node, mesh CA). D855.
309
+ certificates: (0, certificates_router_js_1.createCertificatesRouter)({
310
+ registry: services.capabilityRegistry,
311
+ agentRegistry: services.agentRegistry,
312
+ nodeClient: (nodeId) => (0, node_certificates_client_js_1.createNodeCertificatesClient)(services.moleculer, nodeId),
313
+ hubDataDir: path.resolve(services.configService.get('server.dataPath') ?? 'camstack-data'),
314
+ log: services.loggingService.createLogger('certificates'),
315
+ }),
272
316
  auth: (0, auth_router_js_1.createAuthRouter)(services.authService, services.capabilityRegistry, services.moleculer, services.shareTokenService, services.handoffCodeService, services.externalLinkIntents, services.nativeLink ?? null, {
273
317
  ...(services.authNetworkPolicy !== undefined
274
318
  ? { network: services.authNetworkPolicy }
275
319
  : {}),
276
320
  ...(services.sessionBacking !== undefined ? { sessions: services.sessionBacking } : {}),
321
+ logger: services.loggingService.createLogger('auth'),
277
322
  }),
278
323
  // NOT MOUNTED — `mount: { kind: 'skip' }` legacy provider shapes
279
324
  // (positional args / sync returns) that don't match the codegen
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DeviceEnrollProofs = exports.DEVICE_ENROLL_PROOF_TTL_MS = void 0;
37
+ /**
38
+ * Step-up proofs for `auth.enrollSelf` (D855).
39
+ *
40
+ * A signed-in user may request a device certificate for their own device, but
41
+ * only after signing in AGAIN at that moment — however recent their session
42
+ * is, and however many hours it has been refreshed for. The re-sign-in (a
43
+ * password / passkey re-authentication, or the app login handoff run in
44
+ * `step-up` purpose for any web method) yields ONE proof: purpose
45
+ * `device-enroll`, bound to the user, 5 minutes, single use, kept only as a
46
+ * hash. It replaces no session.
47
+ */
48
+ const crypto = __importStar(require("node:crypto"));
49
+ exports.DEVICE_ENROLL_PROOF_TTL_MS = 5 * 60_000;
50
+ const MAX_PENDING = 1_000;
51
+ function hash(proof) {
52
+ return crypto.createHash('sha256').update(proof).digest('hex');
53
+ }
54
+ /** How long a spent reauth token / claimed session is remembered (past the token's own 5 min). */
55
+ const SPENT_MEMORY_MS = 6 * 60_000;
56
+ class DeviceEnrollProofs {
57
+ now;
58
+ logger;
59
+ pending = new Map();
60
+ spentReauth = new Map();
61
+ claimedSessions = new Map();
62
+ /**
63
+ * `claimedSessions` lives in memory, so a restart forgets which sign-ins already started a
64
+ * step-up. To keep "once per sign-in" true across a restart, a session OPENED BEFORE this
65
+ * process started is refused (it simply signs in again): the window is 120 s, so the cost
66
+ * is one re-login right after a hub restart.
67
+ */
68
+ bootedAt;
69
+ constructor(now = Date.now, logger = null) {
70
+ this.now = now;
71
+ this.logger = logger;
72
+ this.bootedAt = now();
73
+ }
74
+ mint(userId) {
75
+ this.prune();
76
+ if (this.pending.size >= MAX_PENDING)
77
+ throw new Error('Too many pending step-up proofs');
78
+ const proof = `cdp_${crypto.randomBytes(32).toString('base64url')}`;
79
+ const expiresAt = this.now() + exports.DEVICE_ENROLL_PROOF_TTL_MS;
80
+ this.pending.set(hash(proof), { userId, expiresAt });
81
+ return { proof, expiresAt };
82
+ }
83
+ /** Consume `proof` for `userId`. Burned on the first attempt whatever the verdict. */
84
+ consume(proof, userId) {
85
+ if (proof === undefined || proof === '')
86
+ return this.refuse('missing', userId);
87
+ const key = hash(proof);
88
+ const entry = this.pending.get(key);
89
+ if (entry === undefined)
90
+ return this.refuse('unknown-or-used', userId);
91
+ this.pending.delete(key);
92
+ if (this.now() > entry.expiresAt)
93
+ return this.refuse('expired', userId);
94
+ if (entry.userId !== userId)
95
+ return this.refuse('other-user', userId);
96
+ return 'ok';
97
+ }
98
+ refuse(verdict, userId) {
99
+ this.logger?.warn(`Device enrollment step-up proof refused: ${verdict}`, {
100
+ tags: { userId },
101
+ meta: { reason: verdict },
102
+ });
103
+ return verdict;
104
+ }
105
+ /**
106
+ * A reauth token feeds ONE step-up (a proof or a step-up handoff code):
107
+ * `true` the first time, `false` for every later presentation.
108
+ */
109
+ consumeReauth(reauthToken) {
110
+ this.prune();
111
+ const key = hash(reauthToken);
112
+ if (this.spentReauth.has(key)) {
113
+ this.logger?.warn('Reauth token already used for a step-up', {
114
+ meta: { reason: 'reauth-reused' },
115
+ });
116
+ return false;
117
+ }
118
+ this.spentReauth.set(key, this.now() + SPENT_MEMORY_MS);
119
+ return true;
120
+ }
121
+ /** A freshly authenticated session may start ONE step-up: `true` the first time. */
122
+ claimFreshSession(sessionId, sessionCreatedAt) {
123
+ this.prune();
124
+ if (sessionCreatedAt < this.bootedAt) {
125
+ this.logger?.warn('Step-up refused: the sign-in predates this process, so a prior claim cannot be ruled out', {
126
+ meta: { reason: 'predates-boot' },
127
+ });
128
+ return false;
129
+ }
130
+ if (this.claimedSessions.has(sessionId))
131
+ return false;
132
+ this.claimedSessions.set(sessionId, this.now() + SPENT_MEMORY_MS);
133
+ return true;
134
+ }
135
+ prune() {
136
+ const at = this.now();
137
+ for (const [k, exp] of this.spentReauth)
138
+ if (at > exp)
139
+ this.spentReauth.delete(k);
140
+ for (const [k, exp] of this.claimedSessions)
141
+ if (at > exp)
142
+ this.claimedSessions.delete(k);
143
+ for (const [k, v] of this.pending)
144
+ if (at > v.expiresAt)
145
+ this.pending.delete(k);
146
+ }
147
+ }
148
+ exports.DeviceEnrollProofs = DeviceEnrollProofs;
@@ -30,6 +30,8 @@ function createSessionBacking(sessions, lifetimes) {
30
30
  });
31
31
  return { session, refreshToken };
32
32
  },
33
+ revoke: (sessionId, reason) => sessions.revoke(sessionId, reason),
34
+ peek: (refreshToken) => sessions.peekByRefreshToken(refreshToken),
33
35
  extend: async (sessionId) => sessions.extend(sessionId, lifetimes().sessionMs),
34
36
  rotate: async (refreshToken) => {
35
37
  const result = await sessions.refresh(refreshToken, lifetimes().sessionMs);
@@ -53,8 +53,9 @@ function createSessionMinter(deps) {
53
53
  throw new SessionDirectoryUnavailableError();
54
54
  return live;
55
55
  };
56
- const claims = (record, sid) => ({
56
+ const claims = (record, sid, cid) => ({
57
57
  ...(sid !== undefined ? { sid } : {}),
58
+ ...(cid !== undefined && cid !== null ? { cid } : {}),
58
59
  userId: record.id,
59
60
  username: record.username,
60
61
  isAdmin: record.isAdmin,
@@ -72,7 +73,9 @@ function createSessionMinter(deps) {
72
73
  const remainingSec = Math.max(60, Math.floor((session.expiresAt - Date.now()) / 1000));
73
74
  const expiresInSec = refreshable ? Math.min(live.accessSec(), remainingSec) : remainingSec;
74
75
  return {
75
- token: deps.signer.signToken(claims(record, session.id), { expiresInSec }),
76
+ token: deps.signer.signToken(claims(record, session.id, session.credentialId), {
77
+ expiresInSec,
78
+ }),
76
79
  expiresAt: Date.now() + expiresInSec * 1000,
77
80
  };
78
81
  };
@@ -92,6 +95,7 @@ function createSessionMinter(deps) {
92
95
  method: issue.method,
93
96
  ...(issue.client !== undefined ? { client: issue.client } : {}),
94
97
  ...(issue.ip !== undefined ? { ip: issue.ip } : {}),
98
+ ...(issue.credentialId !== undefined ? { credentialId: issue.credentialId } : {}),
95
99
  });
96
100
  const access = signFor(record, opened.session, refreshable, live);
97
101
  return {
@@ -132,6 +136,24 @@ function createSessionMinter(deps) {
132
136
  const live = backing();
133
137
  if (live === null)
134
138
  throw new SessionRefreshRefusedError('unknown');
139
+ // A session opened by a device certificate lives only while that
140
+ // credential does (D855). The credential is judged BEFORE the refresh
141
+ // token is spent: a refusal here leaves the token untouched, so a transient
142
+ // `unavailable` can never turn into a "rotated-out token presented"
143
+ // refresh-reuse revocation on the retry. A revoked / expired credential
144
+ // revokes the session, so nothing is left to refresh.
145
+ const peeked = live.peek(refreshToken);
146
+ const credentialId = peeked?.credentialId ?? null;
147
+ if (peeked !== null && credentialId !== null) {
148
+ const gate = deps.credentials?.() ?? null;
149
+ const state = gate === null ? 'unavailable' : gate.check(credentialId);
150
+ if (state !== 'active') {
151
+ if (state === 'revoked' || state === 'expired') {
152
+ await live.revoke(peeked.id, `credential-${state}`);
153
+ }
154
+ throw new SessionRefreshRefusedError(`credential-${state}`);
155
+ }
156
+ }
135
157
  const rotated = await live.rotate(refreshToken);
136
158
  if (!rotated.ok)
137
159
  throw new SessionRefreshRefusedError(rotated.reason);
@@ -77,6 +77,7 @@ function registerSsoRoutes(fastify, deps) {
77
77
  session = await deps.minter.mintForUserId(grant.userId, {
78
78
  method: 'handoff',
79
79
  refreshable: true,
80
+ ...(grant.credentialId !== undefined ? { credentialId: grant.credentialId } : {}),
80
81
  ...(ip !== null ? { ip } : {}),
81
82
  ...clientOf(request.headers['user-agent']),
82
83
  });
@@ -379,6 +379,13 @@ class AgentRegistryService {
379
379
  // of failed deliveries to it is meaningless — drop it too.
380
380
  this.backfillTracker.forget(nodeId);
381
381
  this.deliveryLedger.forget(nodeId);
382
+ // The names the hub certified to this node are free again (a forgotten node cannot hold them).
383
+ await (0, system_1.getProcessAgentHttpsNames)()
384
+ ?.release(nodeId)
385
+ .catch((err) => this.logger?.warn("forget cluster node: could not release the node's certified names", {
386
+ tags: { nodeId },
387
+ meta: { error: err instanceof Error ? err.message : String(err) },
388
+ }));
382
389
  const historyRemoved = historyOutcome === 'removed';
383
390
  const stillListed = this.isNodeKnown(nodeId);
384
391
  const message = describeForgetOutcome(nodeId, historyOutcome, registryRemoved, stillListed);
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createNodeCertificatesClient = createNodeCertificatesClient;
4
+ /**
5
+ * The hub's typed handle on a node's `node-certificates` capability (D856).
6
+ *
7
+ * `createCapabilityProxy` hands back untyped functions; every answer is narrowed
8
+ * through the capability's own Zod output schema, and a missing proxy (node
9
+ * offline, capability not declared by an old agent) or a malformed answer becomes
10
+ * a plain error naming the node - never a cast.
11
+ */
12
+ const types_1 = require("@camstack/types");
13
+ function createNodeCertificatesClient(moleculer, nodeId) {
14
+ const proxy = moleculer?.createCapabilityProxy('node-certificates', nodeId) ?? null;
15
+ if (proxy === null)
16
+ return null;
17
+ const call = async (method, schema, params) => {
18
+ const fn = proxy[method];
19
+ if (typeof fn !== 'function') {
20
+ throw new Error(`node ${nodeId} does not provide node-certificates.${method} (update the agent)`);
21
+ }
22
+ const parsed = schema.safeParse(await fn(params));
23
+ if (!parsed.success) {
24
+ throw new Error(`node ${nodeId} answered node-certificates.${method} with an unexpected shape`);
25
+ }
26
+ return parsed.data;
27
+ };
28
+ const m = types_1.nodeCertificatesCapability.methods;
29
+ return {
30
+ getCertificates: () => call('getCertificates', m.getCertificates.output, {}),
31
+ prepareMeshRenewal: () => call('prepareMeshRenewal', m.prepareMeshRenewal.output, {}),
32
+ installMeshLeaf: (input) => call('installMeshLeaf', m.installMeshLeaf.output, input),
33
+ confirmMeshLeaf: (input) => call('confirmMeshLeaf', m.confirmMeshLeaf.output, input),
34
+ rollbackMeshLeaf: () => call('rollbackMeshLeaf', m.rollbackMeshLeaf.output, {}),
35
+ prepareHttpsCertificate: () => call('prepareHttpsCertificate', m.prepareHttpsCertificate.output, {}),
36
+ installHttpsCertificate: (input) => call('installHttpsCertificate', m.installHttpsCertificate.output, input),
37
+ };
38
+ }
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.HandoffCodeService = exports.HANDOFF_CODE_MAX_PENDING = exports.HANDOFF_CODE_TTL_MS = exports.HANDOFF_CODE_PREFIX = void 0;
37
+ exports.pkceChallenge = pkceChallenge;
37
38
  /**
38
39
  * HandoffCodeService — one-time login handoff codes for the native-app
39
40
  * auth handoff (viewer "Sign in with CamStack").
@@ -64,6 +65,10 @@ exports.HANDOFF_CODE_TTL_MS = 60_000;
64
65
  /** Hard bound on concurrently-pending codes (mint is auth-gated, so this
65
66
  * only guards against a runaway authenticated client). */
66
67
  exports.HANDOFF_CODE_MAX_PENDING = 1_000;
68
+ /** RFC 7636 S256: `base64url(sha256(verifier))`. */
69
+ function pkceChallenge(verifier) {
70
+ return crypto.createHash('sha256').update(verifier).digest('base64url');
71
+ }
67
72
  function hashCode(code) {
68
73
  return crypto.createHash('sha256').update(code).digest('hex');
69
74
  }
@@ -90,6 +95,9 @@ class HandoffCodeService {
90
95
  userId,
91
96
  ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
92
97
  purpose: options.purpose ?? 'renew',
98
+ ...(options.codeChallenge !== undefined ? { codeChallenge: options.codeChallenge } : {}),
99
+ ...(options.state !== undefined ? { state: options.state } : {}),
100
+ ...(options.credentialId !== undefined ? { credentialId: options.credentialId } : {}),
93
101
  expiresAt,
94
102
  });
95
103
  return { code, expiresAt };
@@ -97,15 +105,30 @@ class HandoffCodeService {
97
105
  /** Redeem a raw code. Consumes the entry on the FIRST attempt no
98
106
  * matter the outcome (single-use); returns `null` for unknown,
99
107
  * already-used, or expired codes — the router maps that to 401. */
100
- redeem(code) {
108
+ redeem(code, proof = {}) {
109
+ return this.redeemWithReason(code, proof).grant;
110
+ }
111
+ /** Like {@link redeem}, but says why a code was refused (for the log line). */
112
+ redeemWithReason(code, proof = {}) {
101
113
  const entry = this.pending.get(hashCode(code));
102
114
  if (!entry)
103
- return null;
115
+ return { grant: null, reason: 'unknown-or-used' };
104
116
  this.pending.delete(hashCode(code));
105
117
  if (this.now() > entry.expiresAt)
106
- return null;
118
+ return { grant: null, reason: 'expired' };
119
+ // PKCE: a code minted with a challenge redeems only with its verifier.
120
+ // The entry is already burned, so a wrong guess cannot be retried.
121
+ if (entry.codeChallenge !== undefined) {
122
+ if (proof.codeVerifier === undefined ||
123
+ pkceChallenge(proof.codeVerifier) !== entry.codeChallenge) {
124
+ return { grant: null, reason: 'pkce-mismatch' };
125
+ }
126
+ }
127
+ if (entry.state !== undefined && proof.state !== entry.state) {
128
+ return { grant: null, reason: 'state-mismatch' };
129
+ }
107
130
  const { expiresAt: _expiresAt, ...grant } = entry;
108
- return grant;
131
+ return { grant, reason: null };
109
132
  }
110
133
  /** Number of not-yet-redeemed (possibly expired) codes. Test/diag aid. */
111
134
  get pendingCount() {
@@ -711,6 +711,8 @@ class MoleculerService {
711
711
  });
712
712
  (0, system_1.setProcessMeshPeerTransportLookup)({
713
713
  transportOf: (nodeId) => (0, system_1.getBrokerTlsTransporter)(this.broker)?.peerTransport(nodeId),
714
+ peerLeaf: (nodeId) => (0, system_1.getBrokerTlsTransporter)(this.broker)?.peerLeaf(nodeId),
715
+ dropPeer: (nodeId) => (0, system_1.getBrokerTlsTransporter)(this.broker)?.dropPeer(nodeId) ?? 0,
714
716
  });
715
717
  await this.brokerSafe.start();
716
718
  logger.info('Moleculer broker started (TCP transport)');
@@ -927,6 +929,9 @@ class MoleculerService {
927
929
  else
928
930
  this.nodeOwners.set(params.nodeId, owner);
929
931
  this.applyNodeManifest(params, previousManifest, owner, previousOwner);
932
+ // The node's capabilities are routable now: whoever waits for this registration (a mesh
933
+ // leaf renewal confirming the node came back WITH the new leaf) is told, with no polling.
934
+ (0, system_1.emitProcessNodeRegistered)(params.nodeId);
930
935
  // Notify AgentRegistryService to reconcile placement for bare-ID
931
936
  // agent nodes (no '/' = not a hub child worker, not the hub itself).
932
937
  // The handshake is the authoritative completeness signal — the full
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.2.563",
3
+ "version": "1.2.565",
4
4
  "license": "MIT",
5
5
  "private": false,
6
6
  "files": [
@@ -38,19 +38,19 @@
38
38
  ]
39
39
  },
40
40
  "dependencies": {
41
- "@camstack/addon-admin-ui": "1.2.418",
42
- "@camstack/addon-agent-ui": "1.2.230",
43
- "@camstack/addon-auth": "1.2.143",
41
+ "@camstack/addon-admin-ui": "1.2.419",
42
+ "@camstack/addon-agent-ui": "1.2.231",
43
+ "@camstack/addon-auth": "1.2.144",
44
44
  "@camstack/addon-decoder-nodeav": "1.2.123",
45
45
  "@camstack/addon-notifiers": "1.2.134",
46
- "@camstack/addon-pipeline": "1.2.367",
47
- "@camstack/addon-pipeline-orchestrator": "1.2.317",
46
+ "@camstack/addon-pipeline": "1.2.368",
47
+ "@camstack/addon-pipeline-orchestrator": "1.2.318",
48
48
  "@camstack/addon-post-analysis": "1.2.369",
49
49
  "@camstack/develop": "0.1.8",
50
50
  "@camstack/sdk": "1.2.131",
51
- "@camstack/system": "1.2.428",
52
- "@camstack/types": "1.2.364",
53
- "@camstack/ui-library": "1.2.287",
51
+ "@camstack/system": "1.2.429",
52
+ "@camstack/types": "1.2.365",
53
+ "@camstack/ui-library": "1.2.288",
54
54
  "@fastify/compress": "^9.0.0",
55
55
  "@fastify/cookie": "^11.0.2",
56
56
  "@fastify/cors": "^11.2.0",