@camstack/server 1.1.25 → 1.1.26

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.
@@ -243,6 +243,14 @@ class AgentRegistryService {
243
243
  * match — a single package can ship multiple addons with distinct ids
244
244
  * and placements.
245
245
  *
246
+ * Version-skew exception: a decl-id the hub has never heard of is NOT
247
+ * stale when the hub already ships that addon's PACKAGE. A newer agent
248
+ * bundle can add a decl-id within a package the hub also ships (e.g. a
249
+ * new `decoder-nodeav` inside `@camstack/addon-pipeline`); undeploying
250
+ * it would delete the whole shared bundle dir on the agent and crash
251
+ * every sibling runner. Only a decl-id whose PACKAGE is absent from the
252
+ * hub is treated as genuinely stale.
253
+ *
246
254
  * All errors are caught and logged so a single bad agent never breaks
247
255
  * the caller (connect handler or boot pass).
248
256
  */
@@ -268,14 +276,20 @@ class AgentRegistryService {
268
276
  if (agentAddons.length === 0)
269
277
  return;
270
278
  // Build the hub's placement map: decl id → placement. Absence from
271
- // this map means "not installed on the hub".
279
+ // this map means "not installed on the hub". Also collect the set of
280
+ // PACKAGE names the hub ships — used by the version-skew guard below.
272
281
  const hubPlacements = new Map();
282
+ const hubPackages = new Set();
273
283
  for (const row of this.addonRegistry.listAddons()) {
274
284
  const declId = row.manifest.id;
275
285
  if (typeof declId !== 'string')
276
286
  continue;
277
287
  const decl = row.declaration ?? row.manifest;
278
288
  hubPlacements.set(declId, (0, types_1.resolveAddonPlacement)(decl));
289
+ const packageName = row.manifest.packageName;
290
+ if (typeof packageName === 'string' && packageName.length > 0) {
291
+ hubPackages.add(packageName);
292
+ }
279
293
  }
280
294
  const stale = agentAddons.filter((addon) => {
281
295
  // Agent bootstrap infrastructure (storage/settings/metrics/logging from
@@ -289,9 +303,16 @@ class AgentRegistryService {
289
303
  return false;
290
304
  }
291
305
  const placement = hubPlacements.get(addon.id);
292
- // Not installed on the hub → stale.
293
- if (placement === undefined)
306
+ if (placement === undefined) {
307
+ // decl-id unknown to the hub. If the hub ships this PACKAGE, this is a
308
+ // version-skew sibling (a newer agent bundle added a decl-id within a
309
+ // package the hub already ships) — undeploying it would delete the whole
310
+ // shared bundle on the agent. Only undeploy when the PACKAGE itself is
311
+ // absent from the hub.
312
+ if (addon.packageName !== undefined && hubPackages.has(addon.packageName))
313
+ return false;
294
314
  return true;
315
+ }
295
316
  // Installed but pinned to the hub → must not run on an agent.
296
317
  return placement === 'hub-only';
297
318
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.1.25",
3
+ "version": "1.1.26",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist",