@camstack/system 1.2.84 → 1.2.86

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 (60) 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 +1 -1
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -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/core-blocks.addon.js +1 -1
  14. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  15. package/dist/builtins/device-manager/device-manager.addon.js +32 -2
  16. package/dist/builtins/device-manager/device-manager.addon.mjs +32 -2
  17. package/dist/builtins/device-manager/device-meta-actions.d.ts +12 -0
  18. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  19. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  20. package/dist/builtins/hub-forwarder/index.js +1 -1
  21. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  22. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  23. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  24. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  25. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  26. package/dist/builtins/local-network/local-network.addon.js +1 -1
  27. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  28. package/dist/builtins/loki-logging/index.js +1 -1
  29. package/dist/builtins/loki-logging/index.mjs +1 -1
  30. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  31. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  32. package/dist/builtins/platform-probe/index.js +1 -1
  33. package/dist/builtins/platform-probe/index.mjs +1 -1
  34. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  35. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  36. package/dist/builtins/snapshot/index.js +66 -11
  37. package/dist/builtins/snapshot/index.mjs +66 -11
  38. package/dist/builtins/snapshot/snapshot.addon.d.ts +39 -3
  39. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  40. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  41. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +1 -1
  42. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
  43. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  44. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  45. package/dist/builtins/system-config/system-config.addon.js +1 -1
  46. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  47. package/dist/builtins/winston-logging/index.js +1 -1
  48. package/dist/builtins/winston-logging/index.mjs +1 -1
  49. package/dist/{dist-BAwlOEUy.mjs → dist-B90N7AWO.mjs} +575 -34
  50. package/dist/{dist-CQy9KjsL.js → dist-BV5Bug9t.js} +575 -34
  51. package/dist/index.js +73 -16
  52. package/dist/index.mjs +73 -16
  53. package/dist/kernel/addon-installer.d.ts +49 -5
  54. package/dist/kernel/moleculer/event-bus-core.d.ts +47 -1
  55. package/dist/kernel/transport/child-cap-protocol.d.ts +32 -0
  56. package/dist/kernel/transport/hub-cap-forward.d.ts +8 -0
  57. package/dist/kernel/transport/parent-unowned-call.d.ts +19 -0
  58. package/dist/{manifest-python-deps-DG_LLcZF.js → manifest-python-deps-C0zkl1Ae.js} +133 -53
  59. package/dist/{manifest-python-deps-C1DMs1J9.mjs → manifest-python-deps-fWzdEasI.mjs} +133 -53
  60. package/package.json +6 -1
@@ -1,4 +1,4 @@
1
- import { Ft as nodePin, Ht as EventCategory, St as DeviceType, bt as DeviceFeature, dt as streamQualityLabel, gt as BaseAddon, ht as errMsg, i as BatteryStatusSchema, st as snapshotCapability, w as bareAddonId } from "../../dist-BAwlOEUy.mjs";
1
+ import { Ft as nodePin, Ht as EventCategory, St as DeviceType, bt as DeviceFeature, dt as streamQualityLabel, gt as BaseAddon, ht as errMsg, i as BatteryStatusSchema, st as snapshotCapability, w as bareAddonId } from "../../dist-B90N7AWO.mjs";
2
2
  import { z } from "zod";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { signExpiringUrl, verifyExpiringUrl } from "@camstack/types/node";
@@ -865,6 +865,11 @@ var SnapshotAddon = class SnapshotAddon extends BaseAddon {
865
865
  * currently holding, which is a fleet-wide blank grid after each restart. */
866
866
  linkSecret = null;
867
867
  /**
868
+ * In-flight `serveLinkDataPlane` attempt, so the retry below cannot start a
869
+ * second one while the first is still awaiting the settings store.
870
+ */
871
+ linkPlaneAttempt = null;
872
+ /**
868
873
  * How a full frame becomes a card-sized one. Defaults to the real ffmpeg
869
874
  * resize; injectable so the wrapper's own logic is testable without spawning a
870
875
  * process for every fixture. `JpegResizer` was declared for exactly this and
@@ -893,7 +898,7 @@ var SnapshotAddon = class SnapshotAddon extends BaseAddon {
893
898
  if (typeof deviceId === "number") this.evictRemovedDevice(deviceId, "device-unregistered");
894
899
  });
895
900
  await this.serveMediaDataPlane();
896
- await this.serveLinkDataPlane();
901
+ await this.ensureLinkDataPlane();
897
902
  return [{
898
903
  capability: snapshotCapability,
899
904
  provider
@@ -926,6 +931,33 @@ var SnapshotAddon = class SnapshotAddon extends BaseAddon {
926
931
  }
927
932
  }
928
933
  /**
934
+ * Serve the link plane if it is not already served — at init, and again on
935
+ * the first `getSnapshotLinks` after an attempt that could not finish.
936
+ *
937
+ * The retry is not defensive padding, it is the whole reason this wrapper
938
+ * exists. The plane needs a persisted signing secret, and the secret needs
939
+ * the settings store; this addon now boots in its OWN process, so "the store
940
+ * is not answering yet" is a state it can genuinely observe. A one-shot
941
+ * attempt turns that instant into a permanent condition: `linkDataPlane`
942
+ * stays null, every `getSnapshotLinks` row answers `url: null`, and every
943
+ * tile on every grid stays blank until someone restarts the runner. Nothing
944
+ * in the logs would say why, because nothing failed twice.
945
+ *
946
+ * Single-flighted: a burst of link requests joins one attempt.
947
+ */
948
+ async ensureLinkDataPlane() {
949
+ if (this.linkDataPlane !== null) return;
950
+ if (this.linkPlaneAttempt !== null) {
951
+ await this.linkPlaneAttempt;
952
+ return;
953
+ }
954
+ const attempt = this.serveLinkDataPlane().finally(() => {
955
+ this.linkPlaneAttempt = null;
956
+ });
957
+ this.linkPlaneAttempt = attempt;
958
+ await attempt;
959
+ }
960
+ /**
929
961
  * Serve the PUBLIC link plane: `GET /addon/snapshot/link/<deviceId>.jpg?w&v&exp&sig`.
930
962
  *
931
963
  * `access: 'public'` is deliberate and is the only interesting decision here.
@@ -994,20 +1026,42 @@ var SnapshotAddon = class SnapshotAddon extends BaseAddon {
994
1026
  linkRoutePrefix() {
995
1027
  return `/addon/${bareAddonId(this.ctx.id)}/link`;
996
1028
  }
997
- /** Mint-once-and-persist the signing secret. Null if it cannot be stored — a
998
- * secret held only in memory would break every outstanding link on restart,
999
- * so no plane is better than a plane whose links die unpredictably. */
1029
+ /**
1030
+ * Mint-once-and-persist the signing secret. Null when it cannot be
1031
+ * ESTABLISHED a secret held only in memory would break every outstanding
1032
+ * link on restart, so no plane is better than a plane whose links die
1033
+ * unpredictably.
1034
+ *
1035
+ * A null is never cached, so the next `getSnapshotLinks` tries again. That
1036
+ * matters now the wrapper runs in its own process: the settings store can be
1037
+ * a moment behind at boot, and this used to be a one-shot.
1038
+ *
1039
+ * The read-back is the gate. `state.get()` cannot distinguish "no secret
1040
+ * yet" from "the store could not be read" — `readAddonStoreWithRetry` gives
1041
+ * up and answers `{}` — so a store that is merely slow reads as empty and
1042
+ * this would mint a SECOND secret over a perfectly good first one, silently
1043
+ * invalidating every link a client is holding. Reading back what we just
1044
+ * wrote is the only evidence available at this layer that the store is
1045
+ * actually answering, and a mismatch means it is not.
1046
+ */
1000
1047
  async ensureLinkSecret() {
1001
1048
  if (this.linkSecret !== null) return this.linkSecret;
1002
1049
  try {
1003
1050
  const state = this.state("snapshotLinkSecret", z.string(), "");
1004
- let secret = await state.get();
1005
- if (secret === "") {
1006
- secret = randomUUID().replace(/-/g, "");
1007
- await state.set(secret);
1051
+ const stored = await state.get();
1052
+ if (stored !== "") {
1053
+ this.linkSecret = stored;
1054
+ return stored;
1055
+ }
1056
+ const minted = randomUUID().replace(/-/g, "");
1057
+ await state.set(minted);
1058
+ const confirmed = await state.get();
1059
+ if (confirmed !== minted) {
1060
+ this.ctx.logger.warn("snapshot: link secret did not persist — deferring the link plane rather than signing with a secret that will not survive", { meta: { confirmedEmpty: confirmed === "" } });
1061
+ return null;
1008
1062
  }
1009
- this.linkSecret = secret;
1010
- return secret;
1063
+ this.linkSecret = minted;
1064
+ return minted;
1011
1065
  } catch (err) {
1012
1066
  this.ctx.logger.warn("snapshot: could not establish link signing secret", { meta: { error: errMsg(err) } });
1013
1067
  return null;
@@ -1038,6 +1092,7 @@ var SnapshotAddon = class SnapshotAddon extends BaseAddon {
1038
1092
  * forward.
1039
1093
  */
1040
1094
  async getSnapshotLinks(input) {
1095
+ await this.ensureLinkDataPlane();
1041
1096
  const secret = await this.ensureLinkSecret();
1042
1097
  const expMs = snapshotLinkExpiry(Date.now(), SNAPSHOT_LINK_TTL_MS);
1043
1098
  const served = this.linkDataPlane !== null && secret !== null;
@@ -81,6 +81,11 @@ export declare class SnapshotAddon extends BaseAddon<SnapshotAddonConfig> {
81
81
  * secret that rolled on every boot would invalidate every link a client is
82
82
  * currently holding, which is a fleet-wide blank grid after each restart. */
83
83
  private linkSecret;
84
+ /**
85
+ * In-flight `serveLinkDataPlane` attempt, so the retry below cannot start a
86
+ * second one while the first is still awaiting the settings store.
87
+ */
88
+ private linkPlaneAttempt;
84
89
  /**
85
90
  * How a full frame becomes a card-sized one. Defaults to the real ffmpeg
86
91
  * resize; injectable so the wrapper's own logic is testable without spawning a
@@ -101,6 +106,22 @@ export declare class SnapshotAddon extends BaseAddon<SnapshotAddonConfig> {
101
106
  * base64 path.
102
107
  */
103
108
  private serveMediaDataPlane;
109
+ /**
110
+ * Serve the link plane if it is not already served — at init, and again on
111
+ * the first `getSnapshotLinks` after an attempt that could not finish.
112
+ *
113
+ * The retry is not defensive padding, it is the whole reason this wrapper
114
+ * exists. The plane needs a persisted signing secret, and the secret needs
115
+ * the settings store; this addon now boots in its OWN process, so "the store
116
+ * is not answering yet" is a state it can genuinely observe. A one-shot
117
+ * attempt turns that instant into a permanent condition: `linkDataPlane`
118
+ * stays null, every `getSnapshotLinks` row answers `url: null`, and every
119
+ * tile on every grid stays blank until someone restarts the runner. Nothing
120
+ * in the logs would say why, because nothing failed twice.
121
+ *
122
+ * Single-flighted: a burst of link requests joins one attempt.
123
+ */
124
+ private ensureLinkDataPlane;
104
125
  /**
105
126
  * Serve the PUBLIC link plane: `GET /addon/snapshot/link/<deviceId>.jpg?w&v&exp&sig`.
106
127
  *
@@ -128,9 +149,24 @@ export declare class SnapshotAddon extends BaseAddon<SnapshotAddonConfig> {
128
149
  */
129
150
  private handleLinkRequest;
130
151
  private linkRoutePrefix;
131
- /** Mint-once-and-persist the signing secret. Null if it cannot be stored — a
132
- * secret held only in memory would break every outstanding link on restart,
133
- * so no plane is better than a plane whose links die unpredictably. */
152
+ /**
153
+ * Mint-once-and-persist the signing secret. Null when it cannot be
154
+ * ESTABLISHED a secret held only in memory would break every outstanding
155
+ * link on restart, so no plane is better than a plane whose links die
156
+ * unpredictably.
157
+ *
158
+ * A null is never cached, so the next `getSnapshotLinks` tries again. That
159
+ * matters now the wrapper runs in its own process: the settings store can be
160
+ * a moment behind at boot, and this used to be a one-shot.
161
+ *
162
+ * The read-back is the gate. `state.get()` cannot distinguish "no secret
163
+ * yet" from "the store could not be read" — `readAddonStoreWithRetry` gives
164
+ * up and answers `{}` — so a store that is merely slow reads as empty and
165
+ * this would mint a SECOND secret over a perfectly good first one, silently
166
+ * invalidating every link a client is holding. Reading back what we just
167
+ * wrote is the only evidence available at this layer that the store is
168
+ * actually answering, and a mismatch means it is not.
169
+ */
134
170
  private ensureLinkSecret;
135
171
  /**
136
172
  * Mint signed links for the tiles a surface is rendering — and, in the same
@@ -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-CQy9KjsL.js");
6
+ const require_dist = require("../../dist-BV5Bug9t.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_fs_promises = require("node:fs/promises");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { gt as BaseAddon, ut as storageProviderCapability, z as filesystemBrowseCapability } from "../../dist-BAwlOEUy.mjs";
1
+ import { gt as BaseAddon, ut as storageProviderCapability, z as filesystemBrowseCapability } from "../../dist-B90N7AWO.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { mkdir, readdir, realpath, statfs } from "node:fs/promises";
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-CQy9KjsL.js");
6
+ const require_dist = require("../../dist-BV5Bug9t.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_fs = require("node:fs");
9
9
  let node_module = require("node:module");
@@ -1,4 +1,4 @@
1
- import { A as decodeVectorBase64, Et as asJsonObject, Lt as parseJsonUnknown, f as RUNTIME_DEFAULTS, gt as BaseAddon, ht as errMsg, k as dataStoreProviderCapability, mt as vectorStoreCapability, pt as vectorDimFromBase64, w as bareAddonId } from "../../dist-BAwlOEUy.mjs";
1
+ import { A as decodeVectorBase64, Et as asJsonObject, Lt as parseJsonUnknown, f as RUNTIME_DEFAULTS, gt as BaseAddon, ht as errMsg, k as dataStoreProviderCapability, mt as vectorStoreCapability, pt as vectorDimFromBase64, w as bareAddonId } from "../../dist-B90N7AWO.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { statSync } 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-CQy9KjsL.js");
6
+ const require_dist = require("../../dist-BV5Bug9t.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_fs_promises = require("node:fs/promises");
9
9
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -1,4 +1,4 @@
1
- import { It as parseJsonObject, ct as storageCapability, g as StorageMigrationJobSchema, gt as BaseAddon, h as StorageLocationTypeSchema, lt as storageMigrationCapability, ot as settingsStoreCapability } from "../../dist-BAwlOEUy.mjs";
1
+ import { It as parseJsonObject, ct as storageCapability, g as StorageMigrationJobSchema, gt as BaseAddon, h as StorageLocationTypeSchema, lt as storageMigrationCapability, ot as settingsStoreCapability } from "../../dist-B90N7AWO.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import * as fs from "node:fs/promises";
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-CQy9KjsL.js");
6
+ const require_dist = require("../../dist-BV5Bug9t.js");
7
7
  //#region src/builtins/system-config/system-config.addon.ts
8
8
  /**
9
9
  * Built-in `system-config` addon — Phase 4 of the settings redesign.
@@ -1,4 +1,4 @@
1
- import { Nt as hydrateSchema, gt as BaseAddon, ht as errMsg } from "../../dist-BAwlOEUy.mjs";
1
+ import { Nt as hydrateSchema, gt as BaseAddon, ht as errMsg } from "../../dist-B90N7AWO.mjs";
2
2
  //#region src/builtins/system-config/system-config.addon.ts
3
3
  /**
4
4
  * Built-in `system-config` addon — Phase 4 of the settings redesign.
@@ -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-CQy9KjsL.js");
6
+ const require_dist = require("../../dist-BV5Bug9t.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  let node_path = require("node:path");
9
9
  node_path = require_chunk.__toESM(node_path);
@@ -1,4 +1,4 @@
1
- import { J as logDestinationCapability, gt as BaseAddon } from "../../dist-BAwlOEUy.mjs";
1
+ import { J as logDestinationCapability, gt as BaseAddon } from "../../dist-B90N7AWO.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  import * as path$1 from "node:path";
4
4
  import path from "node:path";