@camstack/system 1.2.394 → 1.2.396

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.
@@ -7,6 +7,8 @@ export declare class SystemConfigAddon extends BaseAddon {
7
7
  readonly id = "system-config";
8
8
  private clusterSecretKeeper;
9
9
  private meshCaKeeper;
10
+ /** One warn per process when a retired cutover key is posted with a cluster save. */
11
+ private retiredClusterCutoverPatchWarned;
10
12
  constructor();
11
13
  protected onInitialize(): Promise<AddonInitResult<typeof systemConfigMeshActions>>;
12
14
  protected onShutdown(): Promise<void>;
@@ -30,7 +32,7 @@ export declare class SystemConfigAddon extends BaseAddon {
30
32
  /**
31
33
  * The admin UI / `addonSettings` cap prefer {@link BaseAddon.updateGlobalSettingsAsOperator}.
32
34
  * That BaseAddon path writes the generic addon store and never reaches
33
- * {@link writeClusterSection} / {@link writeMeshClearPort}. Route the operator
35
+ * {@link writeClusterSection}. Route the operator
34
36
  * write through the same section-aware path as {@link updateGlobalSettings}.
35
37
  */
36
38
  override updateGlobalSettingsAsOperator(patch: Record<string, unknown>, _nodeId?: string): Promise<void>;
@@ -43,12 +45,8 @@ export declare class SystemConfigAddon extends BaseAddon {
43
45
  * enforced (D821) — a legacy `meshAuth` in the patch is ignored.
44
46
  */
45
47
  private writeClusterSection;
46
- /**
47
- * `cluster.meshClearPort`: `off` is REFUSED while any online agent still
48
- * connects in clear (or the TLS listener is not up); the refusal names them.
49
- * Persist, then apply — an `on` save always passes.
50
- */
51
- private writeMeshClearPort;
48
+ /** Cutover keys were removed from the Cluster form; ignore stray posts from stale clients. */
49
+ private warnRetiredClusterCutoverPatch;
52
50
  /** Persist + publish mesh auth mode (always `enforced` after D821). */
53
51
  private writeMeshAuthMode;
54
52
  /**
@@ -88102,6 +88102,8 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88102
88102
  id = "system-config";
88103
88103
  clusterSecretKeeper = null;
88104
88104
  meshCaKeeper = null;
88105
+ /** One warn per process when a retired cutover key is posted with a cluster save. */
88106
+ retiredClusterCutoverPatchWarned = false;
88105
88107
  constructor() {
88106
88108
  super({});
88107
88109
  }
@@ -88337,52 +88339,18 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88337
88339
  title: SECTION_TITLES["cluster"],
88338
88340
  description: "Agents joining this hub. Every agent proves the cluster secret when it connects (challenge–response; the secret never crosses the network).",
88339
88341
  columns: 1,
88340
- fields: [
88341
- {
88342
- type: "password",
88343
- key: CLUSTER_SECRET_FIELD,
88344
- label: "Cluster secret",
88345
- description: "Mandatory — generated by the hub at first boot and stored in the keychain. To pair an agent: Reveal and copy it here, then enter it in the agent (its status page, or the desktop setup window). Saving a new value rotates it: every agent must then be given the new one."
88346
- },
88347
- {
88348
- type: "select",
88349
- key: MESH_CLEAR_PORT_FIELD,
88350
- label: "Clear mesh port (:6000)",
88351
- description: "On keeps the clear TCP port and UDP discovery next to the TLS port (:6443). Off closes both — refused while any connected agent has not enrolled with a join token (the Cluster page shows TLS / clear per node).",
88352
- default: "on",
88353
- options: [{
88354
- value: "on",
88355
- label: "On — accept clear agents"
88356
- }, {
88357
- value: "off",
88358
- label: "Off — mutual TLS only"
88359
- }]
88360
- },
88361
- {
88362
- type: "info",
88363
- key: "meshAuthStatus",
88364
- label: "Mesh authentication",
88365
- content: describeMeshStatus(getProcessMeshAuthStatus()),
88366
- variant: "info"
88367
- },
88368
- {
88369
- type: "text",
88370
- key: AGENT_DASHBOARD_ORIGINS_FIELD,
88371
- label: "Agent dashboard origins (NPM)",
88372
- description: "Extra origins allowed for Continue-with-hub unlock redirects (comma-separated), e.g. https://agent.example.com. LAN agents on :4444 are always allowed."
88373
- },
88374
- {
88375
- type: "addon-action-button",
88376
- key: "mintJoinTokenAction",
88377
- label: "Add agent",
88378
- description: "Mint a single-use join token (≤ 1 hour). Paste it into the agent setup instead of copying the cluster secret. The token is shown once in the result.",
88379
- addonId: "system-config",
88380
- action: "mintJoinToken",
88381
- buttonLabel: "Add agent",
88382
- variant: "primary",
88383
- successMessage: "Join token (copy now): {token}"
88384
- }
88385
- ]
88342
+ fields: [{
88343
+ type: "password",
88344
+ key: CLUSTER_SECRET_FIELD,
88345
+ label: "Cluster secret",
88346
+ description: "Mandatory — generated by the hub at first boot and stored in the keychain. To pair an agent: Reveal and copy it here, then enter it in the agent (its status page, or the desktop setup window). Saving a new value rotates it: every agent must then be given the new one."
88347
+ }, {
88348
+ type: "info",
88349
+ key: "meshAuthStatus",
88350
+ label: "Mesh authentication",
88351
+ content: describeMeshStatus(getProcessMeshAuthStatus()),
88352
+ variant: "info"
88353
+ }]
88386
88354
  }
88387
88355
  ] };
88388
88356
  }
@@ -88406,7 +88374,7 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88406
88374
  /**
88407
88375
  * The admin UI / `addonSettings` cap prefer {@link BaseAddon.updateGlobalSettingsAsOperator}.
88408
88376
  * That BaseAddon path writes the generic addon store and never reaches
88409
- * {@link writeClusterSection} / {@link writeMeshClearPort}. Route the operator
88377
+ * {@link writeClusterSection}. Route the operator
88410
88378
  * write through the same section-aware path as {@link updateGlobalSettings}.
88411
88379
  */
88412
88380
  async updateGlobalSettingsAsOperator(patch, _nodeId) {
@@ -88457,8 +88425,7 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88457
88425
  */
88458
88426
  async writeClusterSection(patch) {
88459
88427
  const { [MESH_AUTH_MODE_FIELD]: _legacyMode, [MESH_CLEAR_PORT_FIELD]: clearPort, [AGENT_DASHBOARD_ORIGINS_FIELD]: dashboardOrigins, ...secretPatch } = patch;
88460
- if (clearPort !== void 0) await this.writeMeshClearPort(clearPort);
88461
- if (dashboardOrigins !== void 0) await this.ctx.settings.setSection("cluster", { [AGENT_DASHBOARD_ORIGINS_FIELD]: typeof dashboardOrigins === "string" ? dashboardOrigins : "" });
88428
+ if (clearPort !== void 0 || dashboardOrigins !== void 0) this.warnRetiredClusterCutoverPatch(clearPort !== void 0, dashboardOrigins !== void 0);
88462
88429
  await this.writeMeshAuthMode("enforced");
88463
88430
  if (Object.keys(secretPatch).length === 0) return;
88464
88431
  if (require_dist.isSecretClear(secretPatch["clusterSecret"])) throw new Error("The cluster secret is mandatory and cannot be cleared — save a new value to rotate it");
@@ -88466,26 +88433,14 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88466
88433
  this.ctx.logger.info("Cluster secret updated");
88467
88434
  await this.clusterSecretKeeper?.reload();
88468
88435
  }
88469
- /**
88470
- * `cluster.meshClearPort`: `off` is REFUSED while any online agent still
88471
- * connects in clear (or the TLS listener is not up); the refusal names them.
88472
- * Persist, then apply — an `on` save always passes.
88473
- */
88474
- async writeMeshClearPort(value) {
88475
- if (!isMeshClearPortMode(value)) throw new Error(`system-config: meshClearPort must be 'on' or 'off'`);
88476
- const stored = (await this.ctx.settings.getSection("cluster"))[MESH_CLEAR_PORT_FIELD];
88477
- if (parseMeshClearPortMode(stored) === value) return;
88478
- const decision = checkProcessMeshClearPort(value);
88479
- if (!decision.allowed) {
88480
- this.ctx.logger.warn("mesh clear port switch-off refused", { meta: {
88481
- blocking: decision.blocking,
88482
- error: decision.error
88483
- } });
88484
- throw new Error(decision.error);
88485
- }
88486
- await this.ctx.settings.setSection("cluster", { [MESH_CLEAR_PORT_FIELD]: value });
88487
- await applyProcessMeshClearPort(value);
88488
- this.ctx.logger.info("Mesh clear port switched", { meta: { mode: value } });
88436
+ /** Cutover keys were removed from the Cluster form; ignore stray posts from stale clients. */
88437
+ warnRetiredClusterCutoverPatch(hadMeshClearPort, hadAgentDashboardOrigins) {
88438
+ if (this.retiredClusterCutoverPatchWarned) return;
88439
+ this.retiredClusterCutoverPatchWarned = true;
88440
+ this.ctx.logger.warn("cluster save ignored retired cutover field(s) — use Pipeline → Cluster / Nodes", { meta: {
88441
+ meshClearPort: hadMeshClearPort,
88442
+ agentDashboardOrigins: hadAgentDashboardOrigins
88443
+ } });
88489
88444
  }
88490
88445
  /** Persist + publish mesh auth mode (always `enforced` after D821). */
88491
88446
  async writeMeshAuthMode(mode) {
@@ -88092,6 +88092,8 @@ var SystemConfigAddon = class extends BaseAddon {
88092
88092
  id = "system-config";
88093
88093
  clusterSecretKeeper = null;
88094
88094
  meshCaKeeper = null;
88095
+ /** One warn per process when a retired cutover key is posted with a cluster save. */
88096
+ retiredClusterCutoverPatchWarned = false;
88095
88097
  constructor() {
88096
88098
  super({});
88097
88099
  }
@@ -88327,52 +88329,18 @@ var SystemConfigAddon = class extends BaseAddon {
88327
88329
  title: SECTION_TITLES["cluster"],
88328
88330
  description: "Agents joining this hub. Every agent proves the cluster secret when it connects (challenge–response; the secret never crosses the network).",
88329
88331
  columns: 1,
88330
- fields: [
88331
- {
88332
- type: "password",
88333
- key: CLUSTER_SECRET_FIELD,
88334
- label: "Cluster secret",
88335
- description: "Mandatory — generated by the hub at first boot and stored in the keychain. To pair an agent: Reveal and copy it here, then enter it in the agent (its status page, or the desktop setup window). Saving a new value rotates it: every agent must then be given the new one."
88336
- },
88337
- {
88338
- type: "select",
88339
- key: MESH_CLEAR_PORT_FIELD,
88340
- label: "Clear mesh port (:6000)",
88341
- description: "On keeps the clear TCP port and UDP discovery next to the TLS port (:6443). Off closes both — refused while any connected agent has not enrolled with a join token (the Cluster page shows TLS / clear per node).",
88342
- default: "on",
88343
- options: [{
88344
- value: "on",
88345
- label: "On — accept clear agents"
88346
- }, {
88347
- value: "off",
88348
- label: "Off — mutual TLS only"
88349
- }]
88350
- },
88351
- {
88352
- type: "info",
88353
- key: "meshAuthStatus",
88354
- label: "Mesh authentication",
88355
- content: describeMeshStatus(getProcessMeshAuthStatus()),
88356
- variant: "info"
88357
- },
88358
- {
88359
- type: "text",
88360
- key: AGENT_DASHBOARD_ORIGINS_FIELD,
88361
- label: "Agent dashboard origins (NPM)",
88362
- description: "Extra origins allowed for Continue-with-hub unlock redirects (comma-separated), e.g. https://agent.example.com. LAN agents on :4444 are always allowed."
88363
- },
88364
- {
88365
- type: "addon-action-button",
88366
- key: "mintJoinTokenAction",
88367
- label: "Add agent",
88368
- description: "Mint a single-use join token (≤ 1 hour). Paste it into the agent setup instead of copying the cluster secret. The token is shown once in the result.",
88369
- addonId: "system-config",
88370
- action: "mintJoinToken",
88371
- buttonLabel: "Add agent",
88372
- variant: "primary",
88373
- successMessage: "Join token (copy now): {token}"
88374
- }
88375
- ]
88332
+ fields: [{
88333
+ type: "password",
88334
+ key: CLUSTER_SECRET_FIELD,
88335
+ label: "Cluster secret",
88336
+ description: "Mandatory — generated by the hub at first boot and stored in the keychain. To pair an agent: Reveal and copy it here, then enter it in the agent (its status page, or the desktop setup window). Saving a new value rotates it: every agent must then be given the new one."
88337
+ }, {
88338
+ type: "info",
88339
+ key: "meshAuthStatus",
88340
+ label: "Mesh authentication",
88341
+ content: describeMeshStatus(getProcessMeshAuthStatus()),
88342
+ variant: "info"
88343
+ }]
88376
88344
  }
88377
88345
  ] };
88378
88346
  }
@@ -88396,7 +88364,7 @@ var SystemConfigAddon = class extends BaseAddon {
88396
88364
  /**
88397
88365
  * The admin UI / `addonSettings` cap prefer {@link BaseAddon.updateGlobalSettingsAsOperator}.
88398
88366
  * That BaseAddon path writes the generic addon store and never reaches
88399
- * {@link writeClusterSection} / {@link writeMeshClearPort}. Route the operator
88367
+ * {@link writeClusterSection}. Route the operator
88400
88368
  * write through the same section-aware path as {@link updateGlobalSettings}.
88401
88369
  */
88402
88370
  async updateGlobalSettingsAsOperator(patch, _nodeId) {
@@ -88447,8 +88415,7 @@ var SystemConfigAddon = class extends BaseAddon {
88447
88415
  */
88448
88416
  async writeClusterSection(patch) {
88449
88417
  const { [MESH_AUTH_MODE_FIELD]: _legacyMode, [MESH_CLEAR_PORT_FIELD]: clearPort, [AGENT_DASHBOARD_ORIGINS_FIELD]: dashboardOrigins, ...secretPatch } = patch;
88450
- if (clearPort !== void 0) await this.writeMeshClearPort(clearPort);
88451
- if (dashboardOrigins !== void 0) await this.ctx.settings.setSection("cluster", { [AGENT_DASHBOARD_ORIGINS_FIELD]: typeof dashboardOrigins === "string" ? dashboardOrigins : "" });
88418
+ if (clearPort !== void 0 || dashboardOrigins !== void 0) this.warnRetiredClusterCutoverPatch(clearPort !== void 0, dashboardOrigins !== void 0);
88452
88419
  await this.writeMeshAuthMode("enforced");
88453
88420
  if (Object.keys(secretPatch).length === 0) return;
88454
88421
  if (isSecretClear(secretPatch["clusterSecret"])) throw new Error("The cluster secret is mandatory and cannot be cleared — save a new value to rotate it");
@@ -88456,26 +88423,14 @@ var SystemConfigAddon = class extends BaseAddon {
88456
88423
  this.ctx.logger.info("Cluster secret updated");
88457
88424
  await this.clusterSecretKeeper?.reload();
88458
88425
  }
88459
- /**
88460
- * `cluster.meshClearPort`: `off` is REFUSED while any online agent still
88461
- * connects in clear (or the TLS listener is not up); the refusal names them.
88462
- * Persist, then apply — an `on` save always passes.
88463
- */
88464
- async writeMeshClearPort(value) {
88465
- if (!isMeshClearPortMode(value)) throw new Error(`system-config: meshClearPort must be 'on' or 'off'`);
88466
- const stored = (await this.ctx.settings.getSection("cluster"))[MESH_CLEAR_PORT_FIELD];
88467
- if (parseMeshClearPortMode(stored) === value) return;
88468
- const decision = checkProcessMeshClearPort(value);
88469
- if (!decision.allowed) {
88470
- this.ctx.logger.warn("mesh clear port switch-off refused", { meta: {
88471
- blocking: decision.blocking,
88472
- error: decision.error
88473
- } });
88474
- throw new Error(decision.error);
88475
- }
88476
- await this.ctx.settings.setSection("cluster", { [MESH_CLEAR_PORT_FIELD]: value });
88477
- await applyProcessMeshClearPort(value);
88478
- this.ctx.logger.info("Mesh clear port switched", { meta: { mode: value } });
88426
+ /** Cutover keys were removed from the Cluster form; ignore stray posts from stale clients. */
88427
+ warnRetiredClusterCutoverPatch(hadMeshClearPort, hadAgentDashboardOrigins) {
88428
+ if (this.retiredClusterCutoverPatchWarned) return;
88429
+ this.retiredClusterCutoverPatchWarned = true;
88430
+ this.ctx.logger.warn("cluster save ignored retired cutover field(s) — use Pipeline → Cluster / Nodes", { meta: {
88431
+ meshClearPort: hadMeshClearPort,
88432
+ agentDashboardOrigins: hadAgentDashboardOrigins
88433
+ } });
88479
88434
  }
88480
88435
  /** Persist + publish mesh auth mode (always `enforced` after D821). */
88481
88436
  async writeMeshAuthMode(mode) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.394",
3
+ "version": "1.2.396",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",