@camstack/system 1.2.90 → 1.2.92

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 (59) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.js +1 -1
  8. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  9. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +25 -1
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +25 -1
  11. package/dist/builtins/console-logging/index.js +1 -1
  12. package/dist/builtins/console-logging/index.mjs +1 -1
  13. package/dist/builtins/core-blocks/blocks-integration.d.ts +34 -1
  14. package/dist/builtins/core-blocks/core-block-store.d.ts +11 -0
  15. package/dist/builtins/core-blocks/core-blocks.addon.js +80 -22
  16. package/dist/builtins/core-blocks/core-blocks.addon.mjs +80 -22
  17. package/dist/builtins/device-manager/device-manager.addon.js +1 -1
  18. package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
  19. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  20. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  21. package/dist/builtins/hub-forwarder/index.js +1 -1
  22. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  23. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  24. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  25. package/dist/builtins/local-auth/auth-schema.d.ts +42 -0
  26. package/dist/builtins/local-auth/local-auth.addon.js +43 -1
  27. package/dist/builtins/local-auth/local-auth.addon.mjs +43 -1
  28. package/dist/builtins/local-network/local-network.addon.js +1 -1
  29. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  30. package/dist/builtins/loki-logging/index.js +1 -1
  31. package/dist/builtins/loki-logging/index.mjs +1 -1
  32. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  33. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  34. package/dist/builtins/platform-probe/index.js +1 -1
  35. package/dist/builtins/platform-probe/index.mjs +1 -1
  36. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  37. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  38. package/dist/builtins/snapshot/index.js +1 -1
  39. package/dist/builtins/snapshot/index.mjs +1 -1
  40. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  41. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  42. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +16 -5
  43. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +16 -5
  44. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +19 -2
  45. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +19 -2
  46. package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +12 -0
  47. package/dist/builtins/system-config/system-config.addon.js +1 -1
  48. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  49. package/dist/builtins/winston-logging/index.js +1 -1
  50. package/dist/builtins/winston-logging/index.mjs +1 -1
  51. package/dist/{dist-CYqL8oZq.js → dist-BH2tZ9ZN.js} +525 -47
  52. package/dist/{dist-DMhxx5Kr.mjs → dist-DXDvrBi0.mjs} +525 -47
  53. package/dist/index.js +78 -6
  54. package/dist/index.mjs +78 -6
  55. package/dist/kernel/addon-health-monitor.d.ts +10 -1
  56. package/dist/logging/log-manager.d.ts +28 -0
  57. package/dist/{manifest-python-deps-C0zkl1Ae.js → manifest-python-deps-BZO_eMn-.js} +1 -7
  58. package/dist/{manifest-python-deps-fWzdEasI.mjs → manifest-python-deps-D3hP9W8D.mjs} +2 -8
  59. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-Cek0wNdY.js");
3
- const require_dist = require("./dist-CYqL8oZq.js");
3
+ const require_dist = require("./dist-BH2tZ9ZN.js");
4
4
  const require_builtins_alerts_alerts_addon = require("./builtins/alerts/alerts.addon.js");
5
5
  require("./builtins/alerts/index.js");
6
6
  const require_formatter = require("./formatter-DqAKDlvN.js");
@@ -25,7 +25,7 @@ const require_builtins_system_config_system_config_addon = require("./builtins/s
25
25
  require("./builtins/system-config/index.js");
26
26
  const require_builtins_winston_logging_index = require("./builtins/winston-logging/index.js");
27
27
  const require_file_data_plane = require("./file-data-plane-DUHPHa-Y.js");
28
- const require_manifest_python_deps = require("./manifest-python-deps-C0zkl1Ae.js");
28
+ const require_manifest_python_deps = require("./manifest-python-deps-BZO_eMn-.js");
29
29
  const require_resource_monitor = require("./resource-monitor-CdnzxBLP.js");
30
30
  const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
31
31
  let zod = require("zod");
@@ -1181,6 +1181,11 @@ var LogManager = class {
1181
1181
  subscribers = /* @__PURE__ */ new Map();
1182
1182
  deviceNameLookup = null;
1183
1183
  /**
1184
+ * The bootstrap stdout sink, while one is attached. Detached — and its
1185
+ * replay suppressed — when {@link STDOUT_DESTINATION_ADDON_ID} registers.
1186
+ */
1187
+ bootstrapConsole = null;
1188
+ /**
1184
1189
  * `perAddonCapacity` bounds EACH addon's bucket, not the total — a chatty addon
1185
1190
  * evicts only its own lines, so quiet addons keep their sparse history.
1186
1191
  *
@@ -1282,13 +1287,34 @@ var LogManager = class {
1282
1287
  setDestinationEnabledCheck(check) {
1283
1288
  this.isDestinationEnabled = check ?? void 0;
1284
1289
  }
1290
+ /**
1291
+ * Attach a minimal console sink that carries the boot log until the real
1292
+ * `console-logging` builtin registers — see {@link STDOUT_DESTINATION_ADDON_ID}.
1293
+ *
1294
+ * Registered WITHOUT an `addonId` on purpose: the per-destination toggle
1295
+ * could otherwise hide the one window an operator cannot read any other way
1296
+ * (a hub that dies before pass 3 would emit nothing at all). It is detached
1297
+ * the moment the stdout owner arrives, so stdout never carries two copies.
1298
+ *
1299
+ * Idempotent: a second call while one is attached is a no-op.
1300
+ */
1301
+ attachBootstrapConsole(dest) {
1302
+ if (this.bootstrapConsole !== null) return;
1303
+ this.bootstrapConsole = dest;
1304
+ this.destinations.push({ dest });
1305
+ }
1285
1306
  addDestination(dest, opts = {}) {
1286
- const replay = opts.replay ?? true;
1307
+ const supersedesBootstrap = this.bootstrapConsole !== null && opts.addonId === "console-logging";
1308
+ if (supersedesBootstrap && this.bootstrapConsole !== null) {
1309
+ this.removeDestination(this.bootstrapConsole);
1310
+ this.bootstrapConsole = null;
1311
+ }
1312
+ const replay = opts.replay ?? !supersedesBootstrap;
1287
1313
  this.destinations.push(opts.addonId === void 0 ? { dest } : {
1288
1314
  dest,
1289
1315
  addonId: opts.addonId
1290
1316
  });
1291
- if (replay) for (const entry of this.ringBuffer.query({})) try {
1317
+ if (replay) for (const entry of [...this.ringBuffer.query({})].reverse()) try {
1292
1318
  dest.write(entry);
1293
1319
  } catch {}
1294
1320
  }
@@ -2454,9 +2480,46 @@ var DEVICE_SETTINGS_COLUMNS = [
2454
2480
  defaultValue: "string"
2455
2481
  }
2456
2482
  ];
2483
+ /**
2484
+ * @durable class=config owner=integration-registry
2485
+ * write="`createIntegration` — an operator adds a provider, or an addon declares
2486
+ * a FIXED one (`info.fixed`); `updateIntegration` rewrites name/enabled/info"
2487
+ * retention="`deleteIntegration` only, and a fixed integration refuses to be
2488
+ * deleted. Nothing ages out. The `int_NNNN` counter resumes from the highest
2489
+ * surviving row at boot, so wiping the table restarts numbering."
2490
+ */
2457
2491
  var INTEGRATIONS = "integrations";
2492
+ /**
2493
+ * @durable class=config owner=integration-registry
2494
+ * write="`setIntegrationSetting` — one row per (integration_id, key), deleted and
2495
+ * re-inserted on every write; this is the operator's per-integration intent"
2496
+ * retention="cascade only — `deleteIntegration` removes the parent's rows. There
2497
+ * is no sweep, so a key an addon stops declaring stays on disk forever."
2498
+ */
2458
2499
  var INTEGRATION_SETTINGS = "integration_settings";
2500
+ /**
2501
+ * `stable_id` carries a UNIQUE column constraint AND a UNIQUE index
2502
+ * (`idx_devices_stable`): that pair is what stops a provider re-announcing the
2503
+ * same physical camera from creating a second device row. An insert that
2504
+ * collides throws rather than duplicating.
2505
+ *
2506
+ * @durable class=config owner=integration-registry
2507
+ * write="`createDevice` — a provider adopts a device under a stable id;
2508
+ * `updateDevice` rewrites name/enabled/info"
2509
+ * retention="`deleteDevice`, or the cascade in `deleteIntegration`. Nothing ages
2510
+ * out. The `dev_NNNN` counter resumes from the highest surviving row at boot,
2511
+ * so wiping the table restarts numbering and re-adopted cameras come back
2512
+ * under DIFFERENT ids than every stored track and rule refers to."
2513
+ */
2459
2514
  var DEVICES = "devices";
2515
+ /**
2516
+ * @durable class=config owner=integration-registry
2517
+ * write="`setDeviceSetting` — one row per (device_id, key), deleted and
2518
+ * re-inserted on every write; per-camera operator intent lands here"
2519
+ * retention="cascade only — `deleteDevice` and `deleteIntegration` remove a
2520
+ * device's rows. No sweep; losing the table silently reverts every camera to
2521
+ * its defaults."
2522
+ */
2460
2523
  var DEVICE_SETTINGS = "device_settings_kv";
2461
2524
  var IntegrationRegistry = class IntegrationRegistry {
2462
2525
  store;
@@ -93904,9 +93967,18 @@ function createStreamProbeBrokerService(deps) {
93904
93967
  */
93905
93968
  var HEALTH_MONITOR_TICK_MS = 3e4;
93906
93969
  var HEALTH_MONITOR_GRACE_PERIOD_MS = 5 * 6e4;
93907
- /** Retry intervals after each failure (capped — never stops). */
93970
+ /**
93971
+ * Retry intervals after each failure (capped — never stops).
93972
+ *
93973
+ * The FIRST interval must not exceed {@link HEALTH_MONITOR_TICK_MS}: retries can
93974
+ * only fire on a tick, so anything larger just adds latency on top of a wait the
93975
+ * tick already imposes. It used to be 60 s, which meant an addon that failed to
93976
+ * load because the boot was still moving files around stayed down for 60–90 s
93977
+ * — a schedule that presumed a healthy hub (docs/design/boot-to-usable-camera.md,
93978
+ * item E). Pinned by `addon-health-monitor.spec.ts`.
93979
+ */
93908
93980
  var HEALTH_MONITOR_RETRY_INTERVALS_MS = [
93909
- 6e4,
93981
+ 3e4,
93910
93982
  12e4,
93911
93983
  3e5
93912
93984
  ];
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
2
- import { $ as objectInputDeclaresAddonId, At as createEvent, B as isArrayOutputSchema, Bt as resolveCapMount, Dt as asJsonObject$1, G as kebabToCamel, H as isObjectInput, K as lifecycleJobSchema, Lt as parseJsonObject, Nt as expandCapMethods, Ot as asNumber, R as extractNestedAddonId, Rt as parseJsonUnknown$1, Tt as ReadinessTimeoutError, Ut as EventCategory$1, V as isCollectionArrayMethod, Vt as scopeKey, W as isVoidInput, X as looseSchema, Y as logLevelAtMost, at as scopesAllowDeviceCap, bt as DEVICE_STATUS_METHOD, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, gt as errMsg$1, it as scopesAllowAddon, jt as emitDownForOwnedCaps, kt as asString$1, nt as procedureAuthKey, t as ALL_CAPABILITY_DEFINITIONS, vt as DATAPLANE_SECRET_HEADER$1, wt as ReadinessRegistry, y as addonSettingsCapability, yt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, zt as readinessKey } from "./dist-DMhxx5Kr.mjs";
2
+ import { $ as objectInputDeclaresAddonId, At as createEvent, B as isArrayOutputSchema, Bt as resolveCapMount, Dt as asJsonObject$1, G as kebabToCamel, H as isObjectInput, K as lifecycleJobSchema, Lt as parseJsonObject, Nt as expandCapMethods, Ot as asNumber, R as extractNestedAddonId, Rt as parseJsonUnknown$1, Tt as ReadinessTimeoutError, Ut as EventCategory$1, V as isCollectionArrayMethod, Vt as scopeKey, W as isVoidInput, X as looseSchema, Y as logLevelAtMost, at as scopesAllowDeviceCap, bt as DEVICE_STATUS_METHOD, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, gt as errMsg$1, it as scopesAllowAddon, jt as emitDownForOwnedCaps, kt as asString$1, nt as procedureAuthKey, t as ALL_CAPABILITY_DEFINITIONS, vt as DATAPLANE_SECRET_HEADER$1, wt as ReadinessRegistry, y as addonSettingsCapability, yt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, zt as readinessKey } from "./dist-DXDvrBi0.mjs";
3
3
  import { AlertCenterAddon } from "./builtins/alerts/alerts.addon.mjs";
4
4
  import "./builtins/alerts/index.mjs";
5
5
  import { t as formatLogLine } from "./formatter-B7qW8bPJ.mjs";
@@ -24,7 +24,7 @@ import { SystemConfigAddon } from "./builtins/system-config/system-config.addon.
24
24
  import "./builtins/system-config/index.mjs";
25
25
  import { WinstonDestination, WinstonLoggingAddon } from "./builtins/winston-logging/index.mjs";
26
26
  import { a as parseTokenizedUrl, c as collectModelFiles, d as downloadModel, f as ensureModel, h as isModelDownloaded, i as parseRangeHeader, l as deleteModelFromDisk, m as getModelFilePath, n as contentTypeFor, o as resolveFilePath, p as fetchJson, r as createAuthenticatedFileServer, s as ModelDownloadService, t as createFileDataPlaneHandler, u as downloadFile } from "./file-data-plane-CuE_hBli.mjs";
27
- import { $ as buildNativeCapProxy, A as createHubCapForwardService, B as AGENT_CAP_FWD_ACTION, C as brokerTransportLink, Ct as runNpm, D as localProviderLink, E as ipcParentLink, F as createUdsLogger, G as callWithServiceDiscovery, H as CapRouteResolver, I as createUdsLoggerWithControl, J as UdsLocalTransportServer, K as createLocalTransport, L as LocalChildClient, M as createUdsEventBridge, N as createUdsEventBus, O as HUB_CAP_FWD_ACTION, P as udsChildLogToWorkerEntry, Q as encodeFrame, R as LocalChildRegistry, S as brokerCallForCap, St as resolveNpmInvocation, T as ipcChildLink, U as CapRouteError, V as AGENT_CAP_FWD_SERVICE, W as classifyCapRoute, X as localEndpointPath, Y as SocketChannel, Z as FrameDecoder, _ as createKernelHwAccel, _t as CapabilityHandle, a as getWorkerDeviceRegistry, b as __resetCapUsageRegistryForTests, bt as installManifestNativeDeps, c as setHubConnected, ct as NATIVE_PROVIDER_SERVICE_INFIX, d as getBrokerEventBus, dt as capBareAction, et as buildUdsNativeCapProxy, f as getMoleculerEventStats, ft as capServiceName, g as AddonDepsManager, gt as DeviceRegistry, h as subscribePassthrough, ht as serializeTypedArrays, i as createUdsAddonContext, it as mountNativeCapService, j as createParentUnownedCallHandler, k as HUB_CAP_FWD_SERVICE, l as EVENT_TOPIC_PREFIX, lt as capActionName, m as setNodeEventInterest, mt as deserializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as createAddonService, p as registerEventBusService, pt as parseCapAction, q as UdsLocalTransportClient, r as createAddonContext, s as getOrInitReadinessRegistryForClient, st as validateProviderRegistrations, t as installManifestPythonDeps, tt as createBrokerDeviceManagerApi, u as clusterEventTopic, ut as capActionSuffix, v as resolveHwAccel, vt as CapabilityUnavailableError, w as buildLinkChain, wt as createAddonDataPlaneFacility, x as getCapUsageRegistry, xt as resolveAddonClass, y as CapUsageRegistry, yt as copyBundledNativeModules, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-fWzdEasI.mjs";
27
+ import { $ as buildNativeCapProxy, A as createHubCapForwardService, B as AGENT_CAP_FWD_ACTION, C as brokerTransportLink, Ct as runNpm, D as localProviderLink, E as ipcParentLink, F as createUdsLogger, G as callWithServiceDiscovery, H as CapRouteResolver, I as createUdsLoggerWithControl, J as UdsLocalTransportServer, K as createLocalTransport, L as LocalChildClient, M as createUdsEventBridge, N as createUdsEventBus, O as HUB_CAP_FWD_ACTION, P as udsChildLogToWorkerEntry, Q as encodeFrame, R as LocalChildRegistry, S as brokerCallForCap, St as resolveNpmInvocation, T as ipcChildLink, U as CapRouteError, V as AGENT_CAP_FWD_SERVICE, W as classifyCapRoute, X as localEndpointPath, Y as SocketChannel, Z as FrameDecoder, _ as createKernelHwAccel, _t as CapabilityHandle, a as getWorkerDeviceRegistry, b as __resetCapUsageRegistryForTests, bt as installManifestNativeDeps, c as setHubConnected, ct as NATIVE_PROVIDER_SERVICE_INFIX, d as getBrokerEventBus, dt as capBareAction, et as buildUdsNativeCapProxy, f as getMoleculerEventStats, ft as capServiceName, g as AddonDepsManager, gt as DeviceRegistry, h as subscribePassthrough, ht as serializeTypedArrays, i as createUdsAddonContext, it as mountNativeCapService, j as createParentUnownedCallHandler, k as HUB_CAP_FWD_SERVICE, l as EVENT_TOPIC_PREFIX, lt as capActionName, m as setNodeEventInterest, mt as deserializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as createAddonService, p as registerEventBusService, pt as parseCapAction, q as UdsLocalTransportClient, r as createAddonContext, s as getOrInitReadinessRegistryForClient, st as validateProviderRegistrations, t as installManifestPythonDeps, tt as createBrokerDeviceManagerApi, u as clusterEventTopic, ut as capActionSuffix, v as resolveHwAccel, vt as CapabilityUnavailableError, w as buildLinkChain, wt as createAddonDataPlaneFacility, x as getCapUsageRegistry, xt as resolveAddonClass, y as CapUsageRegistry, yt as copyBundledNativeModules, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-D3hP9W8D.mjs";
28
28
  import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-BWmQ5i-o.mjs";
29
29
  import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
30
30
  import { z } from "zod";
@@ -1173,6 +1173,11 @@ var LogManager = class {
1173
1173
  subscribers = /* @__PURE__ */ new Map();
1174
1174
  deviceNameLookup = null;
1175
1175
  /**
1176
+ * The bootstrap stdout sink, while one is attached. Detached — and its
1177
+ * replay suppressed — when {@link STDOUT_DESTINATION_ADDON_ID} registers.
1178
+ */
1179
+ bootstrapConsole = null;
1180
+ /**
1176
1181
  * `perAddonCapacity` bounds EACH addon's bucket, not the total — a chatty addon
1177
1182
  * evicts only its own lines, so quiet addons keep their sparse history.
1178
1183
  *
@@ -1274,13 +1279,34 @@ var LogManager = class {
1274
1279
  setDestinationEnabledCheck(check) {
1275
1280
  this.isDestinationEnabled = check ?? void 0;
1276
1281
  }
1282
+ /**
1283
+ * Attach a minimal console sink that carries the boot log until the real
1284
+ * `console-logging` builtin registers — see {@link STDOUT_DESTINATION_ADDON_ID}.
1285
+ *
1286
+ * Registered WITHOUT an `addonId` on purpose: the per-destination toggle
1287
+ * could otherwise hide the one window an operator cannot read any other way
1288
+ * (a hub that dies before pass 3 would emit nothing at all). It is detached
1289
+ * the moment the stdout owner arrives, so stdout never carries two copies.
1290
+ *
1291
+ * Idempotent: a second call while one is attached is a no-op.
1292
+ */
1293
+ attachBootstrapConsole(dest) {
1294
+ if (this.bootstrapConsole !== null) return;
1295
+ this.bootstrapConsole = dest;
1296
+ this.destinations.push({ dest });
1297
+ }
1277
1298
  addDestination(dest, opts = {}) {
1278
- const replay = opts.replay ?? true;
1299
+ const supersedesBootstrap = this.bootstrapConsole !== null && opts.addonId === "console-logging";
1300
+ if (supersedesBootstrap && this.bootstrapConsole !== null) {
1301
+ this.removeDestination(this.bootstrapConsole);
1302
+ this.bootstrapConsole = null;
1303
+ }
1304
+ const replay = opts.replay ?? !supersedesBootstrap;
1279
1305
  this.destinations.push(opts.addonId === void 0 ? { dest } : {
1280
1306
  dest,
1281
1307
  addonId: opts.addonId
1282
1308
  });
1283
- if (replay) for (const entry of this.ringBuffer.query({})) try {
1309
+ if (replay) for (const entry of [...this.ringBuffer.query({})].reverse()) try {
1284
1310
  dest.write(entry);
1285
1311
  } catch {}
1286
1312
  }
@@ -2446,9 +2472,46 @@ var DEVICE_SETTINGS_COLUMNS = [
2446
2472
  defaultValue: "string"
2447
2473
  }
2448
2474
  ];
2475
+ /**
2476
+ * @durable class=config owner=integration-registry
2477
+ * write="`createIntegration` — an operator adds a provider, or an addon declares
2478
+ * a FIXED one (`info.fixed`); `updateIntegration` rewrites name/enabled/info"
2479
+ * retention="`deleteIntegration` only, and a fixed integration refuses to be
2480
+ * deleted. Nothing ages out. The `int_NNNN` counter resumes from the highest
2481
+ * surviving row at boot, so wiping the table restarts numbering."
2482
+ */
2449
2483
  var INTEGRATIONS = "integrations";
2484
+ /**
2485
+ * @durable class=config owner=integration-registry
2486
+ * write="`setIntegrationSetting` — one row per (integration_id, key), deleted and
2487
+ * re-inserted on every write; this is the operator's per-integration intent"
2488
+ * retention="cascade only — `deleteIntegration` removes the parent's rows. There
2489
+ * is no sweep, so a key an addon stops declaring stays on disk forever."
2490
+ */
2450
2491
  var INTEGRATION_SETTINGS = "integration_settings";
2492
+ /**
2493
+ * `stable_id` carries a UNIQUE column constraint AND a UNIQUE index
2494
+ * (`idx_devices_stable`): that pair is what stops a provider re-announcing the
2495
+ * same physical camera from creating a second device row. An insert that
2496
+ * collides throws rather than duplicating.
2497
+ *
2498
+ * @durable class=config owner=integration-registry
2499
+ * write="`createDevice` — a provider adopts a device under a stable id;
2500
+ * `updateDevice` rewrites name/enabled/info"
2501
+ * retention="`deleteDevice`, or the cascade in `deleteIntegration`. Nothing ages
2502
+ * out. The `dev_NNNN` counter resumes from the highest surviving row at boot,
2503
+ * so wiping the table restarts numbering and re-adopted cameras come back
2504
+ * under DIFFERENT ids than every stored track and rule refers to."
2505
+ */
2451
2506
  var DEVICES = "devices";
2507
+ /**
2508
+ * @durable class=config owner=integration-registry
2509
+ * write="`setDeviceSetting` — one row per (device_id, key), deleted and
2510
+ * re-inserted on every write; per-camera operator intent lands here"
2511
+ * retention="cascade only — `deleteDevice` and `deleteIntegration` remove a
2512
+ * device's rows. No sweep; losing the table silently reverts every camera to
2513
+ * its defaults."
2514
+ */
2452
2515
  var DEVICE_SETTINGS = "device_settings_kv";
2453
2516
  var IntegrationRegistry = class IntegrationRegistry {
2454
2517
  store;
@@ -93896,9 +93959,18 @@ function createStreamProbeBrokerService(deps) {
93896
93959
  */
93897
93960
  var HEALTH_MONITOR_TICK_MS = 3e4;
93898
93961
  var HEALTH_MONITOR_GRACE_PERIOD_MS = 5 * 6e4;
93899
- /** Retry intervals after each failure (capped — never stops). */
93962
+ /**
93963
+ * Retry intervals after each failure (capped — never stops).
93964
+ *
93965
+ * The FIRST interval must not exceed {@link HEALTH_MONITOR_TICK_MS}: retries can
93966
+ * only fire on a tick, so anything larger just adds latency on top of a wait the
93967
+ * tick already imposes. It used to be 60 s, which meant an addon that failed to
93968
+ * load because the boot was still moving files around stayed down for 60–90 s
93969
+ * — a schedule that presumed a healthy hub (docs/design/boot-to-usable-camera.md,
93970
+ * item E). Pinned by `addon-health-monitor.spec.ts`.
93971
+ */
93900
93972
  var HEALTH_MONITOR_RETRY_INTERVALS_MS = [
93901
- 6e4,
93973
+ 3e4,
93902
93974
  12e4,
93903
93975
  3e5
93904
93976
  ];
@@ -35,7 +35,16 @@ import { IEventBus, IScopedLogger } from '@camstack/types';
35
35
  */
36
36
  export declare const HEALTH_MONITOR_TICK_MS = 30000;
37
37
  export declare const HEALTH_MONITOR_GRACE_PERIOD_MS: number;
38
- /** Retry intervals after each failure (capped — never stops). */
38
+ /**
39
+ * Retry intervals after each failure (capped — never stops).
40
+ *
41
+ * The FIRST interval must not exceed {@link HEALTH_MONITOR_TICK_MS}: retries can
42
+ * only fire on a tick, so anything larger just adds latency on top of a wait the
43
+ * tick already imposes. It used to be 60 s, which meant an addon that failed to
44
+ * load because the boot was still moving files around stayed down for 60–90 s
45
+ * — a schedule that presumed a healthy hub (docs/design/boot-to-usable-camera.md,
46
+ * item E). Pinned by `addon-health-monitor.spec.ts`.
47
+ */
39
48
  export declare const HEALTH_MONITOR_RETRY_INTERVALS_MS: readonly number[];
40
49
  export type AddonHealthPhase = 'pending' | 'healthy' | 'failed';
41
50
  export interface AddonHealthState {
@@ -14,6 +14,17 @@ export interface ILogDestination {
14
14
  * SAME orchestrator toggle as every other destination.
15
15
  */
16
16
  export declare const LOG_BUFFER_DESTINATION_ID = "log-buffer";
17
+ /**
18
+ * The addon that OWNS stdout. Every other shipped destination writes somewhere
19
+ * else (winston is file-only, loki is remote), so this is the single id whose
20
+ * arrival means "the real console is up now".
21
+ *
22
+ * It exists because the console destination is a core builtin that boots after
23
+ * the whole runner plan: a measured hub boot produced no stdout for ~40 s and
24
+ * then flushed the backlog newest-first. {@link LogManager.attachBootstrapConsole}
25
+ * covers that window, and this constant is how the handover is recognised.
26
+ */
27
+ export declare const STDOUT_DESTINATION_ADDON_ID = "console-logging";
17
28
  export declare class LogManager {
18
29
  private readonly ringBuffer;
19
30
  /**
@@ -34,6 +45,11 @@ export declare class LogManager {
34
45
  private isDestinationEnabled?;
35
46
  private readonly subscribers;
36
47
  private deviceNameLookup;
48
+ /**
49
+ * The bootstrap stdout sink, while one is attached. Detached — and its
50
+ * replay suppressed — when {@link STDOUT_DESTINATION_ADDON_ID} registers.
51
+ */
52
+ private bootstrapConsole;
37
53
  /**
38
54
  * `perAddonCapacity` bounds EACH addon's bucket, not the total — a chatty addon
39
55
  * evicts only its own lines, so quiet addons keep their sparse history.
@@ -78,6 +94,18 @@ export declare class LogManager {
78
94
  }): void;
79
95
  /** Set the per-destination enablement check (see {@link isDestinationEnabled}). */
80
96
  setDestinationEnabledCheck(check: ((addonId: string) => boolean) | null): void;
97
+ /**
98
+ * Attach a minimal console sink that carries the boot log until the real
99
+ * `console-logging` builtin registers — see {@link STDOUT_DESTINATION_ADDON_ID}.
100
+ *
101
+ * Registered WITHOUT an `addonId` on purpose: the per-destination toggle
102
+ * could otherwise hide the one window an operator cannot read any other way
103
+ * (a hub that dies before pass 3 would emit nothing at all). It is detached
104
+ * the moment the stdout owner arrives, so stdout never carries two copies.
105
+ *
106
+ * Idempotent: a second call while one is attached is a no-op.
107
+ */
108
+ attachBootstrapConsole(dest: ILogDestination): void;
81
109
  addDestination(dest: ILogDestination, opts?: {
82
110
  replay?: boolean;
83
111
  addonId?: string;
@@ -1678,13 +1678,7 @@ function createBrokerDeviceManagerApi(opts) {
1678
1678
  });
1679
1679
  return child;
1680
1680
  };
1681
- const PROBE_RETRY_BACKOFF_MS = [
1682
- 5 * 6e4,
1683
- 15 * 6e4,
1684
- 30 * 6e4,
1685
- 60 * 6e4,
1686
- 60 * 6e4
1687
- ];
1681
+ const PROBE_RETRY_BACKOFF_MS = _camstack_types_addon.BOOT_RECOVERY_BACKOFF_MS;
1688
1682
  const probeRetryTimers = /* @__PURE__ */ new Map();
1689
1683
  const cancelProbeRetry = (deviceId) => {
1690
1684
  const timer = probeRetryTimers.get(deviceId);
@@ -10,7 +10,7 @@ import * as os from "node:os";
10
10
  import { tmpdir } from "node:os";
11
11
  import * as fs from "node:fs";
12
12
  import { createServer } from "node:http";
13
- import { DATAPLANE_SECRET_HEADER, DeviceType, DisposerChain, EventCategory, ReadinessRegistry, asJsonObject, asString, createDeviceProxy, deviceOpsCapability, emitReadiness, errMsg, expandCapMethods, readNodePin, scopeKey, sleep, withCapInputDefaults } from "@camstack/types/addon";
13
+ import { BOOT_RECOVERY_BACKOFF_MS, DATAPLANE_SECRET_HEADER, DeviceType, DisposerChain, EventCategory, ReadinessRegistry, asJsonObject, asString, createDeviceProxy, deviceOpsCapability, emitReadiness, errMsg, expandCapMethods, readNodePin, scopeKey, sleep, withCapInputDefaults } from "@camstack/types/addon";
14
14
  import { TRPCClientError, createTRPCClient } from "@trpc/client";
15
15
  import { connect, createServer as createServer$1 } from "node:net";
16
16
  //#region src/kernel/moleculer/addon-data-plane-facility.ts
@@ -1676,13 +1676,7 @@ function createBrokerDeviceManagerApi(opts) {
1676
1676
  });
1677
1677
  return child;
1678
1678
  };
1679
- const PROBE_RETRY_BACKOFF_MS = [
1680
- 5 * 6e4,
1681
- 15 * 6e4,
1682
- 30 * 6e4,
1683
- 60 * 6e4,
1684
- 60 * 6e4
1685
- ];
1679
+ const PROBE_RETRY_BACKOFF_MS = BOOT_RECOVERY_BACKOFF_MS;
1686
1680
  const probeRetryTimers = /* @__PURE__ */ new Map();
1687
1681
  const cancelProbeRetry = (deviceId) => {
1688
1682
  const timer = probeRetryTimers.get(deviceId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.90",
3
+ "version": "1.2.92",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",