@camstack/agent 1.0.8 → 1.1.0
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.
- package/dist/{chunk-U6SD2QE6.mjs → chunk-PFQZTXGW.mjs} +87 -16
- package/dist/chunk-PFQZTXGW.mjs.map +1 -0
- package/dist/cli.js +81 -14
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +81 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +3 -2
- package/dist/chunk-U6SD2QE6.mjs.map +0 -1
package/dist/cli.mjs
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -75,6 +75,8 @@ interface AgentServiceDeps {
|
|
|
75
75
|
* presenting a matching `clusterSecretHash`. (Cluster-secret gate.)
|
|
76
76
|
*/
|
|
77
77
|
readonly expectedClusterSecretHash?: string;
|
|
78
|
+
/** Pull-install a published addon from npm/GHCR (wired by agent-bootstrap). */
|
|
79
|
+
readonly installFromNpm?: (packageName: string, version: string) => Promise<void>;
|
|
78
80
|
}
|
|
79
81
|
declare function createAgentService(deps: AgentServiceDeps): ServiceSchema;
|
|
80
82
|
|
package/dist/index.js
CHANGED
|
@@ -176,6 +176,29 @@ async function applyDeployedBundle(input) {
|
|
|
176
176
|
return { addonDir: liveDir };
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
// src/fetch-bundle-from-hub.ts
|
|
180
|
+
var import_node_crypto2 = require("crypto");
|
|
181
|
+
var import_undici = require("undici");
|
|
182
|
+
async function fetchBundleFromHub(opts) {
|
|
183
|
+
const authHeader = { Authorization: `Bearer ${opts.token}` };
|
|
184
|
+
const res = opts.fetchImpl ? await opts.fetchImpl(opts.url, { headers: authHeader }) : await (0, import_undici.fetch)(opts.url, {
|
|
185
|
+
headers: authHeader,
|
|
186
|
+
dispatcher: new import_undici.Agent({ connect: { rejectUnauthorized: false } })
|
|
187
|
+
});
|
|
188
|
+
if (!res.ok) {
|
|
189
|
+
throw new Error(`bundle fetch failed: HTTP ${res.status}`);
|
|
190
|
+
}
|
|
191
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
192
|
+
if (buffer.length !== opts.bytes) {
|
|
193
|
+
throw new Error(`bundle bytes mismatch: expected ${opts.bytes}, got ${buffer.length}`);
|
|
194
|
+
}
|
|
195
|
+
const sha = (0, import_node_crypto2.createHash)("sha256").update(buffer).digest("hex");
|
|
196
|
+
if (sha !== opts.sha256) {
|
|
197
|
+
throw new Error(`bundle sha256 mismatch: expected ${opts.sha256}, got ${sha}`);
|
|
198
|
+
}
|
|
199
|
+
return buffer;
|
|
200
|
+
}
|
|
201
|
+
|
|
179
202
|
// src/agent-service.ts
|
|
180
203
|
var deploySwapLogger = {
|
|
181
204
|
info: (msg) => console.log(`[Agent] ${msg}`),
|
|
@@ -209,6 +232,28 @@ async function withTimeout(p, ms, fallback) {
|
|
|
209
232
|
}
|
|
210
233
|
}
|
|
211
234
|
var METRICS_SNAPSHOT_TIMEOUT_MS = 2e3;
|
|
235
|
+
function resolveDeployAction(seam) {
|
|
236
|
+
return async (params) => {
|
|
237
|
+
const { addonId, source, bundle } = params;
|
|
238
|
+
if (source && (0, import_system.isAddonDeploySource)(source)) {
|
|
239
|
+
if (source.kind === "npm") {
|
|
240
|
+
await seam.installFromNpm(addonId, source.version);
|
|
241
|
+
return { success: true, addonId };
|
|
242
|
+
}
|
|
243
|
+
const buf2 = await seam.fetchBundle(source);
|
|
244
|
+
const { addonDir: addonDir2 } = await seam.applyBundle(buf2);
|
|
245
|
+
seam.onApplied(addonDir2);
|
|
246
|
+
return { success: true, addonId, path: addonDir2 };
|
|
247
|
+
}
|
|
248
|
+
if (bundle === void 0) {
|
|
249
|
+
throw new Error("$agent.deploy: no source descriptor and no legacy bundle provided");
|
|
250
|
+
}
|
|
251
|
+
const buf = typeof bundle === "string" ? Buffer.from(bundle, "base64") : bundle;
|
|
252
|
+
const { addonDir } = await seam.applyBundle(buf);
|
|
253
|
+
seam.onApplied(addonDir);
|
|
254
|
+
return { success: true, addonId, path: addonDir };
|
|
255
|
+
};
|
|
256
|
+
}
|
|
212
257
|
function readHubAddressFromConfig(configPath) {
|
|
213
258
|
if (!configPath) return null;
|
|
214
259
|
try {
|
|
@@ -381,8 +426,7 @@ function createAgentService(deps) {
|
|
|
381
426
|
deploy: {
|
|
382
427
|
handler: async (ctx) => {
|
|
383
428
|
const { params } = ctx;
|
|
384
|
-
const { addonId, bundle } = params;
|
|
385
|
-
const bufferData = typeof bundle === "string" ? Buffer.from(bundle, "base64") : bundle;
|
|
429
|
+
const { addonId, source, bundle } = params;
|
|
386
430
|
const { execFile } = await import("child_process");
|
|
387
431
|
const { promisify } = await import("util");
|
|
388
432
|
const execFileAsync = promisify(execFile);
|
|
@@ -400,17 +444,37 @@ function createAgentService(deps) {
|
|
|
400
444
|
}
|
|
401
445
|
}
|
|
402
446
|
};
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
447
|
+
const seam = {
|
|
448
|
+
installFromNpm: (pkg, v) => {
|
|
449
|
+
if (!deps.installFromNpm) {
|
|
450
|
+
throw new Error("npm deploy source unsupported on this agent");
|
|
451
|
+
}
|
|
452
|
+
return deps.installFromNpm(pkg, v);
|
|
453
|
+
},
|
|
454
|
+
applyBundle: (buf) => applyDeployedBundle({
|
|
455
|
+
addonsDir: deps.addonsDir,
|
|
456
|
+
addonId,
|
|
457
|
+
bundle: buf,
|
|
458
|
+
extract,
|
|
459
|
+
logger: deploySwapLogger
|
|
460
|
+
}),
|
|
461
|
+
fetchBundle: (s) => fetchBundleFromHub(s),
|
|
462
|
+
// Evict every addon DECLARATION id this package contributes
|
|
463
|
+
// from `loadedAddons` so the follow-up `$agent.reload` actually
|
|
464
|
+
// re-instantiates it. `loadDeployedAddons` skips any addon
|
|
465
|
+
// still present in `loadedAddons`; without this eviction a
|
|
466
|
+
// redeploy would leave the agent pinned to the pre-update
|
|
467
|
+
// version. The `deploy` param `addonId` is the PACKAGE name
|
|
468
|
+
// (used only as the on-disk dir), whereas `loadedAddons` is
|
|
469
|
+
// keyed by the addon DECLARATION id — they differ for scoped
|
|
470
|
+
// packages, so we read the extracted manifest to bridge them.
|
|
471
|
+
onApplied: (addonDir) => {
|
|
472
|
+
for (const declId of readDeployedAddonIds(addonDir)) {
|
|
473
|
+
deps.loadedAddons.delete(declId);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
return resolveDeployAction(seam)({ addonId, source, bundle });
|
|
414
478
|
}
|
|
415
479
|
},
|
|
416
480
|
/**
|
|
@@ -1082,7 +1146,10 @@ async function startAgent(configPath) {
|
|
|
1082
1146
|
subtree.registerNode(params);
|
|
1083
1147
|
triggerUpwardRegistration();
|
|
1084
1148
|
},
|
|
1085
|
-
expectedClusterSecretHash: config.secret ? (0, import_system3.hashClusterSecret)(config.secret) : void 0
|
|
1149
|
+
expectedClusterSecretHash: config.secret ? (0, import_system3.hashClusterSecret)(config.secret) : void 0,
|
|
1150
|
+
installFromNpm: async (pkg, version) => {
|
|
1151
|
+
await installer.install(pkg, version);
|
|
1152
|
+
}
|
|
1086
1153
|
});
|
|
1087
1154
|
broker.createService(agentServiceSchema);
|
|
1088
1155
|
const agentTcpPort = (0, import_system3.deriveAgentListenPort)(broker.nodeID);
|