@camstack/server 1.2.500 → 1.2.502

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.
@@ -44,6 +44,8 @@ const moleculer_1 = require("moleculer");
44
44
  const agent_deploy_swap_js_1 = require("./agent-deploy-swap.js");
45
45
  const agent_undeploy_js_1 = require("./agent-undeploy.js");
46
46
  const apply_model_distribution_js_1 = require("./apply-model-distribution.js");
47
+ const apply_stage_dev_uploads_js_1 = require("./apply-stage-dev-uploads.js");
48
+ const dev_uploads_bundle_js_1 = require("../api/dev-uploads-bundle.js");
47
49
  const fetch_bundle_from_hub_js_1 = require("./fetch-bundle-from-hub.js");
48
50
  /**
49
51
  * Console-backed scoped logger for the deploy swap (the only consumer in this
@@ -459,6 +461,23 @@ function createAgentService(deps) {
459
461
  return resolveDeployAction(seam)({ addonId, source, bundle });
460
462
  },
461
463
  },
464
+ /**
465
+ * Stage a hub-packed `dev-uploads/<version>/` set under this node's
466
+ * `server-root/dev-uploads/` so a subsequent `applyServerUpdate` for a
467
+ * `-dev.<epoch>` version can promote locally (Path B fan-out). Does not
468
+ * restart or promote — only writes the upload layout.
469
+ */
470
+ stageDevUploads: {
471
+ handler: async (ctx) => {
472
+ const { params } = ctx;
473
+ const seam = {
474
+ dataDir: deps.dataDir,
475
+ fetchBundle: (s) => (0, fetch_bundle_from_hub_js_1.fetchBundleFromHub)(s),
476
+ unpack: dev_uploads_bundle_js_1.unpackDevUploadVersionBundle,
477
+ };
478
+ return (0, apply_stage_dev_uploads_js_1.applyStageDevUploads)(seam, params);
479
+ },
480
+ },
462
481
  /**
463
482
  * Pull a staged model tarball from the hub and untar it into this node's
464
483
  * `<dataDir>/models` (Model Studio P2). Reuses the agent-pull machinery:
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.applyStageDevUploads = applyStageDevUploads;
4
+ /**
5
+ * Pure seam for `$agent.stageDevUploads` — fetch a hub-staged pack of
6
+ * `dev-uploads/<version>/` and write it under this node's server-root.
7
+ */
8
+ const node_crypto_1 = require("node:crypto");
9
+ const index_js_1 = require("../server-root/index.js");
10
+ async function applyStageDevUploads(seam, params) {
11
+ const { version, source } = params;
12
+ if (!(0, index_js_1.isDevChannelVersion)(version)) {
13
+ throw new Error(`$agent.stageDevUploads: version "${version}" is not dev-channel shaped`);
14
+ }
15
+ const bundle = await seam.fetchBundle(source);
16
+ const appliedSha256 = (0, node_crypto_1.createHash)('sha256').update(bundle).digest('hex');
17
+ const unpacked = await seam.unpack({
18
+ serverRoot: (0, index_js_1.serverRootDir)(seam.dataDir),
19
+ version,
20
+ bundle,
21
+ });
22
+ return {
23
+ success: true,
24
+ version,
25
+ path: unpacked.versionDir,
26
+ packageCount: unpacked.packageCount,
27
+ appliedSha256,
28
+ };
29
+ }
@@ -0,0 +1,170 @@
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.isSafeDevUploadVersion = isSafeDevUploadVersion;
37
+ exports.packDevUploadVersionDir = packDevUploadVersionDir;
38
+ exports.unpackDevUploadVersionBundle = unpackDevUploadVersionBundle;
39
+ /**
40
+ * Pack / unpack a hub `server-root/dev-uploads/<version>/` directory for
41
+ * agent fan-out (`POST /api/server-upload/propagate` → `$agent.stageDevUploads`).
42
+ *
43
+ * One gzipped tar carries every tarball + `manifest.json`. Fail-closed on
44
+ * path traversal and on a layout that would not satisfy RootUpdateService.
45
+ */
46
+ const fs = __importStar(require("node:fs"));
47
+ const os = __importStar(require("node:os"));
48
+ const path = __importStar(require("node:path"));
49
+ const tar = __importStar(require("tar"));
50
+ const index_js_1 = require("../server-root/index.js");
51
+ /** Version chars safe as a single path segment (matches server-upload). */
52
+ const SAFE_VERSION_RE = /^[0-9A-Za-z][0-9A-Za-z.-]*$/;
53
+ function isSafeDevUploadVersion(version) {
54
+ return SAFE_VERSION_RE.test(version) && (0, index_js_1.isDevChannelVersion)(version);
55
+ }
56
+ function hasPathTraversal(name) {
57
+ return name.includes('/') || name.includes('\\') || name.includes('..');
58
+ }
59
+ /**
60
+ * Pack every file in `versionDir` (basename entries only) into a gzipped tar.
61
+ * Refuses if the manifest is missing/invalid or lists a missing tarball.
62
+ */
63
+ async function packDevUploadVersionDir(versionDir) {
64
+ const manifest = (0, index_js_1.readDevUploadManifest)(versionDir);
65
+ if (manifest === null) {
66
+ throw new Error(`dev-uploads manifest missing or invalid in ${versionDir}`);
67
+ }
68
+ for (const filename of Object.values(manifest.packages)) {
69
+ if (hasPathTraversal(filename)) {
70
+ throw new Error(`dev-uploads package filename refuses path traversal: ${filename}`);
71
+ }
72
+ const abs = path.join(versionDir, filename);
73
+ if (!fs.existsSync(abs)) {
74
+ throw new Error(`dev-uploads tarball listed in manifest is missing: ${filename}`);
75
+ }
76
+ }
77
+ if (!fs.existsSync(path.join(versionDir, index_js_1.DEV_UPLOAD_MANIFEST_FILE))) {
78
+ throw new Error(`dev-uploads manifest file missing in ${versionDir}`);
79
+ }
80
+ const entries = fs.readdirSync(versionDir).filter((name) => {
81
+ const st = fs.statSync(path.join(versionDir, name));
82
+ return st.isFile() && !hasPathTraversal(name);
83
+ });
84
+ if (entries.length === 0) {
85
+ throw new Error(`dev-uploads version dir is empty: ${versionDir}`);
86
+ }
87
+ const chunks = [];
88
+ await new Promise((resolve, reject) => {
89
+ const stream = tar.c({ gzip: true, cwd: versionDir, portable: true }, entries);
90
+ stream.on('data', (chunk) => {
91
+ chunks.push(chunk);
92
+ });
93
+ stream.on('error', reject);
94
+ stream.on('end', () => resolve());
95
+ });
96
+ return Buffer.concat(chunks);
97
+ }
98
+ /**
99
+ * Extract a packed version dir into `serverRoot/dev-uploads/<version>/`
100
+ * atomically (stage sibling + rename). Validates version shape, entry names,
101
+ * and that the extracted layout matches the manifest.
102
+ */
103
+ async function unpackDevUploadVersionBundle(args) {
104
+ const { serverRoot, version, bundle } = args;
105
+ if (!isSafeDevUploadVersion(version)) {
106
+ throw new Error(`Refused: version "${version}" is not a safe dev-channel version for staging`);
107
+ }
108
+ const uploadsRoot = path.join(serverRoot, 'dev-uploads');
109
+ fs.mkdirSync(uploadsRoot, { recursive: true });
110
+ const finalDir = path.join(uploadsRoot, version);
111
+ const stagingDir = path.join(uploadsRoot, `.staging-${version}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
112
+ fs.mkdirSync(stagingDir, { recursive: true });
113
+ const tmpTgz = path.join(os.tmpdir(), `camstack-dev-uploads-${version.replace(/[^\w.-]/g, '_')}-${Date.now()}.tgz`);
114
+ try {
115
+ fs.writeFileSync(tmpTgz, bundle);
116
+ let refusedEntry = null;
117
+ await tar.x({
118
+ file: tmpTgz,
119
+ cwd: stagingDir,
120
+ gzip: true,
121
+ // Basename-only layout. Skipping the entry (filter false) then failing
122
+ // after extract avoids an unhandled throw from tar's async parser.
123
+ filter: (entryPath) => {
124
+ const name = entryPath.replace(/^\.\//, '');
125
+ if (hasPathTraversal(name) || path.isAbsolute(name) || name.includes('/')) {
126
+ refusedEntry = entryPath;
127
+ return false;
128
+ }
129
+ return true;
130
+ },
131
+ });
132
+ if (refusedEntry !== null) {
133
+ throw new Error(`Refused: archive entry is not a basename: ${refusedEntry}`);
134
+ }
135
+ const manifest = (0, index_js_1.readDevUploadManifest)(stagingDir);
136
+ if (manifest === null) {
137
+ throw new Error('extracted archive has no valid manifest.json');
138
+ }
139
+ if (manifest.version !== version) {
140
+ throw new Error(`extracted manifest version mismatch: expected ${version}, got ${manifest.version}`);
141
+ }
142
+ for (const filename of Object.values(manifest.packages)) {
143
+ if (hasPathTraversal(filename)) {
144
+ throw new Error(`manifest package filename refuses path traversal: ${filename}`);
145
+ }
146
+ if (!fs.existsSync(path.join(stagingDir, filename))) {
147
+ throw new Error(`extracted archive missing package tarball: ${filename}`);
148
+ }
149
+ }
150
+ // Replace any previous incomplete/stale version dir.
151
+ fs.rmSync(finalDir, { recursive: true, force: true });
152
+ fs.renameSync(stagingDir, finalDir);
153
+ return {
154
+ versionDir: finalDir,
155
+ packageCount: Object.keys(manifest.packages).length,
156
+ };
157
+ }
158
+ catch (err) {
159
+ fs.rmSync(stagingDir, { recursive: true, force: true });
160
+ throw err;
161
+ }
162
+ finally {
163
+ try {
164
+ fs.unlinkSync(tmpTgz);
165
+ }
166
+ catch {
167
+ /* best-effort */
168
+ }
169
+ }
170
+ }
@@ -0,0 +1,178 @@
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.registerServerUploadPropagateRoute = registerServerUploadPropagateRoute;
37
+ /**
38
+ * POST /api/server-upload/propagate — deliver an already-uploaded
39
+ * `dev-uploads/<version>/` set from the hub onto one agent, then leave
40
+ * `applyServerUpdate` to the caller (CLI).
41
+ *
42
+ * Mirrors addon fan-out: pack the version dir → stage one-shot hub-http
43
+ * ticket → `$agent.stageDevUploads`. Does NOT promote the closure.
44
+ */
45
+ const fs = __importStar(require("node:fs"));
46
+ const path = __importStar(require("node:path"));
47
+ const agent_addon_delivery_js_1 = require("./agent-addon-delivery.js");
48
+ const addon_upload_js_1 = require("./addon-upload.js");
49
+ const dev_uploads_bundle_js_1 = require("./dev-uploads-bundle.js");
50
+ const upload_auth_js_1 = require("./upload-auth.js");
51
+ const index_js_1 = require("../server-root/index.js");
52
+ function isStageResponse(value) {
53
+ if (value === null || typeof value !== 'object')
54
+ return false;
55
+ return typeof value.success === 'boolean';
56
+ }
57
+ function readBody(value) {
58
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
59
+ return { error: 'Expected JSON body { version, nodeId }' };
60
+ }
61
+ const body = value;
62
+ if (typeof body.version !== 'string' || body.version.length === 0) {
63
+ return { error: 'Missing "version" field' };
64
+ }
65
+ if (typeof body.nodeId !== 'string' || body.nodeId.length === 0) {
66
+ return { error: 'Missing "nodeId" field' };
67
+ }
68
+ if (body.nodeId === 'hub' || body.nodeId.includes('/')) {
69
+ return {
70
+ error: 'nodeId must be a top-level agent id (not "hub" and not a child runner id)',
71
+ };
72
+ }
73
+ if (!(0, dev_uploads_bundle_js_1.isSafeDevUploadVersion)(body.version)) {
74
+ return {
75
+ error: `Refused: version "${body.version}" is not a safe dev-channel version ` +
76
+ '(expected `<base>-dev.<epochSeconds>`)',
77
+ };
78
+ }
79
+ return { version: body.version, nodeId: body.nodeId };
80
+ }
81
+ function registerServerUploadPropagateRoute(fastify, options) {
82
+ const { authService, addonRegistry, logger, broker, resolveClusterBaseUrl } = options;
83
+ fastify.post('/api/server-upload/propagate', async (request, reply) => {
84
+ const auth = await (0, upload_auth_js_1.authorizeUploadRequest)({
85
+ authHeader: request.headers.authorization,
86
+ authService,
87
+ addonRegistry,
88
+ });
89
+ if (!auth.ok) {
90
+ return reply.status(auth.status).send({ error: auth.error });
91
+ }
92
+ const parsed = readBody(request.body);
93
+ if ('error' in parsed) {
94
+ return reply.status(400).send({ error: parsed.error });
95
+ }
96
+ const { version, nodeId } = parsed;
97
+ const dataDir = path.resolve(options.dataDir ?? process.env['CAMSTACK_DATA'] ?? 'camstack-data');
98
+ const versionDir = (0, index_js_1.devUploadVersionDir)((0, index_js_1.serverRootDir)(dataDir), version);
99
+ if (!fs.existsSync(versionDir)) {
100
+ return reply.status(404).send({
101
+ error: `No hub-side upload for ${version} at ${versionDir}. ` +
102
+ 'Upload first with `camstack deploy-server` (POST /api/server-upload).',
103
+ });
104
+ }
105
+ const manifest = (0, index_js_1.readDevUploadManifest)(versionDir);
106
+ if (manifest === null) {
107
+ return reply.status(400).send({
108
+ error: `Hub upload for ${version} has a missing or invalid manifest.json`,
109
+ });
110
+ }
111
+ let hubBaseUrl;
112
+ try {
113
+ hubBaseUrl = await resolveClusterBaseUrl();
114
+ }
115
+ catch (err) {
116
+ const message = err instanceof Error ? err.message : String(err);
117
+ logger.error('server-upload propagate: no hub address agents can reach', {
118
+ meta: { version, nodeId, error: message },
119
+ });
120
+ return reply.status(502).send({ error: `Agent propagate failed: ${message}` });
121
+ }
122
+ let bundle;
123
+ let source;
124
+ try {
125
+ bundle = await (0, dev_uploads_bundle_js_1.packDevUploadVersionDir)(versionDir);
126
+ source = (0, addon_upload_js_1.buildHubHttpSource)(bundle, hubBaseUrl);
127
+ }
128
+ catch (err) {
129
+ const message = err instanceof Error ? err.message : String(err);
130
+ logger.error('server-upload propagate: pack/stage failed', {
131
+ meta: { version, nodeId, error: message },
132
+ });
133
+ return reply.status(500).send({ error: `Failed to stage upload pack: ${message}` });
134
+ }
135
+ try {
136
+ const raw = await broker.call('$agent.stageDevUploads', { version, source }, { nodeID: nodeId, timeout: agent_addon_delivery_js_1.AGENT_DEPLOY_CONTROL_TIMEOUT_MS });
137
+ if (!isStageResponse(raw) || raw.success !== true) {
138
+ logger.warn('server-upload propagate: malformed agent response', {
139
+ meta: { version, nodeId },
140
+ });
141
+ return reply.status(502).send({ error: 'Agent returned a malformed stage response' });
142
+ }
143
+ const applied = raw.appliedSha256;
144
+ if (applied !== undefined && applied !== source.sha256) {
145
+ logger.error('server-upload propagate: applied hash mismatch', {
146
+ meta: { version, nodeId, expected: source.sha256, applied },
147
+ });
148
+ return reply.status(502).send({
149
+ error: `applied bundle hash mismatch (shipped ${source.sha256}, agent applied ${applied})`,
150
+ });
151
+ }
152
+ logger.info('server-upload propagate: staged on agent', {
153
+ meta: {
154
+ version,
155
+ nodeId,
156
+ path: raw.path,
157
+ packageCount: raw.packageCount,
158
+ verifiedSha256: applied,
159
+ },
160
+ });
161
+ return reply.send({
162
+ success: true,
163
+ version,
164
+ nodeId,
165
+ path: raw.path,
166
+ packageCount: raw.packageCount ?? Object.keys(manifest.packages).length,
167
+ verifiedSha256: applied,
168
+ });
169
+ }
170
+ catch (err) {
171
+ const message = err instanceof Error ? err.message : String(err);
172
+ logger.warn('server-upload propagate: agent call failed', {
173
+ meta: { version, nodeId, error: message },
174
+ });
175
+ return reply.status(502).send({ error: `Agent propagate failed: ${message}` });
176
+ }
177
+ });
178
+ }
@@ -545,6 +545,8 @@ function mountAllCaps(services) {
545
545
  return {
546
546
  ...first,
547
547
  describe: (0, cap_mount_helpers_js_1.concatCollection)(providers, 'describe'),
548
+ describeTypes: (0, cap_mount_helpers_js_1.concatCollection)(providers, 'describeTypes'),
549
+ listEntries: (0, cap_mount_helpers_js_1.concatCollection)(providers, 'listEntries'),
548
550
  listJobs: (0, cap_mount_helpers_js_1.concatCollection)(providers, 'listJobs'),
549
551
  };
550
552
  }, remoteCapProxy),
@@ -7201,6 +7201,24 @@ function createCapRouter_pipelineAnalytics(getProvider, createRemoteProxy) {
7201
7201
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
7202
7202
  return p.listRetrainStaging(methodInput);
7203
7203
  }),
7204
+ listRetrainCorpusPage: trpc_middleware_js_1.adminProcedure
7205
+ .input(types_94.pipelineAnalyticsCapability.methods.listRetrainCorpusPage.input.loose())
7206
+ .output(types_94.pipelineAnalyticsCapability.methods.listRetrainCorpusPage.output)
7207
+ .query(async ({ input, ctx }) => {
7208
+ const { nodeId, ...methodInput } = input;
7209
+ const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
7210
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
7211
+ return p.listRetrainCorpusPage(methodInput);
7212
+ }),
7213
+ getRetrainCorpusKpi: trpc_middleware_js_1.adminProcedure
7214
+ .input(types_94.pipelineAnalyticsCapability.methods.getRetrainCorpusKpi.input.loose())
7215
+ .output(types_94.pipelineAnalyticsCapability.methods.getRetrainCorpusKpi.output)
7216
+ .query(async ({ input, ctx }) => {
7217
+ const { nodeId, ...methodInput } = input;
7218
+ const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
7219
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
7220
+ return p.getRetrainCorpusKpi(methodInput);
7221
+ }),
7204
7222
  listRetrainFrames: trpc_middleware_js_1.adminProcedure
7205
7223
  .input(types_94.pipelineAnalyticsCapability.methods.listRetrainFrames.input.loose())
7206
7224
  .output(types_94.pipelineAnalyticsCapability.methods.listRetrainFrames.output)
@@ -7318,51 +7336,6 @@ function createCapRouter_pipelineAnalytics(getProvider, createRemoteProxy) {
7318
7336
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
7319
7337
  return p.offerRetrainArchive(methodInput);
7320
7338
  }),
7321
- previewRetrainDataset: trpc_middleware_js_1.adminProcedure
7322
- .input(types_94.pipelineAnalyticsCapability.methods.previewRetrainDataset.input.loose())
7323
- .output(types_94.pipelineAnalyticsCapability.methods.previewRetrainDataset.output)
7324
- .query(async ({ input, ctx }) => {
7325
- const { nodeId, ...methodInput } = input;
7326
- const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
7327
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
7328
- return p.previewRetrainDataset(methodInput);
7329
- }),
7330
- createRetrainDatasetVersion: trpc_middleware_js_1.adminProcedure
7331
- .input(types_94.pipelineAnalyticsCapability.methods.createRetrainDatasetVersion.input.loose())
7332
- .output(types_94.pipelineAnalyticsCapability.methods.createRetrainDatasetVersion.output)
7333
- .mutation(async ({ input, ctx }) => {
7334
- const { nodeId, ...methodInput } = input;
7335
- const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
7336
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
7337
- return p.createRetrainDatasetVersion(methodInput);
7338
- }),
7339
- listRetrainDatasetVersions: trpc_middleware_js_1.adminProcedure
7340
- .input(types_94.pipelineAnalyticsCapability.methods.listRetrainDatasetVersions.input.loose())
7341
- .output(types_94.pipelineAnalyticsCapability.methods.listRetrainDatasetVersions.output)
7342
- .query(async ({ input, ctx }) => {
7343
- const { nodeId, ...methodInput } = input;
7344
- const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
7345
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
7346
- return p.listRetrainDatasetVersions(methodInput);
7347
- }),
7348
- deleteRetrainDatasetVersion: trpc_middleware_js_1.adminProcedure
7349
- .input(types_94.pipelineAnalyticsCapability.methods.deleteRetrainDatasetVersion.input.loose())
7350
- .output(types_94.pipelineAnalyticsCapability.methods.deleteRetrainDatasetVersion.output)
7351
- .mutation(async ({ input, ctx }) => {
7352
- const { nodeId, ...methodInput } = input;
7353
- const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
7354
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
7355
- return p.deleteRetrainDatasetVersion(methodInput);
7356
- }),
7357
- verifyRetrainDatasetVersion: trpc_middleware_js_1.adminProcedure
7358
- .input(types_94.pipelineAnalyticsCapability.methods.verifyRetrainDatasetVersion.input.loose())
7359
- .output(types_94.pipelineAnalyticsCapability.methods.verifyRetrainDatasetVersion.output)
7360
- .query(async ({ input, ctx }) => {
7361
- const { nodeId, ...methodInput } = input;
7362
- const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
7363
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
7364
- return p.verifyRetrainDatasetVersion(methodInput);
7365
- }),
7366
7339
  listRetrainAssistProfiles: trpc_middleware_js_1.adminProcedure
7367
7340
  .input(types_94.pipelineAnalyticsCapability.methods.listRetrainAssistProfiles.input.loose())
7368
7341
  .output(types_94.pipelineAnalyticsCapability.methods.listRetrainAssistProfiles.output)
@@ -7399,6 +7372,15 @@ function createCapRouter_pipelineAnalytics(getProvider, createRemoteProxy) {
7399
7372
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
7400
7373
  return p.listRetrainCollections(methodInput);
7401
7374
  }),
7375
+ resolveRetrainTrainingCorpus: trpc_middleware_js_1.adminProcedure
7376
+ .input(types_94.pipelineAnalyticsCapability.methods.resolveRetrainTrainingCorpus.input.loose())
7377
+ .output(types_94.pipelineAnalyticsCapability.methods.resolveRetrainTrainingCorpus.output)
7378
+ .query(async ({ input, ctx }) => {
7379
+ const { nodeId, ...methodInput } = input;
7380
+ const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
7381
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
7382
+ return p.resolveRetrainTrainingCorpus(methodInput);
7383
+ }),
7402
7384
  renameRetrainCollection: trpc_middleware_js_1.adminProcedure
7403
7385
  .input(types_94.pipelineAnalyticsCapability.methods.renameRetrainCollection.input.loose())
7404
7386
  .output(types_94.pipelineAnalyticsCapability.methods.renameRetrainCollection.output)
@@ -11065,51 +11047,6 @@ function createCapRouter_toast(getProvider, _createRemoteProxy) {
11065
11047
  }
11066
11048
  function createCapRouter_training(getProvider, createRemoteProxy) {
11067
11049
  return (0, trpc_middleware_js_1.trpcRouter)({
11068
- putDatasetVersion: trpc_middleware_js_1.adminProcedure
11069
- .input(types_128.trainingCapability.methods.putDatasetVersion.input.loose())
11070
- .output(types_128.trainingCapability.methods.putDatasetVersion.output)
11071
- .mutation(async ({ input, ctx }) => {
11072
- const { nodeId, ...methodInput } = input;
11073
- const p = resolveProvider('training', nodeId, () => getProvider(ctx), createRemoteProxy);
11074
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11075
- return p.putDatasetVersion(methodInput);
11076
- }),
11077
- getDatasetVersion: trpc_middleware_js_1.adminProcedure
11078
- .input(types_128.trainingCapability.methods.getDatasetVersion.input.loose())
11079
- .output(types_128.trainingCapability.methods.getDatasetVersion.output)
11080
- .query(async ({ input, ctx }) => {
11081
- const { nodeId, ...methodInput } = input;
11082
- const p = resolveProvider('training', nodeId, () => getProvider(ctx), createRemoteProxy);
11083
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11084
- return p.getDatasetVersion(methodInput);
11085
- }),
11086
- listDatasetVersions: trpc_middleware_js_1.adminProcedure
11087
- .input(types_128.trainingCapability.methods.listDatasetVersions.input.loose())
11088
- .output(types_128.trainingCapability.methods.listDatasetVersions.output)
11089
- .query(async ({ input, ctx }) => {
11090
- const { nodeId, ...methodInput } = input;
11091
- const p = resolveProvider('training', nodeId, () => getProvider(ctx), createRemoteProxy);
11092
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11093
- return p.listDatasetVersions(methodInput);
11094
- }),
11095
- findDatasetVersionIdByName: trpc_middleware_js_1.adminProcedure
11096
- .input(types_128.trainingCapability.methods.findDatasetVersionIdByName.input.loose())
11097
- .output(types_128.trainingCapability.methods.findDatasetVersionIdByName.output)
11098
- .query(async ({ input, ctx }) => {
11099
- const { nodeId, ...methodInput } = input;
11100
- const p = resolveProvider('training', nodeId, () => getProvider(ctx), createRemoteProxy);
11101
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11102
- return p.findDatasetVersionIdByName(methodInput);
11103
- }),
11104
- removeDatasetVersion: trpc_middleware_js_1.adminProcedure
11105
- .input(types_128.trainingCapability.methods.removeDatasetVersion.input.loose())
11106
- .output(types_128.trainingCapability.methods.removeDatasetVersion.output)
11107
- .mutation(async ({ input, ctx }) => {
11108
- const { nodeId, ...methodInput } = input;
11109
- const p = resolveProvider('training', nodeId, () => getProvider(ctx), createRemoteProxy);
11110
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11111
- return p.removeDatasetVersion(methodInput);
11112
- }),
11113
11050
  listBaseModels: trpc_middleware_js_1.adminProcedure
11114
11051
  .input(types_128.trainingCapability.methods.listBaseModels.input.loose())
11115
11052
  .output(types_128.trainingCapability.methods.listBaseModels.output)
@@ -11137,6 +11074,15 @@ function createCapRouter_training(getProvider, createRemoteProxy) {
11137
11074
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11138
11075
  return p.startJob(methodInput);
11139
11076
  }),
11077
+ startJobBatch: trpc_middleware_js_1.adminProcedure
11078
+ .input(types_128.trainingCapability.methods.startJobBatch.input.loose())
11079
+ .output(types_128.trainingCapability.methods.startJobBatch.output)
11080
+ .mutation(async ({ input, ctx }) => {
11081
+ const { nodeId, ...methodInput } = input;
11082
+ const p = resolveProvider('training', nodeId, () => getProvider(ctx), createRemoteProxy);
11083
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11084
+ return p.startJobBatch(methodInput);
11085
+ }),
11140
11086
  listJobs: trpc_middleware_js_1.adminProcedure
11141
11087
  .input(types_128.trainingCapability.methods.listJobs.input.loose())
11142
11088
  .output(types_128.trainingCapability.methods.listJobs.output)
@@ -11222,6 +11168,42 @@ function createCapRouter_trainingProvider(getProvider, createRemoteProxy) {
11222
11168
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11223
11169
  return p.describe(methodInput);
11224
11170
  }),
11171
+ describeTypes: trpc_middleware_js_1.adminProcedure
11172
+ .input(types_129.trainingProviderCapability.methods.describeTypes.input.loose())
11173
+ .output(types_129.trainingProviderCapability.methods.describeTypes.output)
11174
+ .query(async ({ input, ctx }) => {
11175
+ const { nodeId, addonId, ...methodInput } = input;
11176
+ const p = resolveProvider('training-provider', nodeId, () => getProvider(ctx, addonId), createRemoteProxy);
11177
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11178
+ return p.describeTypes(methodInput);
11179
+ }),
11180
+ listEntries: trpc_middleware_js_1.adminProcedure
11181
+ .input(types_129.trainingProviderCapability.methods.listEntries.input.loose())
11182
+ .output(types_129.trainingProviderCapability.methods.listEntries.output)
11183
+ .query(async ({ input, ctx }) => {
11184
+ const { nodeId, addonId, ...methodInput } = input;
11185
+ const p = resolveProvider('training-provider', nodeId, () => getProvider(ctx, addonId), createRemoteProxy);
11186
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11187
+ return p.listEntries(methodInput);
11188
+ }),
11189
+ createEntry: trpc_middleware_js_1.adminProcedure
11190
+ .input(types_129.trainingProviderCapability.methods.createEntry.input.loose())
11191
+ .output(types_129.trainingProviderCapability.methods.createEntry.output)
11192
+ .mutation(async ({ input, ctx }) => {
11193
+ const { nodeId, addonId, ...methodInput } = input;
11194
+ const p = resolveProvider('training-provider', nodeId, () => getProvider(ctx, addonId), createRemoteProxy);
11195
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11196
+ return p.createEntry(methodInput);
11197
+ }),
11198
+ deleteEntry: trpc_middleware_js_1.adminProcedure
11199
+ .input(types_129.trainingProviderCapability.methods.deleteEntry.input.loose())
11200
+ .output(types_129.trainingProviderCapability.methods.deleteEntry.output)
11201
+ .mutation(async ({ input, ctx }) => {
11202
+ const { nodeId, addonId, ...methodInput } = input;
11203
+ const p = resolveProvider('training-provider', nodeId, () => getProvider(ctx, addonId), createRemoteProxy);
11204
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11205
+ return p.deleteEntry(methodInput);
11206
+ }),
11225
11207
  validateCredentials: trpc_middleware_js_1.adminProcedure
11226
11208
  .input(types_129.trainingProviderCapability.methods.validateCredentials.input.loose())
11227
11209
  .output(types_129.trainingProviderCapability.methods.validateCredentials.output)
package/dist/main.js CHANGED
@@ -71,6 +71,7 @@ const hub_cluster_url_1 = require("./api/hub-cluster-url");
71
71
  const model_distributor_js_1 = require("./api/model-distributor.js");
72
72
  const oauth2_routes_js_1 = require("./api/oauth2/oauth2-routes.js");
73
73
  const server_upload_1 = require("./api/server-upload");
74
+ const server_upload_propagate_1 = require("./api/server-upload-propagate");
74
75
  const sse_no_compression_js_1 = require("./api/sse-no-compression.js");
75
76
  const frame_policy_1 = require("./api/static/frame-policy");
76
77
  const precompressed_asset_js_1 = require("./api/static/precompressed-asset.js");
@@ -453,6 +454,16 @@ async function bootstrap() {
453
454
  logger: app.get(logging_service_1.LoggingService).createLogger('server-upload'),
454
455
  });
455
456
  console.log('[bootstrap] Server upload route registered at POST /api/server-upload');
457
+ (0, server_upload_propagate_1.registerServerUploadPropagateRoute)(fastify, {
458
+ authService: uploadAuthService,
459
+ addonRegistry: uploadAddonRegistry,
460
+ logger: app.get(logging_service_1.LoggingService).createLogger('server-upload-propagate'),
461
+ broker: uploadMoleculer.broker,
462
+ resolveClusterBaseUrl: (0, hub_cluster_url_1.clusterBaseUrlResolver)(() => uploadAddonRegistry
463
+ .getCapabilityRegistry()
464
+ .getSingleton('local-network')),
465
+ });
466
+ console.log('[bootstrap] Server upload propagate route registered at POST /api/server-upload/propagate');
456
467
  // Companion endpoint: /api/auth/whoami — validates JWT or cst_*
457
468
  // scoped tokens, returns the resolved identity + scope summary.
458
469
  // Mirrors the addon-upload auth chain so the CLI can ping for
@@ -1474,7 +1474,7 @@ var require_dist = __commonJS({
1474
1474
  if (isDevChannelVersion(target)) {
1475
1475
  const uploadsDir = devUploadVersionDir(this.rootDir(), target);
1476
1476
  if (!fs6.existsSync(uploadsDir)) {
1477
- return this.refuseUpdate("dev-uploads-missing", target, `Refused: dev-channel version ${target} has no uploaded tarballs on this node (${uploadsDir} is missing). Dev server deploys are hub-only in this phase \u2014 upload via \`camstack deploy-server\` against this node first.`);
1477
+ return this.refuseUpdate("dev-uploads-missing", target, `Refused: dev-channel version ${target} has no uploaded tarballs on this node (${uploadsDir} is missing). On the hub: \`camstack deploy-server\`. On an agent: \`camstack deploy-server -n <nodeId>\` (or \`--all\`) so the hub can POST /api/server-upload/propagate first.`);
1478
1478
  }
1479
1479
  }
1480
1480
  this.inFlight = "staging";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.2.500",
3
+ "version": "1.2.502",
4
4
  "license": "MIT",
5
5
  "private": false,
6
6
  "files": [
@@ -37,18 +37,18 @@
37
37
  ]
38
38
  },
39
39
  "dependencies": {
40
- "@camstack/addon-admin-ui": "1.2.369",
41
- "@camstack/addon-agent-ui": "1.2.202",
40
+ "@camstack/addon-admin-ui": "1.2.370",
41
+ "@camstack/addon-agent-ui": "1.2.203",
42
42
  "@camstack/addon-auth": "1.2.136",
43
43
  "@camstack/addon-decoder-nodeav": "1.2.122",
44
44
  "@camstack/addon-notifiers": "1.2.129",
45
45
  "@camstack/addon-pipeline": "1.2.351",
46
- "@camstack/addon-pipeline-orchestrator": "1.2.304",
47
- "@camstack/addon-post-analysis": "1.2.351",
46
+ "@camstack/addon-pipeline-orchestrator": "1.2.305",
47
+ "@camstack/addon-post-analysis": "1.2.352",
48
48
  "@camstack/sdk": "1.2.129",
49
- "@camstack/system": "1.2.393",
50
- "@camstack/types": "1.2.339",
51
- "@camstack/ui-library": "1.2.259",
49
+ "@camstack/system": "1.2.395",
50
+ "@camstack/types": "1.2.340",
51
+ "@camstack/ui-library": "1.2.260",
52
52
  "@fastify/compress": "^9.0.0",
53
53
  "@fastify/cookie": "^11.0.2",
54
54
  "@fastify/cors": "^11.2.0",