@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
@@ -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-CYqL8oZq.js");
6
+ const require_dist = require("../../dist-BH2tZ9ZN.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  node_crypto = require_chunk.__toESM(node_crypto);
9
9
  let crypto$1 = require("crypto");
@@ -8823,9 +8823,44 @@ var TotpManager = class {
8823
8823
  };
8824
8824
  //#endregion
8825
8825
  //#region src/builtins/local-auth/auth-schema.ts
8826
+ /**
8827
+ * @durable class=config owner=local-auth
8828
+ * write="an operator creates a user, or `ensureAdminExists` seeds/re-syncs the
8829
+ * configured admin at boot; updated on scope, isAdmin and password edits"
8830
+ * retention="none — a row goes only when an operator deletes the user. A
8831
+ * `declareCollection` that adds a PK/UNIQUE/NOT-NULL-without-default column
8832
+ * REBUILDS the table: every account is wiped and only the configured admin
8833
+ * comes back on the next boot."
8834
+ */
8826
8835
  var USERS_COLLECTION = "users";
8836
+ /**
8837
+ * @durable class=config owner=local-auth
8838
+ * write="an operator mints an API key; `validateToken` rewrites `lastUsedAt` on
8839
+ * every request the key authorises"
8840
+ * retention="none — an explicit `revoke` is the only delete. API keys have no
8841
+ * expiry column and no sweep, so a key lives until someone removes it (or the
8842
+ * destructive `declareCollection` rebuild takes the table)."
8843
+ */
8827
8844
  var API_KEYS_COLLECTION = "api_keys";
8845
+ /**
8846
+ * @durable class=config owner=local-auth
8847
+ * write="an operator or the CLI mints a scoped token; `validate` fires
8848
+ * `updateLastUsed` on every accepted call"
8849
+ * retention="`revoke` deletes one. The daily sweep `reapExpired` drops rows past
8850
+ * `expiresAt` — a NULL expiry is a deliberate never-expires token and BETWEEN
8851
+ * never matches it. `cleanupOrphans` drops tokens owned by the legacy 'system'
8852
+ * id or by a user that no longer exists."
8853
+ */
8828
8854
  var SCOPED_TOKENS_COLLECTION = "scoped_tokens";
8855
+ /**
8856
+ * @durable class=ledger owner=local-auth
8857
+ * write="one row per redeemed OAuth code — every completed account link through
8858
+ * `oauthExchangeCode`; `touch` rewrites `lastUsedAt` on each refresh"
8859
+ * retention="ONLY revoked rows are pruned: the daily sweep deletes sessions
8860
+ * revoked more than OAUTH_REVOKED_RETENTION_MS (30 d) ago. An ACTIVE session
8861
+ * has `revokedAt` NULL, never expires and is never swept — the table grows one
8862
+ * row per login until an operator revokes the link."
8863
+ */
8829
8864
  var OAUTH_SESSIONS_COLLECTION = "oauth_sessions";
8830
8865
  /**
8831
8866
  * TOTP enrollment table — split off from `users` to avoid the
@@ -8839,6 +8874,13 @@ var OAUTH_SESSIONS_COLLECTION = "oauth_sessions";
8839
8874
  *
8840
8875
  * "Enabled" means `confirmedAt != null`. A half-enrolled row (`confirmedAt
8841
8876
  * = null`) is INACTIVE — `verifyTotp` returns false until confirmation.
8877
+ *
8878
+ * @durable class=config owner=local-auth
8879
+ * write="`setup` inserts a fresh secret for the user (deleting any pending row
8880
+ * first); `confirm` flips `confirmedAt` once a valid code proves possession"
8881
+ * retention="`disable` deletes the row, and `setup` deletes before re-inserting.
8882
+ * Nothing else prunes — deleting a USER does not cascade here, so their
8883
+ * enrollment row outlives the account."
8842
8884
  */
8843
8885
  var USER_TOTP_COLLECTION = "user_totp";
8844
8886
  var USERS_COLUMNS = [
@@ -1,5 +1,5 @@
1
1
  import { i as __require, o as __toESM, t as __commonJSMin } from "../../chunk-CNf5ZN-e.mjs";
2
- import { S as authProviderCapability, _ as UserRecordSchema, _t as BaseAddon, m as ScopedTokenSchema, pt as userManagementCapability, r as ApiKeyRecordSchema } from "../../dist-DMhxx5Kr.mjs";
2
+ import { S as authProviderCapability, _ as UserRecordSchema, _t as BaseAddon, m as ScopedTokenSchema, pt as userManagementCapability, r as ApiKeyRecordSchema } from "../../dist-DXDvrBi0.mjs";
3
3
  import * as crypto$2 from "node:crypto";
4
4
  import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
5
5
  import nodeCrypto from "crypto";
@@ -8815,9 +8815,44 @@ var TotpManager = class {
8815
8815
  };
8816
8816
  //#endregion
8817
8817
  //#region src/builtins/local-auth/auth-schema.ts
8818
+ /**
8819
+ * @durable class=config owner=local-auth
8820
+ * write="an operator creates a user, or `ensureAdminExists` seeds/re-syncs the
8821
+ * configured admin at boot; updated on scope, isAdmin and password edits"
8822
+ * retention="none — a row goes only when an operator deletes the user. A
8823
+ * `declareCollection` that adds a PK/UNIQUE/NOT-NULL-without-default column
8824
+ * REBUILDS the table: every account is wiped and only the configured admin
8825
+ * comes back on the next boot."
8826
+ */
8818
8827
  var USERS_COLLECTION = "users";
8828
+ /**
8829
+ * @durable class=config owner=local-auth
8830
+ * write="an operator mints an API key; `validateToken` rewrites `lastUsedAt` on
8831
+ * every request the key authorises"
8832
+ * retention="none — an explicit `revoke` is the only delete. API keys have no
8833
+ * expiry column and no sweep, so a key lives until someone removes it (or the
8834
+ * destructive `declareCollection` rebuild takes the table)."
8835
+ */
8819
8836
  var API_KEYS_COLLECTION = "api_keys";
8837
+ /**
8838
+ * @durable class=config owner=local-auth
8839
+ * write="an operator or the CLI mints a scoped token; `validate` fires
8840
+ * `updateLastUsed` on every accepted call"
8841
+ * retention="`revoke` deletes one. The daily sweep `reapExpired` drops rows past
8842
+ * `expiresAt` — a NULL expiry is a deliberate never-expires token and BETWEEN
8843
+ * never matches it. `cleanupOrphans` drops tokens owned by the legacy 'system'
8844
+ * id or by a user that no longer exists."
8845
+ */
8820
8846
  var SCOPED_TOKENS_COLLECTION = "scoped_tokens";
8847
+ /**
8848
+ * @durable class=ledger owner=local-auth
8849
+ * write="one row per redeemed OAuth code — every completed account link through
8850
+ * `oauthExchangeCode`; `touch` rewrites `lastUsedAt` on each refresh"
8851
+ * retention="ONLY revoked rows are pruned: the daily sweep deletes sessions
8852
+ * revoked more than OAUTH_REVOKED_RETENTION_MS (30 d) ago. An ACTIVE session
8853
+ * has `revokedAt` NULL, never expires and is never swept — the table grows one
8854
+ * row per login until an operator revokes the link."
8855
+ */
8821
8856
  var OAUTH_SESSIONS_COLLECTION = "oauth_sessions";
8822
8857
  /**
8823
8858
  * TOTP enrollment table — split off from `users` to avoid the
@@ -8831,6 +8866,13 @@ var OAUTH_SESSIONS_COLLECTION = "oauth_sessions";
8831
8866
  *
8832
8867
  * "Enabled" means `confirmedAt != null`. A half-enrolled row (`confirmedAt
8833
8868
  * = null`) is INACTIVE — `verifyTotp` returns false until confirmation.
8869
+ *
8870
+ * @durable class=config owner=local-auth
8871
+ * write="`setup` inserts a fresh secret for the user (deleting any pending row
8872
+ * first); `confirm` flips `confirmedAt` once a valid code proves possession"
8873
+ * retention="`disable` deletes the row, and `setup` deletes before re-inserting.
8874
+ * Nothing else prunes — deleting a USER does not cascade here, so their
8875
+ * enrollment row outlives the account."
8834
8876
  */
8835
8877
  var USER_TOTP_COLLECTION = "user_totp";
8836
8878
  var USERS_COLUMNS = [
@@ -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
  let node_os = require("node:os");
5
5
  node_os = require_chunk.__toESM(node_os);
6
6
  //#region src/builtins/local-network/local-network.addon.ts
@@ -1,4 +1,4 @@
1
- import { Ut as EventCategory, _t as BaseAddon, q as localNetworkCapability } from "../../dist-DMhxx5Kr.mjs";
1
+ import { Ut as EventCategory, _t as BaseAddon, q as localNetworkCapability } from "../../dist-DXDvrBi0.mjs";
2
2
  import * as os from "node:os";
3
3
  //#region src/builtins/local-network/local-network.addon.ts
4
4
  /**
@@ -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-CYqL8oZq.js");
6
+ const require_dist = require("../../dist-BH2tZ9ZN.js");
7
7
  //#region src/builtins/loki-logging/loki-payload.ts
8
8
  /**
9
9
  * Loki rejects a label name that is not a valid Prometheus label
@@ -1,4 +1,4 @@
1
- import { J as logDestinationCapability, _t as BaseAddon } from "../../dist-DMhxx5Kr.mjs";
1
+ import { J as logDestinationCapability, _t as BaseAddon } from "../../dist-DXDvrBi0.mjs";
2
2
  //#region src/builtins/loki-logging/loki-payload.ts
3
3
  /**
4
4
  * Loki rejects a label name that is not a valid Prometheus label
@@ -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-CYqL8oZq.js");
6
+ const require_dist = require("../../dist-BH2tZ9ZN.js");
7
7
  let node_child_process = require("node:child_process");
8
8
  let node_util = require("node:util");
9
9
  let node_os = require("node:os");
@@ -1,4 +1,4 @@
1
- import { At as createEvent, Ut as EventCategory, Z as metricsProviderCapability, _t as BaseAddon } from "../../dist-DMhxx5Kr.mjs";
1
+ import { At as createEvent, Ut as EventCategory, Z as metricsProviderCapability, _t as BaseAddon } from "../../dist-DXDvrBi0.mjs";
2
2
  import { execFile, execFileSync } from "node:child_process";
3
3
  import { promisify } from "node:util";
4
4
  import * as os from "node:os";
@@ -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-CYqL8oZq.js");
6
+ const require_dist = require("../../dist-BH2tZ9ZN.js");
7
7
  let node_child_process = require("node:child_process");
8
8
  let node_util = require("node:util");
9
9
  let node_os = require("node:os");
@@ -1,5 +1,5 @@
1
1
  import { o as __toESM } from "../../chunk-CNf5ZN-e.mjs";
2
- import { F as enumerateInferenceDevices, Mt as emitReadiness, Ut as EventCategory, _t as BaseAddon, gt as errMsg, ot as scoreRuntimes, tt as platformProbeCapability } from "../../dist-DMhxx5Kr.mjs";
2
+ import { F as enumerateInferenceDevices, Mt as emitReadiness, Ut as EventCategory, _t as BaseAddon, gt as errMsg, ot as scoreRuntimes, tt as platformProbeCapability } from "../../dist-DXDvrBi0.mjs";
3
3
  import { execFile } from "node:child_process";
4
4
  import { promisify } from "node:util";
5
5
  import * as os from "node:os";
@@ -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-CYqL8oZq.js");
6
+ const require_dist = require("../../dist-BH2tZ9ZN.js");
7
7
  //#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
8
8
  /**
9
9
  * Reconcile the durable `enabledProviders` set against authoritative
@@ -1,4 +1,4 @@
1
- import { Ut as EventCategory, _t as BaseAddon } from "../../dist-DMhxx5Kr.mjs";
1
+ import { Ut as EventCategory, _t as BaseAddon } from "../../dist-DXDvrBi0.mjs";
2
2
  //#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
3
3
  /**
4
4
  * Reconcile the durable `enabledProviders` set against authoritative
@@ -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-CYqL8oZq.js");
6
+ const require_dist = require("../../dist-BH2tZ9ZN.js");
7
7
  let zod = require("zod");
8
8
  let node_crypto = require("node:crypto");
9
9
  let _camstack_types_node = require("@camstack/types/node");
@@ -1,4 +1,4 @@
1
- import { Ct as DeviceType, It as nodePin, Ut as EventCategory, _t as BaseAddon, ct as snapshotCapability, ft as streamQualityLabel, gt as errMsg, i as BatteryStatusSchema, w as bareAddonId, xt as DeviceFeature } from "../../dist-DMhxx5Kr.mjs";
1
+ import { Ct as DeviceType, It as nodePin, Ut as EventCategory, _t as BaseAddon, ct as snapshotCapability, ft as streamQualityLabel, gt as errMsg, i as BatteryStatusSchema, w as bareAddonId, xt as DeviceFeature } from "../../dist-DXDvrBi0.mjs";
2
2
  import { z } from "zod";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { signExpiringUrl, verifyExpiringUrl } from "@camstack/types/node";
@@ -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-CYqL8oZq.js");
6
+ const require_dist = require("../../dist-BH2tZ9ZN.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 { _t as BaseAddon, dt as storageProviderCapability, z as filesystemBrowseCapability } from "../../dist-DMhxx5Kr.mjs";
1
+ import { _t as BaseAddon, dt as storageProviderCapability, z as filesystemBrowseCapability } from "../../dist-DXDvrBi0.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-CYqL8oZq.js");
6
+ const require_dist = require("../../dist-BH2tZ9ZN.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");
@@ -1144,10 +1144,21 @@ var SqliteSettingsBackend = class SqliteSettingsBackend {
1144
1144
  }
1145
1145
  }
1146
1146
  this.getDb().exec(`CREATE TABLE IF NOT EXISTS "${table}" (${colDefs.join(", ")})`);
1147
- if (schema.indexes) for (const idx of schema.indexes) {
1148
- const unique = idx.unique ? "UNIQUE " : "";
1149
- const cols = idx.columns.map((c) => `"${c}"`).join(", ");
1150
- this.getDb().exec(`CREATE ${unique}INDEX IF NOT EXISTS "${idx.name}" ON "${table}" (${cols})`);
1147
+ if (schema.indexes) {
1148
+ const pkName = schema.columns.find((c) => c.primaryKey === true)?.name ?? "id";
1149
+ const nonPkColumns = schema.columns.filter((c) => c.name !== pkName).map((c) => c.name);
1150
+ const kvBlobColumn = nonPkColumns.length === 1 && nonPkColumns[0] === "data" ? "data" : null;
1151
+ const isRealColumn = (field) => field === pkName || nonPkColumns.includes(field);
1152
+ const indexExpr = (field) => {
1153
+ if (isRealColumn(field)) return `"${field}"`;
1154
+ return kvBlobColumn === null ? null : `json_extract("${kvBlobColumn}", '$.${field}')`;
1155
+ };
1156
+ for (const idx of schema.indexes) {
1157
+ const exprs = idx.columns.map((c) => indexExpr(c));
1158
+ if (exprs.some((e) => e === null)) continue;
1159
+ const unique = idx.unique ? "UNIQUE " : "";
1160
+ this.getDb().exec(`CREATE ${unique}INDEX IF NOT EXISTS "${idx.name}" ON "${table}" (${exprs.join(", ")})`);
1161
+ }
1151
1162
  }
1152
1163
  this.structuredTables.set(table, fingerprint);
1153
1164
  }
@@ -1,4 +1,4 @@
1
- import { A as decodeVectorBase64, Dt as asJsonObject, Rt as parseJsonUnknown, _t as BaseAddon, f as RUNTIME_DEFAULTS, gt as errMsg, ht as vectorStoreCapability, k as dataStoreProviderCapability, mt as vectorDimFromBase64, w as bareAddonId } from "../../dist-DMhxx5Kr.mjs";
1
+ import { A as decodeVectorBase64, Dt as asJsonObject, Rt as parseJsonUnknown, _t as BaseAddon, f as RUNTIME_DEFAULTS, gt as errMsg, ht as vectorStoreCapability, k as dataStoreProviderCapability, mt as vectorDimFromBase64, w as bareAddonId } from "../../dist-DXDvrBi0.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { statSync } from "node:fs";
@@ -1138,10 +1138,21 @@ var SqliteSettingsBackend = class SqliteSettingsBackend {
1138
1138
  }
1139
1139
  }
1140
1140
  this.getDb().exec(`CREATE TABLE IF NOT EXISTS "${table}" (${colDefs.join(", ")})`);
1141
- if (schema.indexes) for (const idx of schema.indexes) {
1142
- const unique = idx.unique ? "UNIQUE " : "";
1143
- const cols = idx.columns.map((c) => `"${c}"`).join(", ");
1144
- this.getDb().exec(`CREATE ${unique}INDEX IF NOT EXISTS "${idx.name}" ON "${table}" (${cols})`);
1141
+ if (schema.indexes) {
1142
+ const pkName = schema.columns.find((c) => c.primaryKey === true)?.name ?? "id";
1143
+ const nonPkColumns = schema.columns.filter((c) => c.name !== pkName).map((c) => c.name);
1144
+ const kvBlobColumn = nonPkColumns.length === 1 && nonPkColumns[0] === "data" ? "data" : null;
1145
+ const isRealColumn = (field) => field === pkName || nonPkColumns.includes(field);
1146
+ const indexExpr = (field) => {
1147
+ if (isRealColumn(field)) return `"${field}"`;
1148
+ return kvBlobColumn === null ? null : `json_extract("${kvBlobColumn}", '$.${field}')`;
1149
+ };
1150
+ for (const idx of schema.indexes) {
1151
+ const exprs = idx.columns.map((c) => indexExpr(c));
1152
+ if (exprs.some((e) => e === null)) continue;
1153
+ const unique = idx.unique ? "UNIQUE " : "";
1154
+ this.getDb().exec(`CREATE ${unique}INDEX IF NOT EXISTS "${idx.name}" ON "${table}" (${exprs.join(", ")})`);
1155
+ }
1145
1156
  }
1146
1157
  this.structuredTables.set(table, fingerprint);
1147
1158
  }
@@ -3,13 +3,18 @@ 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-CYqL8oZq.js");
6
+ const require_dist = require("../../dist-BH2tZ9ZN.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);
10
10
  let node_path = require("node:path");
11
11
  node_path = require_chunk.__toESM(node_path);
12
12
  //#region src/builtins/storage-orchestrator/location-store.ts
13
+ /**
14
+ * @durable class=config owner=storage-orchestrator
15
+ * write="an operator creates or edits a location (basePath, minFreePercent, enabled, node pin); plus the boot reconcile — declared defaults seeded on a fresh install, and in-memory-only locations backfilled when the store is late-wired"
16
+ * retention="none — a row goes only when the operator deletes the location, or when the declaration pass prunes one whose declaring addon is gone. Bounded by the storage targets a human configures."
17
+ */
13
18
  var STORAGE_LOCATIONS = "storage_locations";
14
19
  /**
15
20
  * Reserved key under which the cluster `nodeId` (SP1) is persisted INSIDE
@@ -799,11 +804,23 @@ var StorageOrchestratorService = class {
799
804
  * 2. backfill — in-memory locations the DB doesn't have yet (the
800
805
  * pre-store seed defaults on a fresh install) are persisted, so the
801
806
  * store becomes the durable source of truth from here on.
807
+ *
808
+ * **The re-entry guard latches on a SUCCESSFUL hydrate, not on the attempt** —
809
+ * `loadAll()` is awaited BEFORE `this.locationStore` is assigned, and the
810
+ * order is load-bearing. Latching first meant one transient read error
811
+ * answered `hasStore()` true forever, so the addon's `ensureStoreWired` gate
812
+ * skipped every retry; the service then ran the whole process lifetime on
813
+ * pre-store seed defaults while `upsert` mirrored them onto rows it had never
814
+ * read, silently replacing the operator's persisted `minFreePercent`. Failing
815
+ * back to store-less is the safe direction: an in-memory-only service writes
816
+ * nothing over what is on disk, and the next `capability:provider-registered`
817
+ * event tries again. Held by
818
+ * `__tests__/storage-orchestrator-persistence.spec.ts`.
802
819
  */
803
820
  async attachStore(store) {
804
821
  if (this.locationStore) return;
805
- this.locationStore = store;
806
822
  const rows = await store.loadAll();
823
+ this.locationStore = store;
807
824
  const dbIds = new Set(rows.map((r) => r.id));
808
825
  for (const loc of rows) {
809
826
  const upgraded = !loc.isSystem && loc.id === `${loc.type}:default` ? {
@@ -1,8 +1,13 @@
1
- import { Lt as parseJsonObject, _t as BaseAddon, g as StorageMigrationJobSchema, h as StorageLocationTypeSchema, lt as storageCapability, st as settingsStoreCapability, ut as storageMigrationCapability } from "../../dist-DMhxx5Kr.mjs";
1
+ import { Lt as parseJsonObject, _t as BaseAddon, g as StorageMigrationJobSchema, h as StorageLocationTypeSchema, lt as storageCapability, st as settingsStoreCapability, ut as storageMigrationCapability } from "../../dist-DXDvrBi0.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";
5
5
  //#region src/builtins/storage-orchestrator/location-store.ts
6
+ /**
7
+ * @durable class=config owner=storage-orchestrator
8
+ * write="an operator creates or edits a location (basePath, minFreePercent, enabled, node pin); plus the boot reconcile — declared defaults seeded on a fresh install, and in-memory-only locations backfilled when the store is late-wired"
9
+ * retention="none — a row goes only when the operator deletes the location, or when the declaration pass prunes one whose declaring addon is gone. Bounded by the storage targets a human configures."
10
+ */
6
11
  var STORAGE_LOCATIONS = "storage_locations";
7
12
  /**
8
13
  * Reserved key under which the cluster `nodeId` (SP1) is persisted INSIDE
@@ -792,11 +797,23 @@ var StorageOrchestratorService = class {
792
797
  * 2. backfill — in-memory locations the DB doesn't have yet (the
793
798
  * pre-store seed defaults on a fresh install) are persisted, so the
794
799
  * store becomes the durable source of truth from here on.
800
+ *
801
+ * **The re-entry guard latches on a SUCCESSFUL hydrate, not on the attempt** —
802
+ * `loadAll()` is awaited BEFORE `this.locationStore` is assigned, and the
803
+ * order is load-bearing. Latching first meant one transient read error
804
+ * answered `hasStore()` true forever, so the addon's `ensureStoreWired` gate
805
+ * skipped every retry; the service then ran the whole process lifetime on
806
+ * pre-store seed defaults while `upsert` mirrored them onto rows it had never
807
+ * read, silently replacing the operator's persisted `minFreePercent`. Failing
808
+ * back to store-less is the safe direction: an in-memory-only service writes
809
+ * nothing over what is on disk, and the next `capability:provider-registered`
810
+ * event tries again. Held by
811
+ * `__tests__/storage-orchestrator-persistence.spec.ts`.
795
812
  */
796
813
  async attachStore(store) {
797
814
  if (this.locationStore) return;
798
- this.locationStore = store;
799
815
  const rows = await store.loadAll();
816
+ this.locationStore = store;
800
817
  const dbIds = new Set(rows.map((r) => r.id));
801
818
  for (const loc of rows) {
802
819
  const upgraded = !loc.isSystem && loc.id === `${loc.type}:default` ? {
@@ -139,6 +139,18 @@ export declare class StorageOrchestratorService {
139
139
  * 2. backfill — in-memory locations the DB doesn't have yet (the
140
140
  * pre-store seed defaults on a fresh install) are persisted, so the
141
141
  * store becomes the durable source of truth from here on.
142
+ *
143
+ * **The re-entry guard latches on a SUCCESSFUL hydrate, not on the attempt** —
144
+ * `loadAll()` is awaited BEFORE `this.locationStore` is assigned, and the
145
+ * order is load-bearing. Latching first meant one transient read error
146
+ * answered `hasStore()` true forever, so the addon's `ensureStoreWired` gate
147
+ * skipped every retry; the service then ran the whole process lifetime on
148
+ * pre-store seed defaults while `upsert` mirrored them onto rows it had never
149
+ * read, silently replacing the operator's persisted `minFreePercent`. Failing
150
+ * back to store-less is the safe direction: an in-memory-only service writes
151
+ * nothing over what is on disk, and the next `capability:provider-registered`
152
+ * event tries again. Held by
153
+ * `__tests__/storage-orchestrator-persistence.spec.ts`.
142
154
  */
143
155
  attachStore(store: ILocationStore): Promise<void>;
144
156
  /**
@@ -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-CYqL8oZq.js");
6
+ const require_dist = require("../../dist-BH2tZ9ZN.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 { Pt as hydrateSchema, _t as BaseAddon, gt as errMsg } from "../../dist-DMhxx5Kr.mjs";
1
+ import { Pt as hydrateSchema, _t as BaseAddon, gt as errMsg } from "../../dist-DXDvrBi0.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-CYqL8oZq.js");
6
+ const require_dist = require("../../dist-BH2tZ9ZN.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, _t as BaseAddon } from "../../dist-DMhxx5Kr.mjs";
1
+ import { J as logDestinationCapability, _t as BaseAddon } from "../../dist-DXDvrBi0.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";