@camstack/system 1.2.62 → 1.2.64

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 (90) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/addon-utils.js +1 -1
  4. package/dist/addon-utils.mjs +1 -1
  5. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  9. package/dist/builtins/alerts/alerts.addon.js +1 -1
  10. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +3 -3
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
  13. package/dist/builtins/console-logging/index.js +1 -1
  14. package/dist/builtins/console-logging/index.mjs +1 -1
  15. package/dist/builtins/core-blocks/block-package.d.ts +9 -27
  16. package/dist/builtins/core-blocks/block-supervisor.d.ts +15 -0
  17. package/dist/builtins/core-blocks/core-blocks.addon.js +91 -24
  18. package/dist/builtins/core-blocks/core-blocks.addon.mjs +91 -25
  19. package/dist/builtins/device-manager/device-bindings-store.d.ts +28 -5
  20. package/dist/builtins/device-manager/device-linked-devices.d.ts +2 -2
  21. package/dist/builtins/device-manager/device-manager.addon.d.ts +3 -45
  22. package/dist/builtins/device-manager/device-manager.addon.js +123 -884
  23. package/dist/builtins/device-manager/device-manager.addon.mjs +123 -884
  24. package/dist/builtins/device-manager/device-meta-actions.d.ts +0 -8
  25. package/dist/builtins/device-manager/device-meta-store.d.ts +1 -28
  26. package/dist/builtins/device-manager/device-meta-types.d.ts +2 -6
  27. package/dist/builtins/device-manager/device-projection.d.ts +1 -2
  28. package/dist/builtins/device-manager/device-provider-context.d.ts +2 -13
  29. package/dist/builtins/device-manager/device-queries.d.ts +1 -1
  30. package/dist/builtins/device-manager/device-state-mirror.d.ts +8 -49
  31. package/dist/builtins/device-manager/device-sync-resolvers.d.ts +0 -11
  32. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  33. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  34. package/dist/builtins/hub-forwarder/index.js +1 -1
  35. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  36. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  37. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  38. package/dist/builtins/local-auth/homeassistant-integration.d.ts +7 -0
  39. package/dist/builtins/local-auth/index.d.ts +1 -0
  40. package/dist/builtins/local-auth/index.js +1 -0
  41. package/dist/builtins/local-auth/index.mjs +2 -2
  42. package/dist/builtins/local-auth/local-auth.addon.js +561 -497
  43. package/dist/builtins/local-auth/local-auth.addon.mjs +580 -517
  44. package/dist/builtins/local-auth/oauth-grants.d.ts +11 -0
  45. package/dist/builtins/local-auth/oauth-session-manager.d.ts +1 -1
  46. package/dist/builtins/local-network/local-network.addon.js +1 -1
  47. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  48. package/dist/builtins/loki-logging/index.js +1 -1
  49. package/dist/builtins/loki-logging/index.mjs +1 -1
  50. package/dist/builtins/native-metrics/native-metrics.addon.js +2 -2
  51. package/dist/builtins/native-metrics/native-metrics.addon.mjs +2 -2
  52. package/dist/builtins/platform-probe/index.js +2 -2
  53. package/dist/builtins/platform-probe/index.mjs +2 -2
  54. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  55. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  56. package/dist/builtins/snapshot/index.js +319 -20
  57. package/dist/builtins/snapshot/index.mjs +319 -20
  58. package/dist/builtins/snapshot/snapshot-keep-warm.d.ts +86 -0
  59. package/dist/builtins/snapshot/snapshot-media-handler.d.ts +48 -1
  60. package/dist/builtins/snapshot/snapshot.addon.d.ts +65 -1
  61. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  62. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  63. package/dist/builtins/sqlite-storage/retired-settings-keys.d.ts +15 -0
  64. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +73 -7
  65. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +73 -7
  66. package/dist/builtins/sqlite-storage/vector-index-vec.d.ts +19 -0
  67. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  68. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  69. package/dist/builtins/system-config/system-config.addon.js +1 -1
  70. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  71. package/dist/builtins/winston-logging/index.js +1 -1
  72. package/dist/builtins/winston-logging/index.mjs +1 -1
  73. package/dist/{dist-DnKpFaP1.mjs → dist-CMb7aKS0.mjs} +1227 -1330
  74. package/dist/{dist-DgPUarcs.js → dist-DP3nHlNM.js} +1251 -1366
  75. package/dist/http/asset-compression.d.ts +93 -0
  76. package/dist/index.d.ts +1 -1
  77. package/dist/index.js +64 -9
  78. package/dist/index.mjs +65 -11
  79. package/dist/kernel/heap-watch.d.ts +55 -0
  80. package/dist/kernel/moleculer/device-cap-proxy.d.ts +2 -2
  81. package/dist/{manifest-python-deps-d4acYXVV.js → manifest-python-deps-BE6l8Y4W.js} +21 -15
  82. package/dist/{manifest-python-deps-CX5tGRqf.mjs → manifest-python-deps-Dz1ryHIN.mjs} +21 -15
  83. package/dist/{model-download-service-D8B-4ktF.mjs → model-download-service-CTBHzORJ.mjs} +220 -2
  84. package/dist/{model-download-service-Cpc6SWzV.js → model-download-service-Caj1kaSi.js} +220 -2
  85. package/package.json +5 -1
  86. package/dist/builtins/device-manager/device-link-cycle.d.ts +0 -18
  87. package/dist/builtins/device-manager/device-link-overlay.d.ts +0 -33
  88. package/dist/builtins/device-manager/device-link-resolver.d.ts +0 -44
  89. package/dist/main-CVLq8IzA.js +0 -2356
  90. package/dist/main-CzH19GkU.mjs +0 -2353
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_manifest_python_deps = require("./manifest-python-deps-d4acYXVV.js");
2
+ const require_manifest_python_deps = require("./manifest-python-deps-BE6l8Y4W.js");
3
3
  const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
4
4
  let node_v8 = require("node:v8");
5
5
  node_v8 = require_chunk.__toESM(node_v8);
@@ -1,4 +1,4 @@
1
- import { Ct as resolveAddonClass, I as createUdsLoggerWithControl, L as LocalChildClient, at as setWorkerNativeCapsChangeListener, bt as installManifestNativeDeps, i as createUdsAddonContext, nt as getWorkerNativeCapProvider, rt as getWorkerNativeCapSnapshot, st as validateProviderRegistrations, t as installManifestPythonDeps } from "./manifest-python-deps-CX5tGRqf.mjs";
1
+ import { Ct as resolveAddonClass, I as createUdsLoggerWithControl, L as LocalChildClient, at as setWorkerNativeCapsChangeListener, bt as installManifestNativeDeps, i as createUdsAddonContext, nt as getWorkerNativeCapProvider, rt as getWorkerNativeCapSnapshot, st as validateProviderRegistrations, t as installManifestPythonDeps } from "./manifest-python-deps-Dz1ryHIN.mjs";
2
2
  import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
3
3
  import { register } from "node:module";
4
4
  import * as v8 from "node:v8";
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("./chunk-Cek0wNdY.js");
3
- const require_model_download_service = require("./model-download-service-Cpc6SWzV.js");
3
+ const require_model_download_service = require("./model-download-service-Caj1kaSi.js");
4
4
  const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
5
5
  exports.CustomActionRegistry = require_custom_action_registry.CustomActionRegistry;
6
6
  exports.ModelDownloadService = require_model_download_service.ModelDownloadService;
@@ -1,3 +1,3 @@
1
- import { c as getModelFilePath, d as contentTypeFor, i as downloadFile, l as isModelDownloaded, n as collectModelFiles, o as ensureModel, p as parseRangeHeader, r as deleteModelFromDisk, t as ModelDownloadService, u as createFileDataPlaneHandler } from "./model-download-service-D8B-4ktF.mjs";
1
+ import { c as getModelFilePath, d as contentTypeFor, i as downloadFile, l as isModelDownloaded, n as collectModelFiles, o as ensureModel, p as parseRangeHeader, r as deleteModelFromDisk, t as ModelDownloadService, u as createFileDataPlaneHandler } from "./model-download-service-CTBHzORJ.mjs";
2
2
  import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
3
3
  export { CustomActionRegistry, ModelDownloadService, collectModelFiles, contentTypeFor, createFileDataPlaneHandler, deleteModelFromDisk, downloadFile, ensureModel, getModelFilePath, isModelDownloaded, parseRangeHeader };
@@ -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-DgPUarcs.js");
6
+ const require_dist = require("../../dist-DP3nHlNM.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_fs = require("node:fs");
@@ -1,4 +1,4 @@
1
- import { ft as errMsg, m as addonPagesCapability, pt as BaseAddon, zt as EventCategory } from "../../dist-DnKpFaP1.mjs";
1
+ import { Lt as EventCategory, dt as BaseAddon, h as addonPagesCapability, ut as errMsg } from "../../dist-CMb7aKS0.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import * as fs from "node:fs";
@@ -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-DgPUarcs.js");
6
+ const require_dist = require("../../dist-DP3nHlNM.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_fs = require("node:fs");
@@ -1,4 +1,4 @@
1
- import { ft as errMsg, g as addonWidgetsCapability, pt as BaseAddon, zt as EventCategory } from "../../dist-DnKpFaP1.mjs";
1
+ import { Lt as EventCategory, _ as addonWidgetsCapability, dt as BaseAddon, ut as errMsg } from "../../dist-CMb7aKS0.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import * as fs from "node:fs";
@@ -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-DgPUarcs.js");
6
+ const require_dist = require("../../dist-DP3nHlNM.js");
7
7
  //#region src/builtins/alerts/prune-policy.ts
8
8
  /**
9
9
  * Ids older than `cutoffMs`, oldest first.
@@ -1,4 +1,4 @@
1
- import { Et as createEvent, _ as alertsCapability, ft as errMsg, n as AlertSchema, pt as BaseAddon, zt as EventCategory } from "../../dist-DnKpFaP1.mjs";
1
+ import { Lt as EventCategory, dt as BaseAddon, n as AlertSchema, ut as errMsg, v as alertsCapability, wt as createEvent } from "../../dist-CMb7aKS0.mjs";
2
2
  //#region src/builtins/alerts/prune-policy.ts
3
3
  /**
4
4
  * Ids older than `cutoffMs`, oldest first.
@@ -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-DgPUarcs.js");
6
+ const require_dist = require("../../dist-DP3nHlNM.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_fs = require("node:fs");
9
9
  let node_fs$1 = require_chunk.__toESM(node_fs, 1);
@@ -11,6 +11,8 @@ node_fs = require_chunk.__toESM(node_fs);
11
11
  let node_path = require("node:path");
12
12
  let node_path$1 = require_chunk.__toESM(node_path, 1);
13
13
  node_path = require_chunk.__toESM(node_path);
14
+ let node_zlib = require("node:zlib");
15
+ node_zlib = require_chunk.__toESM(node_zlib);
14
16
  let node_fs_promises = require("node:fs/promises");
15
17
  let node_fs_promises$1 = require_chunk.__toESM(node_fs_promises, 1);
16
18
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -29,8 +31,6 @@ let assert = require("assert");
29
31
  assert = require_chunk.__toESM(assert, 1);
30
32
  let events = require("events");
31
33
  events = require_chunk.__toESM(events, 1);
32
- let node_zlib = require("node:zlib");
33
- node_zlib = require_chunk.__toESM(node_zlib);
34
34
  let node_assert = require("node:assert");
35
35
  node_assert = require_chunk.__toESM(node_assert, 1);
36
36
  //#region node_modules/tar/dist/esm/index.min.js
@@ -1,9 +1,10 @@
1
- import { b as backupCapability, pt as BaseAddon, zt as EventCategory } from "../../dist-DnKpFaP1.mjs";
1
+ import { Lt as EventCategory, b as backupCapability, dt as BaseAddon } from "../../dist-CMb7aKS0.mjs";
2
2
  import { randomBytes, randomUUID } from "node:crypto";
3
3
  import * as fs from "node:fs";
4
4
  import Kt from "node:fs";
5
5
  import * as path$1 from "node:path";
6
6
  import path, { basename, join, posix, win32 } from "node:path";
7
+ import * as zlib from "node:zlib";
7
8
  import * as fsp from "node:fs/promises";
8
9
  import jn from "node:fs/promises";
9
10
  import { Buffer as Buffer$1 } from "buffer";
@@ -16,7 +17,6 @@ import * as Ms from "zlib";
16
17
  import Jr from "zlib";
17
18
  import Pi from "assert";
18
19
  import $r, { EventEmitter as EventEmitter$1 } from "events";
19
- import * as zlib from "node:zlib";
20
20
  import no from "node:assert";
21
21
  //#region node_modules/tar/dist/esm/index.min.js
22
22
  var Mr = Object.defineProperty;
@@ -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-DgPUarcs.js");
6
+ const require_dist = require("../../dist-DP3nHlNM.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  //#region src/builtins/console-logging/console-destination.ts
9
9
  var LEVEL_RANK = {
@@ -1,4 +1,4 @@
1
- import { G as logDestinationCapability, pt as BaseAddon } from "../../dist-DnKpFaP1.mjs";
1
+ import { G as logDestinationCapability, dt as BaseAddon } from "../../dist-CMb7aKS0.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  //#region src/builtins/console-logging/console-destination.ts
4
4
  var LEVEL_RANK = {
@@ -1,34 +1,16 @@
1
+ import { coreBlockAddonId, coreBlockIdFromAddonId } from '@camstack/types';
1
2
  /**
2
- * Turning a stored block into something the addon runner can fork.
3
+ * The runner id lives on the CAPABILITY, not here.
3
4
  *
4
- * The runner already knows how to do everything a block needs — fork a
5
- * process, build the full UDS `ctx`, redirect host-provided imports, and hand
6
- * the whole thing to `CrashSupervisor` (D6). What it does NOT know how to do is
7
- * load code out of a database row: `addon-runner` reads a package.json off
8
- * disk. So a block is MATERIALISED as a minimal addon package and spawned like
9
- * any other addon. No second runner, no second supervisor, no `node:vm`.
10
- *
11
- * Two files are generated per block:
12
- *
13
- * `dist/block.js` — the author's TypeScript, transpiled.
14
- * `dist/index.js` — a generated wrapper that adapts the author's contract
15
- * (`export default (ctx) => disposer`) to `ICamstackAddon`.
16
- *
17
- * The wrapper exists so the author never writes `super({})`, which is the trap
18
- * that killed `CoreBlocksAddon` in production while the build stayed green and
19
- * the topology reported it running.
5
+ * It stopped being an implementation detail the day the operator surface
6
+ * started reading a block's logs by asking `logs.query` for
7
+ * `addonId = core-block-<id>` with no cap of its own. A second copy of the
8
+ * string would drift into a logs pane that is silently always empty, so these
9
+ * are re-exports under the names this package already used.
20
10
  */
21
- /** Prefix for the generated addon id AND the runner id — one addon, one
22
- * process, so the two are the same string (D2). Grep-able on purpose: an
23
- * operator reading `$process.list` must be able to tell a block runner from
24
- * an addon runner at a glance. */
25
11
  export declare const BLOCK_ADDON_PREFIX = "core-block-";
26
- /** The generated addon/runner id for a block. */
27
- export declare function blockAddonId(blockId: string): string;
28
- /** The block id behind a generated addon/runner id, or null when the id
29
- * belongs to something else. The inverse of {@link blockAddonId} — used to
30
- * read the live process list back into block terms. */
31
- export declare function blockIdFromAddonId(addonId: string): string | null;
12
+ export declare const blockAddonId: typeof coreBlockAddonId;
13
+ export declare const blockIdFromAddonId: typeof coreBlockIdFromAddonId;
32
14
  export interface MaterializeBlockInput {
33
15
  /** Root under which every block package lives — one directory per block. */
34
16
  readonly root: string;
@@ -65,6 +65,21 @@ export declare class BlockSupervisor {
65
65
  * next one, and the reason belongs in the log, not in a rejected promise
66
66
  * nobody awaits. */
67
67
  converge(): Promise<void>;
68
+ /**
69
+ * Stop one block's runner and let the pass that follows bring it back.
70
+ *
71
+ * The same path a code change already takes (see `stale` in `reconcile`),
72
+ * exposed on purpose. It writes NO state of its own: forgetting the
73
+ * materialised `updatedAt` is what makes the next pass treat the block as
74
+ * needing a launch, and that pass is still the authority — so a restart that
75
+ * raced a converge ends with one runner, not two.
76
+ *
77
+ * Queued on the same chain as `converge()`: a restart that interleaved with a
78
+ * timer tick could stop a runner the tick had just decided was healthy and
79
+ * then never re-launch it.
80
+ */
81
+ restart(blockId: string): Promise<void>;
82
+ private runRestart;
68
83
  private runPass;
69
84
  private reconcile;
70
85
  /** Compile, write the package, spawn. Each failure is reported ON the block
@@ -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-DgPUarcs.js");
3
+ const require_dist = require("../../dist-DP3nHlNM.js");
4
4
  let node_crypto = require("node:crypto");
5
5
  let node_path = require("node:path");
6
6
  node_path = require_chunk.__toESM(node_path);
@@ -27,23 +27,18 @@ node_fs_promises = require_chunk.__toESM(node_fs_promises);
27
27
  * that killed `CoreBlocksAddon` in production while the build stayed green and
28
28
  * the topology reported it running.
29
29
  */
30
- /** Prefix for the generated addon id AND the runner id — one addon, one
31
- * process, so the two are the same string (D2). Grep-able on purpose: an
32
- * operator reading `$process.list` must be able to tell a block runner from
33
- * an addon runner at a glance. */
34
- var BLOCK_ADDON_PREFIX = "core-block-";
35
- /** The generated addon/runner id for a block. */
36
- function blockAddonId(blockId) {
37
- return `${BLOCK_ADDON_PREFIX}${blockId}`;
38
- }
39
- /** The block id behind a generated addon/runner id, or null when the id
40
- * belongs to something else. The inverse of {@link blockAddonId} — used to
41
- * read the live process list back into block terms. */
42
- function blockIdFromAddonId(addonId) {
43
- if (!addonId.startsWith("core-block-")) return null;
44
- const rest = addonId.slice(11);
45
- return rest.length > 0 ? rest : null;
46
- }
30
+ /**
31
+ * The runner id lives on the CAPABILITY, not here.
32
+ *
33
+ * It stopped being an implementation detail the day the operator surface
34
+ * started reading a block's logs by asking `logs.query` for
35
+ * `addonId = core-block-<id>` with no cap of its own. A second copy of the
36
+ * string would drift into a logs pane that is silently always empty, so these
37
+ * are re-exports under the names this package already used.
38
+ */
39
+ var BLOCK_ADDON_PREFIX = require_dist.CORE_BLOCK_ADDON_PREFIX;
40
+ var blockAddonId = require_dist.coreBlockAddonId;
41
+ var blockIdFromAddonId = require_dist.coreBlockIdFromAddonId;
47
42
  /**
48
43
  * The wrapper module, generated verbatim.
49
44
  *
@@ -207,6 +202,36 @@ var BlockSupervisor = class {
207
202
  this.inFlight = this.inFlight.then(() => this.runPass(), () => this.runPass());
208
203
  return this.inFlight;
209
204
  }
205
+ /**
206
+ * Stop one block's runner and let the pass that follows bring it back.
207
+ *
208
+ * The same path a code change already takes (see `stale` in `reconcile`),
209
+ * exposed on purpose. It writes NO state of its own: forgetting the
210
+ * materialised `updatedAt` is what makes the next pass treat the block as
211
+ * needing a launch, and that pass is still the authority — so a restart that
212
+ * raced a converge ends with one runner, not two.
213
+ *
214
+ * Queued on the same chain as `converge()`: a restart that interleaved with a
215
+ * timer tick could stop a runner the tick had just decided was healthy and
216
+ * then never re-launch it.
217
+ */
218
+ restart(blockId) {
219
+ this.inFlight = this.inFlight.then(() => this.runRestart(blockId), () => this.runRestart(blockId));
220
+ return this.inFlight;
221
+ }
222
+ async runRestart(blockId) {
223
+ try {
224
+ await this.deps.host.stop(blockAddonId(blockId));
225
+ this.deps.logger.info("core block runner stopped for restart", { meta: { blockId } });
226
+ } catch (err) {
227
+ this.deps.logger.warn("could not stop the core block runner before restart", { meta: {
228
+ blockId,
229
+ error: err instanceof Error ? err.message : String(err)
230
+ } });
231
+ }
232
+ this.materialized.delete(blockId);
233
+ await this.runPass();
234
+ }
210
235
  async runPass() {
211
236
  try {
212
237
  await this.reconcile();
@@ -821,6 +846,27 @@ var CoreBlocksAddon = class extends require_dist.BaseAddon {
821
846
  this.convergeSoon();
822
847
  return { block: updated };
823
848
  },
849
+ /**
850
+ * Awaited, unlike every other write here.
851
+ *
852
+ * `create`/`update` deliberately do not wait — the write is already
853
+ * durable and converging forks a process. A restart has no durable half:
854
+ * the whole thing IS the converge, so returning before it ran would hand
855
+ * the operator the old status and read as "nothing happened".
856
+ */
857
+ restart: async ({ blockId }) => {
858
+ const store = this.requireStore();
859
+ const block = store.get(blockId);
860
+ if (block === null) throw new Error(`core-blocks: no block "${blockId}"`);
861
+ if (!block.enabled) throw new Error(`core-blocks: "${block.name}" is disabled — enable it instead of restarting it`);
862
+ if (this.supervisor === null) throw new Error("core-blocks: no block supervisor runs on this node — nothing here can restart a block");
863
+ this.ctx.logger.info("core block restart requested", { meta: {
864
+ blockId,
865
+ name: block.name
866
+ } });
867
+ await this.supervisor.restart(blockId);
868
+ return { block: store.get(blockId) ?? block };
869
+ },
824
870
  compile: async ({ code }) => {
825
871
  if (this.transpiler === null) return {
826
872
  ok: false,
@@ -866,16 +912,37 @@ function createBrokerProcessHost(broker) {
866
912
  }
867
913
  };
868
914
  }
869
- /** Load esbuild lazily. Returns null — never throws — so a node without it
870
- * still boots, with the compile gate refusing writes rather than the node
871
- * refusing to start. */
915
+ /**
916
+ * Load esbuild lazily, and PROVE IT WORKS before trusting it.
917
+ *
918
+ * Returns null — never throws — so a node without a usable compiler still
919
+ * boots, with the compile gate refusing writes rather than the node refusing
920
+ * to start.
921
+ *
922
+ * The probe is not defensive decoration. On the live hub, 2026-08-08, the
923
+ * import succeeded and `transform()` threw *"The esbuild JavaScript API cannot
924
+ * be bundled"* (it had been inlined into `@camstack/system`'s dist, so it could
925
+ * no longer find its own native binary). Importing successfully was therefore
926
+ * NOT evidence the compiler worked — and because the failure arrived at
927
+ * transform time, every save came back as
928
+ * `core-blocks: the code does not compile: …`, which blames the author for a
929
+ * broken node. Nobody could have written source that passed. One transform at
930
+ * boot converts that into the honest answer the rest of this file already
931
+ * gives: the compiler is unavailable here.
932
+ */
872
933
  async function loadTranspiler(logger) {
873
934
  try {
874
- const transform = (await Promise.resolve().then(() => /* @__PURE__ */ require_chunk.__toESM(require("../../main-CVLq8IzA.js").default))).transform;
935
+ const transform = (await import("esbuild")).transform;
875
936
  if (typeof transform !== "function") return null;
876
- return { transform };
937
+ const transpiler = { transform };
938
+ await transpiler.transform("export default 0", {
939
+ loader: "ts",
940
+ format: "esm",
941
+ target: "node22"
942
+ });
943
+ return transpiler;
877
944
  } catch (err) {
878
- logger.warn("core-blocks: esbuild unavailable — code cannot be compiled on this node", { meta: { error: err instanceof Error ? err.message : String(err) } });
945
+ logger.warn("core-blocks: esbuild unusable — code cannot be compiled on this node", { meta: { error: err instanceof Error ? err.message : String(err) } });
879
946
  return null;
880
947
  }
881
948
  }
@@ -1,5 +1,4 @@
1
- import { o as __toESM } from "../../chunk-CNf5ZN-e.mjs";
2
- import { C as coreBlocksCapability, o as CoreBlockSchema, pt as BaseAddon } from "../../dist-DnKpFaP1.mjs";
1
+ import { C as coreBlockAddonId, T as coreBlocksCapability, dt as BaseAddon, o as CORE_BLOCK_ADDON_PREFIX, s as CoreBlockSchema, w as coreBlockIdFromAddonId } from "../../dist-CMb7aKS0.mjs";
3
2
  import { randomUUID } from "node:crypto";
4
3
  import * as path$1 from "node:path";
5
4
  import * as fs from "node:fs/promises";
@@ -24,23 +23,18 @@ import * as fs from "node:fs/promises";
24
23
  * that killed `CoreBlocksAddon` in production while the build stayed green and
25
24
  * the topology reported it running.
26
25
  */
27
- /** Prefix for the generated addon id AND the runner id — one addon, one
28
- * process, so the two are the same string (D2). Grep-able on purpose: an
29
- * operator reading `$process.list` must be able to tell a block runner from
30
- * an addon runner at a glance. */
31
- var BLOCK_ADDON_PREFIX = "core-block-";
32
- /** The generated addon/runner id for a block. */
33
- function blockAddonId(blockId) {
34
- return `${BLOCK_ADDON_PREFIX}${blockId}`;
35
- }
36
- /** The block id behind a generated addon/runner id, or null when the id
37
- * belongs to something else. The inverse of {@link blockAddonId} used to
38
- * read the live process list back into block terms. */
39
- function blockIdFromAddonId(addonId) {
40
- if (!addonId.startsWith("core-block-")) return null;
41
- const rest = addonId.slice(11);
42
- return rest.length > 0 ? rest : null;
43
- }
26
+ /**
27
+ * The runner id lives on the CAPABILITY, not here.
28
+ *
29
+ * It stopped being an implementation detail the day the operator surface
30
+ * started reading a block's logs by asking `logs.query` for
31
+ * `addonId = core-block-<id>` with no cap of its own. A second copy of the
32
+ * string would drift into a logs pane that is silently always empty, so these
33
+ * are re-exports under the names this package already used.
34
+ */
35
+ var BLOCK_ADDON_PREFIX = CORE_BLOCK_ADDON_PREFIX;
36
+ var blockAddonId = coreBlockAddonId;
37
+ var blockIdFromAddonId = coreBlockIdFromAddonId;
44
38
  /**
45
39
  * The wrapper module, generated verbatim.
46
40
  *
@@ -204,6 +198,36 @@ var BlockSupervisor = class {
204
198
  this.inFlight = this.inFlight.then(() => this.runPass(), () => this.runPass());
205
199
  return this.inFlight;
206
200
  }
201
+ /**
202
+ * Stop one block's runner and let the pass that follows bring it back.
203
+ *
204
+ * The same path a code change already takes (see `stale` in `reconcile`),
205
+ * exposed on purpose. It writes NO state of its own: forgetting the
206
+ * materialised `updatedAt` is what makes the next pass treat the block as
207
+ * needing a launch, and that pass is still the authority — so a restart that
208
+ * raced a converge ends with one runner, not two.
209
+ *
210
+ * Queued on the same chain as `converge()`: a restart that interleaved with a
211
+ * timer tick could stop a runner the tick had just decided was healthy and
212
+ * then never re-launch it.
213
+ */
214
+ restart(blockId) {
215
+ this.inFlight = this.inFlight.then(() => this.runRestart(blockId), () => this.runRestart(blockId));
216
+ return this.inFlight;
217
+ }
218
+ async runRestart(blockId) {
219
+ try {
220
+ await this.deps.host.stop(blockAddonId(blockId));
221
+ this.deps.logger.info("core block runner stopped for restart", { meta: { blockId } });
222
+ } catch (err) {
223
+ this.deps.logger.warn("could not stop the core block runner before restart", { meta: {
224
+ blockId,
225
+ error: err instanceof Error ? err.message : String(err)
226
+ } });
227
+ }
228
+ this.materialized.delete(blockId);
229
+ await this.runPass();
230
+ }
207
231
  async runPass() {
208
232
  try {
209
233
  await this.reconcile();
@@ -818,6 +842,27 @@ var CoreBlocksAddon = class extends BaseAddon {
818
842
  this.convergeSoon();
819
843
  return { block: updated };
820
844
  },
845
+ /**
846
+ * Awaited, unlike every other write here.
847
+ *
848
+ * `create`/`update` deliberately do not wait — the write is already
849
+ * durable and converging forks a process. A restart has no durable half:
850
+ * the whole thing IS the converge, so returning before it ran would hand
851
+ * the operator the old status and read as "nothing happened".
852
+ */
853
+ restart: async ({ blockId }) => {
854
+ const store = this.requireStore();
855
+ const block = store.get(blockId);
856
+ if (block === null) throw new Error(`core-blocks: no block "${blockId}"`);
857
+ if (!block.enabled) throw new Error(`core-blocks: "${block.name}" is disabled — enable it instead of restarting it`);
858
+ if (this.supervisor === null) throw new Error("core-blocks: no block supervisor runs on this node — nothing here can restart a block");
859
+ this.ctx.logger.info("core block restart requested", { meta: {
860
+ blockId,
861
+ name: block.name
862
+ } });
863
+ await this.supervisor.restart(blockId);
864
+ return { block: store.get(blockId) ?? block };
865
+ },
821
866
  compile: async ({ code }) => {
822
867
  if (this.transpiler === null) return {
823
868
  ok: false,
@@ -863,16 +908,37 @@ function createBrokerProcessHost(broker) {
863
908
  }
864
909
  };
865
910
  }
866
- /** Load esbuild lazily. Returns null — never throws — so a node without it
867
- * still boots, with the compile gate refusing writes rather than the node
868
- * refusing to start. */
911
+ /**
912
+ * Load esbuild lazily, and PROVE IT WORKS before trusting it.
913
+ *
914
+ * Returns null — never throws — so a node without a usable compiler still
915
+ * boots, with the compile gate refusing writes rather than the node refusing
916
+ * to start.
917
+ *
918
+ * The probe is not defensive decoration. On the live hub, 2026-08-08, the
919
+ * import succeeded and `transform()` threw *"The esbuild JavaScript API cannot
920
+ * be bundled"* (it had been inlined into `@camstack/system`'s dist, so it could
921
+ * no longer find its own native binary). Importing successfully was therefore
922
+ * NOT evidence the compiler worked — and because the failure arrived at
923
+ * transform time, every save came back as
924
+ * `core-blocks: the code does not compile: …`, which blames the author for a
925
+ * broken node. Nobody could have written source that passed. One transform at
926
+ * boot converts that into the honest answer the rest of this file already
927
+ * gives: the compiler is unavailable here.
928
+ */
869
929
  async function loadTranspiler(logger) {
870
930
  try {
871
- const transform = (await import("../../main-CzH19GkU.mjs").then((m) => /* @__PURE__ */ __toESM(m.default))).transform;
931
+ const transform = (await import("esbuild")).transform;
872
932
  if (typeof transform !== "function") return null;
873
- return { transform };
933
+ const transpiler = { transform };
934
+ await transpiler.transform("export default 0", {
935
+ loader: "ts",
936
+ format: "esm",
937
+ target: "node22"
938
+ });
939
+ return transpiler;
874
940
  } catch (err) {
875
- logger.warn("core-blocks: esbuild unavailable — code cannot be compiled on this node", { meta: { error: err instanceof Error ? err.message : String(err) } });
941
+ logger.warn("core-blocks: esbuild unusable — code cannot be compiled on this node", { meta: { error: err instanceof Error ? err.message : String(err) } });
876
942
  return null;
877
943
  }
878
944
  }
@@ -1,5 +1,5 @@
1
- import { AddonContext, DeviceBindingEntry, ICapabilityRegistry } from '@camstack/types';
2
- import { DeviceBindingsStore } from './device-meta-types.js';
1
+ import { AddonContext, CapabilityDefinition, DeviceBindingEntry, ICapabilityRegistry } from '@camstack/types';
2
+ import { AddonStore, DeviceBindingsStore } from './device-meta-types.js';
3
3
  /** Push-fed remote native-cap cache shape (numeric deviceId → capName → owner). */
4
4
  export type RemoteNativeCaps = Map<number, Map<string, {
5
5
  addonId: string;
@@ -14,9 +14,6 @@ export interface BindingsDeps {
14
14
  readonly ctx: AddonContext;
15
15
  readonly capabilityRegistry: ICapabilityRegistry | undefined;
16
16
  readonly remoteNativeCaps: RemoteNativeCaps;
17
- /** O(1) gate over devices that have `deviceLinks` (the addon's live set).
18
- * Optional: when absent, getBindings adds no virtual `linked` entries. */
19
- readonly devicesWithLinks?: ReadonlySet<number>;
20
17
  }
21
18
  /**
22
19
  * Wire the push-fed cross-process native-cap cache (`remoteNativeCaps`).
@@ -72,6 +69,32 @@ export declare function resolveRemoteNativeCapFromRegistry(deps: BindingsDeps, c
72
69
  addonId: string;
73
70
  nodeId: string;
74
71
  } | null;
72
+ /**
73
+ * Resolve the device's declared TYPE (`'camera'`, `'event-emitter'`, …), or
74
+ * `undefined` when it cannot be established.
75
+ *
76
+ * The PERSISTED meta is the authority: `ctx.kernel.deviceRegistry` is hub-only
77
+ * and has been observed empty in the very process that answers `getBindings`
78
+ * correctly (see the note on `getAllBindings`). The registry is consulted only
79
+ * as a secondary source, for a device constructed but not yet persisted.
80
+ *
81
+ * `undefined` is a first-class answer and callers must treat it as "no
82
+ * filtering" — an absent row must never be the reason a device loses bindings.
83
+ */
84
+ export declare function resolveDeviceType(deps: BindingsDeps, rawStore: AddonStore, deviceId: number): string | undefined;
85
+ /**
86
+ * Does a capability apply to a device of type `deviceType`?
87
+ *
88
+ * The cap's `deviceTypes` is the ONLY declaration consulted (D4: behavioural
89
+ * cap metadata lives in the `*.cap.ts`, never in a manifest). Two deliberate
90
+ * fail-open cases:
91
+ *
92
+ * - a cap that declares no `deviceTypes` (or an empty list) applies to every
93
+ * device — the pre-existing, back-compatible semantics;
94
+ * - an UNKNOWN `deviceType` never filters, so a missing/failed meta lookup
95
+ * changes nothing (D49: a read that fails must not destroy work).
96
+ */
97
+ export declare function capAppliesToDeviceType(def: CapabilityDefinition | undefined, deviceType: string | undefined): boolean;
75
98
  export declare function getBindings(deps: BindingsDeps, input: {
76
99
  deviceId: number;
77
100
  }): Promise<{
@@ -1,4 +1,4 @@
1
- import { ConfigUISchemaWithValues, DeviceLinkMode, IDeviceManagerProvider } from '@camstack/types';
1
+ import { ConfigUISchemaWithValues, IDeviceManagerProvider, LinkedDevicesMode } from '@camstack/types';
2
2
  import { ProviderContext } from './device-provider-context.js';
3
3
  /** Reserved device-config keys (cf. `_profileMap`). */
4
4
  export declare const LINKED_MODE_CONFIG_KEY = "_linkedDevicesMode";
@@ -9,7 +9,7 @@ export declare const LINKED_IDS_CONFIG_KEY = "_linkedDeviceIds";
9
9
  * auto-materialized sensor snapshots the operator never asked for). */
10
10
  export declare const LINKED_TRACKED_IDS_CONFIG_KEY = "_linkedDeviceTrackedIds";
11
11
  export interface LinkedDevicesConfig {
12
- readonly mode: DeviceLinkMode;
12
+ readonly mode: LinkedDevicesMode;
13
13
  readonly manualIds: readonly number[];
14
14
  }
15
15
  /** Parse the two reserved keys out of a device-config blob. Tolerant: