@camstack/system 1.2.436 → 1.2.438

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.
Files changed (96) hide show
  1. package/dist/addon-runner.js +64 -12
  2. package/dist/addon-runner.mjs +65 -13
  3. package/dist/{agent-https-B8lKYVtU.mjs → agent-https-BPfHrI4c.mjs} +3 -3
  4. package/dist/auth/login-session-manager.d.ts +2 -0
  5. package/dist/auth/session-revocation-bus.d.ts +32 -0
  6. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  7. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  9. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  10. package/dist/builtins/alerts/alerts.addon.js +7 -1
  11. package/dist/builtins/alerts/alerts.addon.mjs +7 -1
  12. package/dist/builtins/autotrack/index.js +1 -1
  13. package/dist/builtins/autotrack/index.mjs +1 -1
  14. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
  15. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
  16. package/dist/builtins/calendars/calendars.addon.js +1 -1
  17. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  18. package/dist/builtins/camera-grid/index.js +9 -1
  19. package/dist/builtins/camera-grid/index.mjs +9 -1
  20. package/dist/builtins/composer/composer.addon.js +2 -2
  21. package/dist/builtins/composer/composer.addon.mjs +2 -2
  22. package/dist/builtins/console-logging/index.js +12 -5
  23. package/dist/builtins/console-logging/index.mjs +12 -5
  24. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  25. package/dist/builtins/core-blocks/core-blocks.addon.mjs +5 -5
  26. package/dist/builtins/device-manager/device-manager.addon.d.ts +5 -0
  27. package/dist/builtins/device-manager/device-manager.addon.js +702 -28
  28. package/dist/builtins/device-manager/device-manager.addon.mjs +702 -28
  29. package/dist/builtins/device-manager/device-meta-types.d.ts +4 -0
  30. package/dist/builtins/device-manager/device-provider-context.d.ts +9 -0
  31. package/dist/builtins/device-manager/device-removal-hooks.d.ts +103 -0
  32. package/dist/builtins/device-manager/device-row-store.d.ts +1 -0
  33. package/dist/builtins/device-manager/device-tombstone-store.d.ts +58 -0
  34. package/dist/builtins/device-manager/removal-cleanup.d.ts +50 -0
  35. package/dist/builtins/hub-forwarder/index.js +1 -1
  36. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  37. package/dist/builtins/keychain/index.js +37 -4
  38. package/dist/builtins/keychain/index.mjs +37 -4
  39. package/dist/builtins/keychain/keychain-service.d.ts +14 -0
  40. package/dist/builtins/keychain/keychain-store.d.ts +1 -1
  41. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  42. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  43. package/dist/builtins/local-auth/local-auth.addon.js +53 -12
  44. package/dist/builtins/local-auth/local-auth.addon.mjs +53 -13
  45. package/dist/builtins/local-network/local-network.addon.js +10 -1
  46. package/dist/builtins/local-network/local-network.addon.mjs +13 -4
  47. package/dist/builtins/loki-logging/index.js +28 -5
  48. package/dist/builtins/loki-logging/index.mjs +28 -5
  49. package/dist/builtins/native-metrics/native-metrics.addon.js +11 -1
  50. package/dist/builtins/native-metrics/native-metrics.addon.mjs +20 -10
  51. package/dist/builtins/platform-probe/index.js +1 -1
  52. package/dist/builtins/platform-probe/index.mjs +8 -8
  53. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  54. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  55. package/dist/builtins/snapshot/index.js +11 -1
  56. package/dist/builtins/snapshot/index.mjs +11 -1
  57. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +4 -1
  58. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +4 -1
  59. package/dist/builtins/sqlite-storage/index.js +1 -1
  60. package/dist/builtins/sqlite-storage/index.mjs +1 -1
  61. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +3 -3
  62. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +3 -3
  63. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  64. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  65. package/dist/builtins/system-config/system-config.addon.d.ts +9 -0
  66. package/dist/builtins/system-config/system-config.addon.js +135 -72
  67. package/dist/builtins/system-config/system-config.addon.mjs +135 -73
  68. package/dist/builtins/winston-logging/index.js +14 -5
  69. package/dist/builtins/winston-logging/index.mjs +14 -5
  70. package/dist/{composition-sources-BAOlCu4j.js → composition-sources-DI3Z83vG.js} +1 -1
  71. package/dist/{composition-sources-gN_BWUKp.mjs → composition-sources-DpHGCjdL.mjs} +1 -1
  72. package/dist/{constants-BFpowodq.mjs → constants-DQK705Sb.mjs} +1 -1
  73. package/dist/{constants-GENKqk9k.js → constants-wkcn5Ij3.js} +1 -1
  74. package/dist/{device-ca-CuWuRW9N.js → device-ca-BSvkXqyI.js} +1 -1
  75. package/dist/{device-ca-BNM5ai4t.mjs → device-ca-DvIZjXIl.mjs} +1 -1
  76. package/dist/{dist-DjD2M79P.mjs → dist-Dc8GKC5H.mjs} +301 -6
  77. package/dist/{dist-DVe0Nsp8.js → dist-GgG-7amw.js} +348 -5
  78. package/dist/file-host-worker.js +1 -1
  79. package/dist/file-host-worker.mjs +1 -1
  80. package/dist/{hub-mdns-ciao-DJRwtlA8.mjs → hub-mdns-ciao-DMlQTdPU.mjs} +1 -1
  81. package/dist/i18n/catalog-registry.d.ts +35 -0
  82. package/dist/i18n/index.d.ts +2 -0
  83. package/dist/index.d.ts +3 -0
  84. package/dist/index.js +666 -21
  85. package/dist/index.mjs +676 -38
  86. package/dist/kernel/gc-census.d.ts +18 -1
  87. package/dist/kernel/settings-view-types.d.ts +2 -0
  88. package/dist/kernel/transport/local-transport.d.ts +3 -0
  89. package/dist/kernel/transport/peer-answered-error.d.ts +5 -1
  90. package/dist/{restore-archive-D4h904rb.js → restore-archive-CTRz8v9o.js} +1 -1
  91. package/dist/{restore-archive-BxmP1ChO.mjs → restore-archive-DPg9duVY.mjs} +1 -1
  92. package/dist/{retired-settings-keys-CYP5IZJ5.js → retired-settings-keys-Dr_4lfKu.js} +1 -1
  93. package/dist/{retired-settings-keys-CQaknvx1.mjs → retired-settings-keys-Is0zO8gX.mjs} +1 -1
  94. package/dist/{wal-maintenance-CaDsrJM_.mjs → wal-maintenance-Bx3lcVA7.mjs} +0 -0
  95. package/dist/{wal-maintenance-Br60onAQ.js → wal-maintenance-mjB2i-VR.js} +0 -0
  96. package/package.json +1 -1
@@ -1578,7 +1578,8 @@ function formatOutboundQueueVerdict(label, verdict) {
1578
1578
  }
1579
1579
  //#endregion
1580
1580
  //#region src/kernel/gc-census.ts
1581
- function countsOf(entries, kinds) {
1581
+ function countsOf(entries, kinds, flagBits) {
1582
+ const flags = {};
1582
1583
  let majors = 0;
1583
1584
  let minors = 0;
1584
1585
  let incrementals = 0;
@@ -1588,13 +1589,17 @@ function countsOf(entries, kinds) {
1588
1589
  else if (e.kind === kinds.minor) minors++;
1589
1590
  else if (e.kind === kinds.incremental) incrementals++;
1590
1591
  pauseMs += e.durationMs;
1592
+ if (e.flags !== void 0) {
1593
+ for (const f of flagBits) if ((e.flags & f.bit) !== 0) flags[f.name] = (flags[f.name] ?? 0) + 1;
1594
+ }
1591
1595
  }
1592
1596
  return {
1593
1597
  majors,
1594
1598
  minors,
1595
1599
  incrementals,
1596
1600
  pauseMs,
1597
- windowMs: 0
1601
+ windowMs: 0,
1602
+ ...Object.keys(flags).length > 0 ? { flags } : {}
1598
1603
  };
1599
1604
  }
1600
1605
  /**
@@ -1606,7 +1611,7 @@ function countsOf(entries, kinds) {
1606
1611
  * observed and a process that is not collecting look identical on the line, and
1607
1612
  * they are the two answers furthest apart.
1608
1613
  */
1609
- function createGcCensus(install, kinds, startedAt) {
1614
+ function createGcCensus(install, kinds, startedAt, flagBits = []) {
1610
1615
  let pending = [];
1611
1616
  const stopObserving = install((entry) => {
1612
1617
  pending.push(entry);
@@ -1621,7 +1626,7 @@ function createGcCensus(install, kinds, startedAt) {
1621
1626
  pending = [];
1622
1627
  windowStart = at;
1623
1628
  return {
1624
- ...countsOf(taken, kinds),
1629
+ ...countsOf(taken, kinds, flagBits),
1625
1630
  windowMs
1626
1631
  };
1627
1632
  },
@@ -1646,14 +1651,18 @@ function nodeGcObserver() {
1646
1651
  minor: 1,
1647
1652
  incremental: 8
1648
1653
  }),
1654
+ flagBits: readFlagBits(),
1649
1655
  install: (observe) => {
1650
1656
  try {
1651
1657
  const observer = new (process.getBuiltinModule("node:perf_hooks")).PerformanceObserver((list) => {
1652
1658
  for (const entry of list.getEntries()) {
1653
1659
  const detail = "detail" in entry ? entry.detail : void 0;
1660
+ const kind = typeof detail === "object" && detail !== null && "kind" in detail && typeof detail.kind === "number" ? detail.kind : -1;
1661
+ const flags = typeof detail === "object" && detail !== null && "flags" in detail && typeof detail.flags === "number" ? detail.flags : void 0;
1654
1662
  observe({
1655
- kind: typeof detail === "object" && detail !== null && "kind" in detail && typeof detail.kind === "number" ? detail.kind : -1,
1656
- durationMs: entry.duration
1663
+ kind,
1664
+ durationMs: entry.duration,
1665
+ ...flags !== void 0 ? { flags } : {}
1657
1666
  });
1658
1667
  }
1659
1668
  });
@@ -1667,6 +1676,25 @@ function nodeGcObserver() {
1667
1676
  }
1668
1677
  };
1669
1678
  }
1679
+ var GC_FLAG_PREFIX = "NODE_PERFORMANCE_GC_FLAGS_";
1680
+ /**
1681
+ * The flag bits, read from `perf_hooks.constants` by their prefix so a flag V8
1682
+ * adds tomorrow gets a name without anyone editing a table. `NO` (0) can never
1683
+ * match a bit and is dropped.
1684
+ */
1685
+ function readFlagBits() {
1686
+ try {
1687
+ const perf = process.getBuiltinModule("node:perf_hooks");
1688
+ const bits = [];
1689
+ for (const [key, value] of Object.entries(perf.constants)) if (key.startsWith(GC_FLAG_PREFIX) && typeof value === "number" && value > 0) bits.push({
1690
+ name: key.slice(26),
1691
+ bit: value
1692
+ });
1693
+ return bits;
1694
+ } catch {
1695
+ return [];
1696
+ }
1697
+ }
1670
1698
  function readKinds(fallback) {
1671
1699
  try {
1672
1700
  const c = process.getBuiltinModule("node:perf_hooks").constants;
@@ -1693,7 +1721,14 @@ function readKinds(fallback) {
1693
1721
  function formatGcCensus(window) {
1694
1722
  if (window === null || window === void 0) return "";
1695
1723
  const perMin = (n) => window.windowMs <= 0 ? "?" : (n / (window.windowMs / 6e4)).toFixed(1);
1696
- return ` gc=maj${window.majors}/min${window.minors}/inc${window.incrementals}@${Math.round(window.windowMs / 1e3)}s gcMajPerMin=${perMin(window.majors)} gcPauseMs=${Math.round(window.pauseMs)}`;
1724
+ return ` gc=maj${window.majors}/min${window.minors}/inc${window.incrementals}@${Math.round(window.windowMs / 1e3)}s gcMajPerMin=${perMin(window.majors)} gcPauseMs=${Math.round(window.pauseMs)}` + formatGcFlags(window.flags);
1725
+ }
1726
+ /** ` gcFlags=ALL_EXTERNAL_MEMORY:12,FORCED:1` — most frequent first; empty when none. */
1727
+ function formatGcFlags(flags) {
1728
+ if (flags === void 0) return "";
1729
+ const entries = Object.entries(flags).toSorted((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
1730
+ if (entries.length === 0) return "";
1731
+ return ` gcFlags=${entries.map(([name, n]) => `${name}:${n}`).join(",")}`;
1697
1732
  }
1698
1733
  /**
1699
1734
  * The census. Always exists — `process.cpuUsage()` is available on every
@@ -2440,7 +2475,7 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
2440
2475
  const readMemory = reclaimOptions?.readMemory ?? (() => process.memoryUsage());
2441
2476
  const now = reclaimOptions?.now ?? (() => Date.now());
2442
2477
  const gcObserver = probes?.gcObserver ?? nodeGcObserver();
2443
- const gcCensus = createGcCensus(gcObserver.install, gcObserver.kinds, now());
2478
+ const gcCensus = createGcCensus(gcObserver.install, gcObserver.kinds, now(), gcObserver.flagBits);
2444
2479
  const cpuProbe = probes?.processCpu;
2445
2480
  const processCpu = createProcessCpuCensus({
2446
2481
  cpuUsageUs: cpuProbe?.cpuUsageUs ?? (() => {
@@ -2494,6 +2529,7 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
2494
2529
  };
2495
2530
  let mode = "steady";
2496
2531
  let lastLoggedAt = Number.NEGATIVE_INFINITY;
2532
+ let firstLinePending = true;
2497
2533
  const budgetMb = rssBudget?.budgetMb !== void 0 && rssBudget.budgetMb > 0 ? rssBudget.budgetMb : void 0;
2498
2534
  const budgetSource = rssBudget?.source ?? "unspecified";
2499
2535
  const releaseRatio = rssBudget?.releaseRatio ?? .9;
@@ -2552,7 +2588,9 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
2552
2588
  const due = at - lastLoggedAt >= intervalMs;
2553
2589
  if (mode === "escalated" || due) {
2554
2590
  lastLoggedAt = at;
2555
- const line = format(label, sample, loopDelay?.read(), budgetMb, `${formatHeapSpaces(readSpaces())}${formatEventPlane(eventPlane?.read())}` + formatSocketPlane(socketPlane?.read()) + formatMeshQueue(meshQueue?.()) + formatGcCensus(gcCensus?.read(at)) + formatProcessCpu(processCpu.read(at)));
2591
+ const firstLine = firstLinePending;
2592
+ firstLinePending = false;
2593
+ const line = format(label, sample, loopDelay?.read(), budgetMb, `${formatHeapSpaces(readSpaces(), firstLine ? 0 : void 0)}${formatEventPlane(eventPlane?.read())}` + formatSocketPlane(socketPlane?.read()) + formatMeshQueue(meshQueue?.()) + formatGcCensus(gcCensus?.read(at)) + formatProcessCpu(processCpu.read(at)));
2556
2594
  if (sample.nearLimit) sink.warn(`${line} — APPROACHING HEAP LIMIT`);
2557
2595
  else if (mode === "escalated") sink.warn(`${line} — heap elevated, sampling every ${probeIntervalMs}ms`);
2558
2596
  else sink.info(line);
@@ -2775,9 +2813,14 @@ function capBareAction(capName, method) {
2775
2813
  * node had answered (2026-09-25, device 3836).
2776
2814
  */
2777
2815
  var PeerAnsweredError = class extends Error {
2778
- constructor(message) {
2816
+ /** The far end's stable error code (D863), carried so the hub can translate it. */
2817
+ i18nCode;
2818
+ i18nParams;
2819
+ constructor(message, i18n) {
2779
2820
  super(message);
2780
2821
  this.name = "PeerAnsweredError";
2822
+ this.i18nCode = i18n?.code;
2823
+ this.i18nParams = i18n?.params;
2781
2824
  }
2782
2825
  };
2783
2826
  /**
@@ -4306,6 +4349,13 @@ var PayloadReply = class {
4306
4349
  this.payload = payload;
4307
4350
  }
4308
4351
  };
4352
+ //#endregion
4353
+ //#region src/kernel/transport/socket-channel.ts
4354
+ /** A peer's `i18n` is untrusted wire data: a malformed one is dropped, the message still travels. */
4355
+ function parseWireI18n(raw) {
4356
+ const parsed = _camstack_types_addon.ErrorI18nPayloadSchema.safeParse(raw);
4357
+ return parsed.success ? parsed.data : void 0;
4358
+ }
4309
4359
  var SocketChannel = class {
4310
4360
  socket;
4311
4361
  nextId = 1;
@@ -4517,11 +4567,13 @@ var SocketChannel = class {
4517
4567
  body: result
4518
4568
  });
4519
4569
  } catch (err) {
4570
+ const i18n = (0, _camstack_types_addon.readErrorI18n)(err);
4520
4571
  resBytes = this.send({
4521
4572
  k: "res",
4522
4573
  id: frame.id,
4523
4574
  ok: false,
4524
- err: err instanceof Error ? err.message : String(err)
4575
+ err: err instanceof Error ? err.message : String(err),
4576
+ ...i18n !== null ? { i18n } : {}
4525
4577
  });
4526
4578
  }
4527
4579
  if (label !== void 0) this.recordAction(label, wireBytes, resBytes);
@@ -4533,7 +4585,7 @@ var SocketChannel = class {
4533
4585
  this.pending.delete(frame.id);
4534
4586
  if (p.timer !== null) clearTimeout(p.timer);
4535
4587
  if (p.action !== null) this.recordAction(p.action.label, p.action.reqBytes, wireBytes);
4536
- if (!frame.ok) p.reject(new PeerAnsweredError(frame.err));
4588
+ if (!frame.ok) p.reject(new PeerAnsweredError(frame.err, parseWireI18n(frame.i18n)));
4537
4589
  else if (frame.pl !== void 0) p.resolve(new PayloadReply(frame.body, frame.pl));
4538
4590
  else p.resolve(frame.body);
4539
4591
  return;
@@ -3,7 +3,7 @@ import * as fs from "node:fs";
3
3
  import { createReadStream, createWriteStream, existsSync, readFileSync, readdirSync } from "node:fs";
4
4
  import * as path from "node:path";
5
5
  import { dirname, isAbsolute, join } from "node:path";
6
- import { BOOT_RECOVERY_BACKOFF_MS, DATAPLANE_SECRET_HEADER, DEVICE_CHILDREN_BATCH_MAX, DeviceType, DisposerChain, EventCategory, PEER_BYTES_CHUNK_BYTES, PEER_BYTES_MAX_OUTSTANDING, PEER_BYTES_STALL_MS, PEER_BYTES_TICKET_TTL_MS, ReadinessRegistry, ReadinessTimeoutError, asJsonObject, asString, collectZodSecretPaths, createDeviceProxy, createEventBusSliceSource, createSecretsAccess, describeCustomActions, deviceOpsCapability, emitReadiness, errMsg, expandCapMethods, isCollectionArrayMethodName, isProviderOptionalMethodName, maskUrlCredentials, normalizeAddonInitResult, readNodePin, resolveSecretViewsIn, scopeKey, scrubKnownSecrets, withCapInputDefaults } from "@camstack/types/addon";
6
+ import { BOOT_RECOVERY_BACKOFF_MS, DATAPLANE_SECRET_HEADER, DEVICE_CHILDREN_BATCH_MAX, DeviceType, DisposerChain, ErrorI18nPayloadSchema, EventCategory, PEER_BYTES_CHUNK_BYTES, PEER_BYTES_MAX_OUTSTANDING, PEER_BYTES_STALL_MS, PEER_BYTES_TICKET_TTL_MS, ReadinessRegistry, ReadinessTimeoutError, asJsonObject, asString, collectZodSecretPaths, createDeviceProxy, createEventBusSliceSource, createSecretsAccess, describeCustomActions, deviceOpsCapability, emitReadiness, errMsg, expandCapMethods, isCollectionArrayMethodName, isProviderOptionalMethodName, maskUrlCredentials, normalizeAddonInitResult, readErrorI18n, readNodePin, resolveSecretViewsIn, scopeKey, scrubKnownSecrets, withCapInputDefaults } from "@camstack/types/addon";
7
7
  import { execFile } from "node:child_process";
8
8
  import { promisify } from "node:util";
9
9
  import * as os from "node:os";
@@ -1554,7 +1554,8 @@ function formatOutboundQueueVerdict(label, verdict) {
1554
1554
  }
1555
1555
  //#endregion
1556
1556
  //#region src/kernel/gc-census.ts
1557
- function countsOf(entries, kinds) {
1557
+ function countsOf(entries, kinds, flagBits) {
1558
+ const flags = {};
1558
1559
  let majors = 0;
1559
1560
  let minors = 0;
1560
1561
  let incrementals = 0;
@@ -1564,13 +1565,17 @@ function countsOf(entries, kinds) {
1564
1565
  else if (e.kind === kinds.minor) minors++;
1565
1566
  else if (e.kind === kinds.incremental) incrementals++;
1566
1567
  pauseMs += e.durationMs;
1568
+ if (e.flags !== void 0) {
1569
+ for (const f of flagBits) if ((e.flags & f.bit) !== 0) flags[f.name] = (flags[f.name] ?? 0) + 1;
1570
+ }
1567
1571
  }
1568
1572
  return {
1569
1573
  majors,
1570
1574
  minors,
1571
1575
  incrementals,
1572
1576
  pauseMs,
1573
- windowMs: 0
1577
+ windowMs: 0,
1578
+ ...Object.keys(flags).length > 0 ? { flags } : {}
1574
1579
  };
1575
1580
  }
1576
1581
  /**
@@ -1582,7 +1587,7 @@ function countsOf(entries, kinds) {
1582
1587
  * observed and a process that is not collecting look identical on the line, and
1583
1588
  * they are the two answers furthest apart.
1584
1589
  */
1585
- function createGcCensus(install, kinds, startedAt) {
1590
+ function createGcCensus(install, kinds, startedAt, flagBits = []) {
1586
1591
  let pending = [];
1587
1592
  const stopObserving = install((entry) => {
1588
1593
  pending.push(entry);
@@ -1597,7 +1602,7 @@ function createGcCensus(install, kinds, startedAt) {
1597
1602
  pending = [];
1598
1603
  windowStart = at;
1599
1604
  return {
1600
- ...countsOf(taken, kinds),
1605
+ ...countsOf(taken, kinds, flagBits),
1601
1606
  windowMs
1602
1607
  };
1603
1608
  },
@@ -1622,14 +1627,18 @@ function nodeGcObserver() {
1622
1627
  minor: 1,
1623
1628
  incremental: 8
1624
1629
  }),
1630
+ flagBits: readFlagBits(),
1625
1631
  install: (observe) => {
1626
1632
  try {
1627
1633
  const observer = new (process.getBuiltinModule("node:perf_hooks")).PerformanceObserver((list) => {
1628
1634
  for (const entry of list.getEntries()) {
1629
1635
  const detail = "detail" in entry ? entry.detail : void 0;
1636
+ const kind = typeof detail === "object" && detail !== null && "kind" in detail && typeof detail.kind === "number" ? detail.kind : -1;
1637
+ const flags = typeof detail === "object" && detail !== null && "flags" in detail && typeof detail.flags === "number" ? detail.flags : void 0;
1630
1638
  observe({
1631
- kind: typeof detail === "object" && detail !== null && "kind" in detail && typeof detail.kind === "number" ? detail.kind : -1,
1632
- durationMs: entry.duration
1639
+ kind,
1640
+ durationMs: entry.duration,
1641
+ ...flags !== void 0 ? { flags } : {}
1633
1642
  });
1634
1643
  }
1635
1644
  });
@@ -1643,6 +1652,25 @@ function nodeGcObserver() {
1643
1652
  }
1644
1653
  };
1645
1654
  }
1655
+ var GC_FLAG_PREFIX = "NODE_PERFORMANCE_GC_FLAGS_";
1656
+ /**
1657
+ * The flag bits, read from `perf_hooks.constants` by their prefix so a flag V8
1658
+ * adds tomorrow gets a name without anyone editing a table. `NO` (0) can never
1659
+ * match a bit and is dropped.
1660
+ */
1661
+ function readFlagBits() {
1662
+ try {
1663
+ const perf = process.getBuiltinModule("node:perf_hooks");
1664
+ const bits = [];
1665
+ for (const [key, value] of Object.entries(perf.constants)) if (key.startsWith(GC_FLAG_PREFIX) && typeof value === "number" && value > 0) bits.push({
1666
+ name: key.slice(26),
1667
+ bit: value
1668
+ });
1669
+ return bits;
1670
+ } catch {
1671
+ return [];
1672
+ }
1673
+ }
1646
1674
  function readKinds(fallback) {
1647
1675
  try {
1648
1676
  const c = process.getBuiltinModule("node:perf_hooks").constants;
@@ -1669,7 +1697,14 @@ function readKinds(fallback) {
1669
1697
  function formatGcCensus(window) {
1670
1698
  if (window === null || window === void 0) return "";
1671
1699
  const perMin = (n) => window.windowMs <= 0 ? "?" : (n / (window.windowMs / 6e4)).toFixed(1);
1672
- return ` gc=maj${window.majors}/min${window.minors}/inc${window.incrementals}@${Math.round(window.windowMs / 1e3)}s gcMajPerMin=${perMin(window.majors)} gcPauseMs=${Math.round(window.pauseMs)}`;
1700
+ return ` gc=maj${window.majors}/min${window.minors}/inc${window.incrementals}@${Math.round(window.windowMs / 1e3)}s gcMajPerMin=${perMin(window.majors)} gcPauseMs=${Math.round(window.pauseMs)}` + formatGcFlags(window.flags);
1701
+ }
1702
+ /** ` gcFlags=ALL_EXTERNAL_MEMORY:12,FORCED:1` — most frequent first; empty when none. */
1703
+ function formatGcFlags(flags) {
1704
+ if (flags === void 0) return "";
1705
+ const entries = Object.entries(flags).toSorted((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
1706
+ if (entries.length === 0) return "";
1707
+ return ` gcFlags=${entries.map(([name, n]) => `${name}:${n}`).join(",")}`;
1673
1708
  }
1674
1709
  /**
1675
1710
  * The census. Always exists — `process.cpuUsage()` is available on every
@@ -2416,7 +2451,7 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
2416
2451
  const readMemory = reclaimOptions?.readMemory ?? (() => process.memoryUsage());
2417
2452
  const now = reclaimOptions?.now ?? (() => Date.now());
2418
2453
  const gcObserver = probes?.gcObserver ?? nodeGcObserver();
2419
- const gcCensus = createGcCensus(gcObserver.install, gcObserver.kinds, now());
2454
+ const gcCensus = createGcCensus(gcObserver.install, gcObserver.kinds, now(), gcObserver.flagBits);
2420
2455
  const cpuProbe = probes?.processCpu;
2421
2456
  const processCpu = createProcessCpuCensus({
2422
2457
  cpuUsageUs: cpuProbe?.cpuUsageUs ?? (() => {
@@ -2470,6 +2505,7 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
2470
2505
  };
2471
2506
  let mode = "steady";
2472
2507
  let lastLoggedAt = Number.NEGATIVE_INFINITY;
2508
+ let firstLinePending = true;
2473
2509
  const budgetMb = rssBudget?.budgetMb !== void 0 && rssBudget.budgetMb > 0 ? rssBudget.budgetMb : void 0;
2474
2510
  const budgetSource = rssBudget?.source ?? "unspecified";
2475
2511
  const releaseRatio = rssBudget?.releaseRatio ?? .9;
@@ -2528,7 +2564,9 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
2528
2564
  const due = at - lastLoggedAt >= intervalMs;
2529
2565
  if (mode === "escalated" || due) {
2530
2566
  lastLoggedAt = at;
2531
- const line = format(label, sample, loopDelay?.read(), budgetMb, `${formatHeapSpaces(readSpaces())}${formatEventPlane(eventPlane?.read())}` + formatSocketPlane(socketPlane?.read()) + formatMeshQueue(meshQueue?.()) + formatGcCensus(gcCensus?.read(at)) + formatProcessCpu(processCpu.read(at)));
2567
+ const firstLine = firstLinePending;
2568
+ firstLinePending = false;
2569
+ const line = format(label, sample, loopDelay?.read(), budgetMb, `${formatHeapSpaces(readSpaces(), firstLine ? 0 : void 0)}${formatEventPlane(eventPlane?.read())}` + formatSocketPlane(socketPlane?.read()) + formatMeshQueue(meshQueue?.()) + formatGcCensus(gcCensus?.read(at)) + formatProcessCpu(processCpu.read(at)));
2532
2570
  if (sample.nearLimit) sink.warn(`${line} — APPROACHING HEAP LIMIT`);
2533
2571
  else if (mode === "escalated") sink.warn(`${line} — heap elevated, sampling every ${probeIntervalMs}ms`);
2534
2572
  else sink.info(line);
@@ -2751,9 +2789,14 @@ function capBareAction(capName, method) {
2751
2789
  * node had answered (2026-09-25, device 3836).
2752
2790
  */
2753
2791
  var PeerAnsweredError = class extends Error {
2754
- constructor(message) {
2792
+ /** The far end's stable error code (D863), carried so the hub can translate it. */
2793
+ i18nCode;
2794
+ i18nParams;
2795
+ constructor(message, i18n) {
2755
2796
  super(message);
2756
2797
  this.name = "PeerAnsweredError";
2798
+ this.i18nCode = i18n?.code;
2799
+ this.i18nParams = i18n?.params;
2757
2800
  }
2758
2801
  };
2759
2802
  /**
@@ -4282,6 +4325,13 @@ var PayloadReply = class {
4282
4325
  this.payload = payload;
4283
4326
  }
4284
4327
  };
4328
+ //#endregion
4329
+ //#region src/kernel/transport/socket-channel.ts
4330
+ /** A peer's `i18n` is untrusted wire data: a malformed one is dropped, the message still travels. */
4331
+ function parseWireI18n(raw) {
4332
+ const parsed = ErrorI18nPayloadSchema.safeParse(raw);
4333
+ return parsed.success ? parsed.data : void 0;
4334
+ }
4285
4335
  var SocketChannel = class {
4286
4336
  socket;
4287
4337
  nextId = 1;
@@ -4493,11 +4543,13 @@ var SocketChannel = class {
4493
4543
  body: result
4494
4544
  });
4495
4545
  } catch (err) {
4546
+ const i18n = readErrorI18n(err);
4496
4547
  resBytes = this.send({
4497
4548
  k: "res",
4498
4549
  id: frame.id,
4499
4550
  ok: false,
4500
- err: err instanceof Error ? err.message : String(err)
4551
+ err: err instanceof Error ? err.message : String(err),
4552
+ ...i18n !== null ? { i18n } : {}
4501
4553
  });
4502
4554
  }
4503
4555
  if (label !== void 0) this.recordAction(label, wireBytes, resBytes);
@@ -4509,7 +4561,7 @@ var SocketChannel = class {
4509
4561
  this.pending.delete(frame.id);
4510
4562
  if (p.timer !== null) clearTimeout(p.timer);
4511
4563
  if (p.action !== null) this.recordAction(p.action.label, p.action.reqBytes, wireBytes);
4512
- if (!frame.ok) p.reject(new PeerAnsweredError(frame.err));
4564
+ if (!frame.ok) p.reject(new PeerAnsweredError(frame.err, parseWireI18n(frame.i18n)));
4513
4565
  else if (frame.pl !== void 0) p.resolve(new PayloadReply(frame.body, frame.pl));
4514
4566
  else p.resolve(frame.body);
4515
4567
  return;
@@ -3,7 +3,7 @@ import { X509Certificate, createHash, createPrivateKey, randomBytes, webcrypto }
3
3
  import { writeOwnerOnlyFileSync } from "@camstack/types/node";
4
4
  import { isIP } from "node:net";
5
5
  import { join } from "node:path";
6
- import * as os from "node:os";
6
+ import * as os$1 from "node:os";
7
7
  import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
8
8
  //#region src/tls/agent-https-names.ts
9
9
  /**
@@ -189,8 +189,8 @@ function evaluateExistingCert(input) {
189
189
  /** The real machine. The only place in `tls/` that touches `os`. */
190
190
  function systemHostFacts() {
191
191
  return {
192
- hostname: os.hostname(),
193
- networkInterfaces: os.networkInterfaces()
192
+ hostname: os$1.hostname(),
193
+ networkInterfaces: os$1.networkInterfaces()
194
194
  };
195
195
  }
196
196
  /**
@@ -121,6 +121,8 @@ export declare class LoginSessionManager {
121
121
  listActive(): readonly LoginSessionSummary[];
122
122
  /** Delete rows expired more than 7 days ago or revoked more than 30. Returns how many. */
123
123
  reap(): Promise<number>;
124
+ /** Tell the hub which sessions just ended — right after the mirror, before the store write. */
125
+ private announce;
124
126
  private newRefreshToken;
125
127
  private remember;
126
128
  private forget;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * "These login sessions just ended" — the one announcement every revoke path
3
+ * of the login-session table makes, so the hub can end what those sessions
4
+ * still HOLD (open WebSockets, live media). A revoked `sid` is refused on the
5
+ * next call; without this the socket stays open and the client keeps polling
6
+ * as an anonymous principal.
7
+ *
8
+ * Process-global (`Symbol.for`), like the hub-internal user-management surface:
9
+ * the table lives in `local-auth` and the listener in the hub, and neither may
10
+ * import the other. Listeners are synchronous; one that throws never reaches
11
+ * the revoke (reported to `onListenerError`).
12
+ */
13
+ import type { LoginSessionRevocation } from "./login-session-manager.js";
14
+ export interface SessionsRevokedEvent {
15
+ /** The sessions that ended just now (never one that was already ended). */
16
+ readonly sessionIds: readonly string[];
17
+ /** The user they belong to, when the revoke named one. */
18
+ readonly userId: string | null;
19
+ /**
20
+ * The revoke was "everything of this user" (logout everywhere, password
21
+ * change or reset, deletion): a connection of `userId` that carries NO
22
+ * session id (a pre-session token) ends too, except `exceptSessionId`.
23
+ */
24
+ readonly allOfUser: boolean;
25
+ readonly exceptSessionId: string | null;
26
+ readonly reason: LoginSessionRevocation;
27
+ }
28
+ export type SessionsRevokedListener = (event: SessionsRevokedEvent) => void;
29
+ /** Subscribe; returns the unsubscribe. */
30
+ export declare function onSessionsRevoked(listener: SessionsRevokedListener): () => void;
31
+ /** Announce an ended batch. A listener that throws never reaches the revoke. */
32
+ export declare function announceSessionsRevoked(event: SessionsRevokedEvent, onListenerError?: (error: unknown) => void): void;
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DVe0Nsp8.js");
6
+ const require_dist = require("../../dist-GgG-7amw.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { Q as addonPagesCapability, br as errMsg, di as EventCategory, xr as BaseAddon } from "../../dist-DjD2M79P.mjs";
1
+ import { Dr as errMsg, Or as BaseAddon, nt as addonPagesCapability, yi as EventCategory } from "../../dist-Dc8GKC5H.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DVe0Nsp8.js");
6
+ const require_dist = require("../../dist-GgG-7amw.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { br as errMsg, di as EventCategory, et as addonWidgetsCapability, xr as BaseAddon } from "../../dist-DjD2M79P.mjs";
1
+ import { Dr as errMsg, Or as BaseAddon, it as addonWidgetsCapability, yi as EventCategory } from "../../dist-Dc8GKC5H.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DVe0Nsp8.js");
6
+ const require_dist = require("../../dist-GgG-7amw.js");
7
7
  //#region src/builtins/alerts/device-label.ts
8
8
  /**
9
9
  * Operator-facing device label for alert messages.
@@ -235,13 +235,17 @@ var AlertCenterAddon = class extends require_dist.BaseAddon {
235
235
  return this.schema({ sections: [{
236
236
  id: "alerts",
237
237
  title: "Alert Center",
238
+ titleKey: "server:globalSettings.s_alerts.title",
238
239
  description: "Configure alert storage and retention.",
240
+ descriptionKey: "server:globalSettings.s_alerts.description",
239
241
  columns: 1,
240
242
  fields: [this.field({
241
243
  type: "number",
242
244
  key: "maxAlerts",
243
245
  label: "Maximum stored alerts",
246
+ labelKey: "server:globalSettings.s_alerts.maxAlerts.label",
244
247
  description: "Oldest read alerts are deleted when this limit is exceeded.",
248
+ descriptionKey: "server:globalSettings.s_alerts.maxAlerts.description",
245
249
  min: 50,
246
250
  max: 5e3,
247
251
  step: 50,
@@ -250,7 +254,9 @@ var AlertCenterAddon = class extends require_dist.BaseAddon {
250
254
  type: "number",
251
255
  key: "retentionDays",
252
256
  label: "Alert retention (days)",
257
+ labelKey: "server:globalSettings.s_alerts.retentionDays.label",
253
258
  description: "Alerts older than this are automatically removed.",
259
+ descriptionKey: "server:globalSettings.s_alerts.retentionDays.description",
254
260
  min: 1,
255
261
  max: 365,
256
262
  step: 1,
@@ -1,4 +1,4 @@
1
- import { Lr as createEvent, br as errMsg, di as EventCategory, i as AlertSchema, tt as alertsCapability, xr as BaseAddon } from "../../dist-DjD2M79P.mjs";
1
+ import { Dr as errMsg, Or as BaseAddon, Wr as createEvent, at as alertsCapability, i as AlertSchema, yi as EventCategory } from "../../dist-Dc8GKC5H.mjs";
2
2
  //#region src/builtins/alerts/device-label.ts
3
3
  /**
4
4
  * Operator-facing device label for alert messages.
@@ -230,13 +230,17 @@ var AlertCenterAddon = class extends BaseAddon {
230
230
  return this.schema({ sections: [{
231
231
  id: "alerts",
232
232
  title: "Alert Center",
233
+ titleKey: "server:globalSettings.s_alerts.title",
233
234
  description: "Configure alert storage and retention.",
235
+ descriptionKey: "server:globalSettings.s_alerts.description",
234
236
  columns: 1,
235
237
  fields: [this.field({
236
238
  type: "number",
237
239
  key: "maxAlerts",
238
240
  label: "Maximum stored alerts",
241
+ labelKey: "server:globalSettings.s_alerts.maxAlerts.label",
239
242
  description: "Oldest read alerts are deleted when this limit is exceeded.",
243
+ descriptionKey: "server:globalSettings.s_alerts.maxAlerts.description",
240
244
  min: 50,
241
245
  max: 5e3,
242
246
  step: 50,
@@ -245,7 +249,9 @@ var AlertCenterAddon = class extends BaseAddon {
245
249
  type: "number",
246
250
  key: "retentionDays",
247
251
  label: "Alert retention (days)",
252
+ labelKey: "server:globalSettings.s_alerts.retentionDays.label",
248
253
  description: "Alerts older than this are automatically removed.",
254
+ descriptionKey: "server:globalSettings.s_alerts.retentionDays.description",
249
255
  min: 1,
250
256
  max: 365,
251
257
  step: 1,
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DVe0Nsp8.js");
6
+ const require_dist = require("../../dist-GgG-7amw.js");
7
7
  //#region src/builtins/autotrack/autotrack-config.ts
8
8
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
9
9
  deadZoneFraction: .5,
@@ -1,4 +1,4 @@
1
- import { Dn as ptzAutotrackCapability, Kr as isEvent, br as errMsg, di as EventCategory, it as bareAddonId, k as FIRST_LEVEL_MACRO_CLASSES, xr as BaseAddon } from "../../dist-DjD2M79P.mjs";
1
+ import { $r as isEvent, Dr as errMsg, M as FIRST_LEVEL_MACRO_CLASSES, Mn as ptzAutotrackCapability, Or as BaseAddon, ct as bareAddonId, yi as EventCategory } from "../../dist-Dc8GKC5H.mjs";
2
2
  //#region src/builtins/autotrack/autotrack-config.ts
3
3
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
4
4
  deadZoneFraction: .5,
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DVe0Nsp8.js");
7
- const require_restore_archive = require("../../restore-archive-D4h904rb.js");
6
+ const require_dist = require("../../dist-GgG-7amw.js");
7
+ const require_restore_archive = require("../../restore-archive-CTRz8v9o.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_fs_promises = require("node:fs/promises");
10
10
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -1,5 +1,5 @@
1
- import { Zr as nodePin, ci as toNodeId, di as EventCategory, pn as mayWriteToLocation, qn as storageOccupancyCapability, rt as backupCapability, xr as BaseAddon } from "../../dist-DjD2M79P.mjs";
2
- import { a as BackupSnapshotRefusedError, d as ENCRYPTED_BACKUP_SUFFIX, f as generateBackupKeyPair, i as BackupCancelledError, l as BackupKeyFormatError, m as parseBackupSecretKey, n as precheckRestoreKey, o as DEFAULT_BACKUP_DATABASES, p as parseBackupPublicKey, r as prepareRestoreArchive, s as SystemBackupService } from "../../restore-archive-BxmP1ChO.mjs";
1
+ import { Or as BaseAddon, er as storageOccupancyCapability, hi as toNodeId, ii as nodePin, st as backupCapability, vn as mayWriteToLocation, yi as EventCategory } from "../../dist-Dc8GKC5H.mjs";
2
+ import { a as BackupSnapshotRefusedError, d as ENCRYPTED_BACKUP_SUFFIX, f as generateBackupKeyPair, i as BackupCancelledError, l as BackupKeyFormatError, m as parseBackupSecretKey, n as precheckRestoreKey, o as DEFAULT_BACKUP_DATABASES, p as parseBackupPublicKey, r as prepareRestoreArchive, s as SystemBackupService } from "../../restore-archive-DPg9duVY.mjs";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import * as fsp from "node:fs/promises";
5
5
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DVe0Nsp8.js");
6
+ const require_dist = require("../../dist-GgG-7amw.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let zod = require("zod");
9
9
  //#region src/builtins/calendars/calendar-color.ts
@@ -1,4 +1,4 @@
1
- import { h as CalendarPreferencesSchema, ut as calendarsCapability, xr as BaseAddon } from "../../dist-DjD2M79P.mjs";
1
+ import { Or as BaseAddon, g as CalendarPreferencesSchema, mt as calendarsCapability } from "../../dist-Dc8GKC5H.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { z } from "zod";
4
4
  //#region src/builtins/calendars/calendar-color.ts