@camstack/types 1.2.379 → 1.2.381

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 (45) hide show
  1. package/dist/addon.d.ts +3 -0
  2. package/dist/addon.js +67 -2
  3. package/dist/addon.mjs +5 -3
  4. package/dist/capabilities/caller-stamp.d.ts +12 -0
  5. package/dist/capabilities/index.d.ts +7 -2
  6. package/dist/capabilities/record-entries.cap.d.ts +84 -0
  7. package/dist/capabilities/records.cap.d.ts +399 -0
  8. package/dist/capabilities/storage-admin.cap.d.ts +268 -0
  9. package/dist/client.js +57 -32
  10. package/dist/client.mjs +57 -32
  11. package/dist/device/device-context.d.ts +2 -0
  12. package/dist/ffmpeg/fmp4-fragment-child.d.ts +2 -2
  13. package/dist/ffmpeg/process.d.ts +21 -0
  14. package/dist/generated/addon-api.d.ts +191 -0
  15. package/dist/generated/cap-input-defaults.d.ts +1 -1
  16. package/dist/generated/capability-router-map.d.ts +8 -2
  17. package/dist/generated/method-access-map.d.ts +1 -1
  18. package/dist/generated/method-device-selectors.d.ts +2 -2
  19. package/dist/generated/system-proxy.d.ts +2 -0
  20. package/dist/helpers/addon-slice-handle.d.ts +4 -0
  21. package/dist/helpers/trpc-leaf.d.ts +17 -0
  22. package/dist/index.d.ts +3 -1
  23. package/dist/index.js +724 -32
  24. package/dist/index.mjs +646 -33
  25. package/dist/interfaces/addon-peer-bytes.d.ts +19 -2
  26. package/dist/interfaces/addon.d.ts +13 -0
  27. package/dist/interfaces/config-ui.d.ts +4 -0
  28. package/dist/interfaces/event-bus.d.ts +32 -3
  29. package/dist/interfaces/storage.d.ts +1 -1
  30. package/dist/node.d.ts +2 -2
  31. package/dist/node.js +4 -0
  32. package/dist/node.mjs +4 -1
  33. package/dist/records/constants.d.ts +23 -0
  34. package/dist/records/entry-kind.d.ts +31 -0
  35. package/dist/records/errors.d.ts +81 -0
  36. package/dist/records/in-memory-records.d.ts +21 -0
  37. package/dist/records/index.d.ts +9 -0
  38. package/dist/records/record-kind.d.ts +144 -0
  39. package/dist/records/records-access.d.ts +153 -0
  40. package/dist/records/secret-paths.d.ts +52 -0
  41. package/dist/records/settings-array-adopts-from.d.ts +12 -0
  42. package/dist/records/settings-brokers-adopts-from.d.ts +10 -0
  43. package/dist/{sleep-DQYi915G.js → sleep-D8yJVc4r.js} +1971 -290
  44. package/dist/{sleep-D-Q2_Mcd.mjs → sleep-bZIhUvjd.mjs} +1413 -128
  45. package/package.json +1 -1
@@ -162,7 +162,7 @@ function collectKeychainStoredKeys(schema) {
162
162
  return keys;
163
163
  }
164
164
  function walkKeychainField(field, out) {
165
- if (!isRecord$3(field)) return;
165
+ if (!isRecord$6(field)) return;
166
166
  const type = field["type"];
167
167
  const key = field["key"];
168
168
  const isSecret = type === "password" || field["secret"] === true;
@@ -187,21 +187,21 @@ function schemaDeclaresAnyField(schema) {
187
187
  for (const section of sectionsOf(schema)) if (fieldsOf(section).length > 0) return true;
188
188
  return false;
189
189
  }
190
- function isRecord$3(value) {
190
+ function isRecord$6(value) {
191
191
  return typeof value === "object" && value !== null && !Array.isArray(value);
192
192
  }
193
193
  function sectionsOf(schema) {
194
- if (!isRecord$3(schema)) return [];
194
+ if (!isRecord$6(schema)) return [];
195
195
  const sections = schema["sections"];
196
196
  return Array.isArray(sections) ? sections : [];
197
197
  }
198
198
  function fieldsOf(node) {
199
- if (!isRecord$3(node)) return [];
199
+ if (!isRecord$6(node)) return [];
200
200
  const fields = node["fields"];
201
201
  return Array.isArray(fields) ? fields : [];
202
202
  }
203
203
  function walkField(field, out) {
204
- if (!isRecord$3(field)) return;
204
+ if (!isRecord$6(field)) return;
205
205
  const type = field["type"];
206
206
  const key = field["key"];
207
207
  if ((type === "password" || field["secret"] === true) && typeof key === "string" && key.length > 0) out.add(key);
@@ -241,7 +241,7 @@ function walkField(field, out) {
241
241
  var SECRET_CLEAR = { $secretClear: true };
242
242
  /** The `'***'` token D634 redaction writes for non-admins. */
243
243
  var LEGACY_DEVICE_REDACTION = "***";
244
- function isRecord$2(value) {
244
+ function isRecord$5(value) {
245
245
  return typeof value === "object" && value !== null && !Array.isArray(value);
246
246
  }
247
247
  function makeSecretMarker(ref) {
@@ -252,19 +252,19 @@ function makeSecretMarker(ref) {
252
252
  }
253
253
  /** A stored marker: an object whose `$secret` is a non-empty string. */
254
254
  function isSecretMarker(value) {
255
- if (!isRecord$2(value)) return false;
255
+ if (!isRecord$5(value)) return false;
256
256
  const ref = value["$secret"];
257
257
  return typeof ref === "string" && ref.length > 0;
258
258
  }
259
259
  /** Anything carrying a `$secret` key — a stored marker or a UI view of one. */
260
260
  function isSecretMarkerLike(value) {
261
- return isRecord$2(value) && Object.prototype.hasOwnProperty.call(value, "$secret");
261
+ return isRecord$5(value) && Object.prototype.hasOwnProperty.call(value, "$secret");
262
262
  }
263
263
  function isSecretClear(value) {
264
- return isRecord$2(value) && value["$secretClear"] === true;
264
+ return isRecord$5(value) && value["$secretClear"] === true;
265
265
  }
266
266
  function isSecretFieldView(value) {
267
- return isRecord$2(value) && value["set"] === true && isSecretMarkerLike(value);
267
+ return isRecord$5(value) && value["set"] === true && isSecretMarkerLike(value);
268
268
  }
269
269
  /**
270
270
  * The UI view of a stored secret field value: a marker becomes "set", inline
@@ -677,6 +677,33 @@ function typeOf(field) {
677
677
  default: return "other";
678
678
  }
679
679
  }
680
+ /** Strip inline `value` from a hydrated field for schema-only round-trips. */
681
+ function dehydrateConfigField(field) {
682
+ if (field.type === "group") return {
683
+ ...field,
684
+ fields: field.fields.map(dehydrateConfigField)
685
+ };
686
+ if (field.type === "sub-tabs") return {
687
+ ...field,
688
+ tabs: field.tabs.map((tab) => ({
689
+ ...tab,
690
+ fields: tab.fields.map(dehydrateConfigField)
691
+ }))
692
+ };
693
+ if (isValuelessField(field)) return field;
694
+ const { value: _drop, ...rest } = field;
695
+ return rest;
696
+ }
697
+ /** Inverse of {@link hydrateSchema} — drops resolved values from every leaf field. */
698
+ function dehydrateSchema(schema) {
699
+ return {
700
+ ...schema.tabs ? { tabs: [...schema.tabs] } : {},
701
+ sections: schema.sections.map((section) => ({
702
+ ...section,
703
+ fields: section.fields.map(dehydrateConfigField)
704
+ }))
705
+ };
706
+ }
680
707
  //#endregion
681
708
  //#region src/interfaces/event-bus.ts
682
709
  /**
@@ -1018,7 +1045,7 @@ var KeychainWriteRefusedError = class extends Error {
1018
1045
  }
1019
1046
  };
1020
1047
  var KEEP = { kind: "keep" };
1021
- function isRecord$1(value) {
1048
+ function isRecord$4(value) {
1022
1049
  return typeof value === "object" && value !== null && !Array.isArray(value);
1023
1050
  }
1024
1051
  function defaultMintId() {
@@ -1031,7 +1058,7 @@ function collectSecretMarkerRefs(value, out = []) {
1031
1058
  return out;
1032
1059
  }
1033
1060
  if (Array.isArray(value)) for (const item of value) collectSecretMarkerRefs(item, out);
1034
- else if (isRecord$1(value)) for (const child of Object.values(value)) collectSecretMarkerRefs(child, out);
1061
+ else if (isRecord$4(value)) for (const child of Object.values(value)) collectSecretMarkerRefs(child, out);
1035
1062
  return out;
1036
1063
  }
1037
1064
  async function storedValueEquals(secrets, marker, candidate) {
@@ -1086,7 +1113,7 @@ function rowId(row, idKey) {
1086
1113
  return null;
1087
1114
  }
1088
1115
  async function writeArray(ctx, node, incoming, stored, fieldPath) {
1089
- const storedRows = Array.isArray(stored) ? stored.filter(isRecord$1) : [];
1116
+ const storedRows = Array.isArray(stored) ? stored.filter(isRecord$4) : [];
1090
1117
  if (!Array.isArray(incoming)) {
1091
1118
  ctx.deletes.push(...collectSecretMarkerRefs(storedRows));
1092
1119
  return {
@@ -1102,7 +1129,7 @@ async function writeArray(ctx, node, incoming, stored, fieldPath) {
1102
1129
  const kept = /* @__PURE__ */ new Set();
1103
1130
  const rows = [];
1104
1131
  for (const row of incoming) {
1105
- if (!isRecord$1(row)) {
1132
+ if (!isRecord$4(row)) {
1106
1133
  rows.push(row);
1107
1134
  continue;
1108
1135
  }
@@ -1127,7 +1154,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
1127
1154
  case "leaf": return writeLeaf(ctx, incoming, stored, fieldPath);
1128
1155
  case "array": return writeArray(ctx, node, incoming, stored, fieldPath);
1129
1156
  case "object": {
1130
- if (!isRecord$1(incoming)) {
1157
+ if (!isRecord$4(incoming)) {
1131
1158
  if (incoming === void 0) return KEEP;
1132
1159
  ctx.deletes.push(...collectSecretMarkerRefs(stored));
1133
1160
  return {
@@ -1135,7 +1162,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
1135
1162
  value: incoming
1136
1163
  };
1137
1164
  }
1138
- const storedObj = isRecord$1(stored) ? stored : {};
1165
+ const storedObj = isRecord$4(stored) ? stored : {};
1139
1166
  return {
1140
1167
  kind: "value",
1141
1168
  value: await writeMembers(ctx, node.children, incoming, storedObj, (m) => `${fieldPath}.${m}`)
@@ -1258,7 +1285,7 @@ async function resolveSecretMarkers(value, secrets, options = {}) {
1258
1285
  value: items
1259
1286
  };
1260
1287
  }
1261
- if (isRecord$1(v)) {
1288
+ if (isRecord$4(v)) {
1262
1289
  const out = {};
1263
1290
  for (const [k, child] of Object.entries(v)) {
1264
1291
  const s = substitute(child);
@@ -1292,7 +1319,7 @@ var SecretOverwriteRefusedError = class extends Error {
1292
1319
  this.name = "SecretOverwriteRefusedError";
1293
1320
  }
1294
1321
  };
1295
- function isRecord(value) {
1322
+ function isRecord$3(value) {
1296
1323
  return typeof value === "object" && value !== null && !Array.isArray(value);
1297
1324
  }
1298
1325
  function resolvedValue(pass, marker) {
@@ -1321,7 +1348,7 @@ function inArray(pass, incoming, stored) {
1321
1348
  return incoming.map((item, index) => {
1322
1349
  const twin = stored[index];
1323
1350
  if (isSecretMarker(twin)) return typeof item === "string" && item === resolvedValue(pass, twin) ? twin : item;
1324
- if (isRecord(item) && isRecord(twin)) return inArrayRow(pass, item, twin);
1351
+ if (isRecord$3(item) && isRecord$3(twin)) return inArrayRow(pass, item, twin);
1325
1352
  if (Array.isArray(item) && Array.isArray(twin)) return inArray(pass, item, twin);
1326
1353
  return item;
1327
1354
  });
@@ -1332,7 +1359,7 @@ function inArrayRow(pass, incoming, stored) {
1332
1359
  const twin = stored[key];
1333
1360
  if (isSecretMarker(twin)) {
1334
1361
  if (typeof value === "string" && value === resolvedValue(pass, twin)) out[key] = twin;
1335
- } else if (isRecord(value) && isRecord(twin)) out[key] = inArrayRow(pass, value, twin);
1362
+ } else if (isRecord$3(value) && isRecord$3(twin)) out[key] = inArrayRow(pass, value, twin);
1336
1363
  else if (Array.isArray(value) && Array.isArray(twin)) out[key] = inArray(pass, value, twin);
1337
1364
  }
1338
1365
  return out;
@@ -1340,7 +1367,7 @@ function inArrayRow(pass, incoming, stored) {
1340
1367
  async function walk(pass, incoming, stored) {
1341
1368
  if (isSecretMarker(stored)) return atMarker(pass, incoming, stored);
1342
1369
  if (Array.isArray(incoming) && Array.isArray(stored)) return inArray(pass, incoming, stored);
1343
- if (!isRecord(incoming) || !isRecord(stored)) return incoming;
1370
+ if (!isRecord$3(incoming) || !isRecord$3(stored)) return incoming;
1344
1371
  const out = { ...incoming };
1345
1372
  for (const [key, value] of Object.entries(incoming)) out[key] = await walk(pass, value, stored[key]);
1346
1373
  return out;
@@ -1371,7 +1398,7 @@ async function restoreUnchangedSecrets(input) {
1371
1398
  function isJsonEqual(a, b) {
1372
1399
  if (Object.is(a, b)) return true;
1373
1400
  if (Array.isArray(a)) return Array.isArray(b) && a.length === b.length && a.every((v, i) => isJsonEqual(v, b[i]));
1374
- if (isRecord(a) && isRecord(b)) {
1401
+ if (isRecord$3(a) && isRecord$3(b)) {
1375
1402
  const keys = Object.keys(a);
1376
1403
  if (keys.length !== Object.keys(b).length) return false;
1377
1404
  return keys.every((k) => Object.prototype.hasOwnProperty.call(b, k) && isJsonEqual(a[k], b[k]));
@@ -1395,7 +1422,7 @@ function markerKeysOf(blob, owner) {
1395
1422
  }
1396
1423
  function nodeFromStored(value, owner) {
1397
1424
  if (isSecretMarker(value)) return isSecretRefOwnedBy(value.$secret, owner) ? { kind: "leaf" } : null;
1398
- if (!isRecord(value)) return null;
1425
+ if (!isRecord$3(value)) return null;
1399
1426
  const children = /* @__PURE__ */ new Map();
1400
1427
  for (const [key, child] of Object.entries(value)) {
1401
1428
  const node = nodeFromStored(child, owner);
@@ -2202,7 +2229,7 @@ var BaseAddon = class {
2202
2229
  if (!ctx) return;
2203
2230
  const addonId = ctx.id;
2204
2231
  setImmediate(() => {
2205
- ctx.api.addons?.restartAddon?.mutate({ addonId }).then(() => {
2232
+ ctx.api.addons.restartAddon.mutate({ addonId }).then(() => {
2206
2233
  ctx.logger.info("addon auto-restart triggered by restart-required setting change", { meta: { changedFields: patchKeys.filter((k) => restartKeys.has(k)) } });
2207
2234
  }).catch((err) => {
2208
2235
  ctx.logger.error("addon auto-restart failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
@@ -3122,6 +3149,1297 @@ async function resolveSecretViewsIn(args, secrets) {
3122
3149
  return swap(args).value;
3123
3150
  }
3124
3151
  //#endregion
3152
+ //#region src/records/constants.ts
3153
+ /** Limits and names of `ctx.records` (D881). One authority; the engine and the facade read it. */
3154
+ /** The files a kind may live in. `history` is device-history's (D850), never records. */
3155
+ var RECORD_DATABASES = ["settings", "events"];
3156
+ /** The classes of a kind: the `@durable` vocabulary, one authority (replaces the annotation). */
3157
+ var RECORD_CLASSES = [
3158
+ "config",
3159
+ "ledger",
3160
+ "audit",
3161
+ "mirror",
3162
+ "ephemeral"
3163
+ ];
3164
+ var RECORD_DEFAULT_MAX_DATA_BYTES = 64 * 1024;
3165
+ var RECORD_MAX_DATA_BYTES = 1024 * 1024;
3166
+ var RECORD_ID_MAX_LENGTH = 256;
3167
+ var RECORD_BATCH_MAX = 1e3;
3168
+ var RECORD_BATCH_MAX_BYTES = 4 * 1024 * 1024;
3169
+ var RECORD_QUERY_MAX = 1e3;
3170
+ /** Rows one DELETE statement removes before the serving thread yields. */
3171
+ var RECORD_DELETE_BATCH = 5e3;
3172
+ /** A kind in the `settings` file may not bound itself above this (D447: high volume is `events`). */
3173
+ var RECORD_SETTINGS_MAX_ROWS = 5e4;
3174
+ var RECORD_MAX_INDEXES = 8;
3175
+ var RECORD_MAX_INDEX_FIELDS = 4;
3176
+ /** The engine's TTL sweep cadence. */
3177
+ var RECORD_SWEEP_INTERVAL_MS = 10 * 6e4;
3178
+ /** The `Column`-free proof prefix: a ref collection for a kind's secret fields. */
3179
+ var RECORD_SECRET_COLLECTION_PREFIX = "records:";
3180
+ //#endregion
3181
+ //#region src/records/errors.ts
3182
+ /**
3183
+ * The named failures of `ctx.records` (D881).
3184
+ *
3185
+ * A records call crosses a worker thread, a UDS channel and a tRPC router, and
3186
+ * an error class does not survive any of them - only its message does. So
3187
+ * every message STARTS with a stable code, `records/<code>: <detail>`, and
3188
+ * {@link recordsErrorFromMessage} rebuilds the typed class on the caller's side.
3189
+ * A failed read is never `[]` or `undefined`: it throws one of these.
3190
+ */
3191
+ /** Every code a records failure carries. */
3192
+ var RECORDS_ERROR_CODES = [
3193
+ "rev-conflict",
3194
+ "too-large",
3195
+ "unindexed-filter",
3196
+ "filter-required",
3197
+ "unknown-kind",
3198
+ "not-found",
3199
+ "unique-violation",
3200
+ "plaintext-secret",
3201
+ "foreign-marker",
3202
+ "secret-unavailable",
3203
+ "invalid-record",
3204
+ "declaration-refused",
3205
+ "adoption-pending",
3206
+ "no-caller",
3207
+ "batch-too-large"
3208
+ ];
3209
+ var PREFIX = "records/";
3210
+ /** The base of every records failure. `detail` is the human part of the message. */
3211
+ var RecordsError = class extends Error {
3212
+ code;
3213
+ detail;
3214
+ constructor(code, detail) {
3215
+ super(`${PREFIX}${code}: ${detail}`);
3216
+ this.name = "RecordsError";
3217
+ this.code = code;
3218
+ this.detail = detail;
3219
+ }
3220
+ };
3221
+ /** A write guarded by `ifRev` found another revision (or an existing row for `ifRev: 0`). */
3222
+ var RevConflictError = class extends RecordsError {
3223
+ constructor(detail) {
3224
+ super("rev-conflict", detail);
3225
+ this.name = "RevConflictError";
3226
+ }
3227
+ };
3228
+ /** `data` exceeds the kind's `maxDataBytes`. Bytes are never record fields (D613). */
3229
+ var RecordTooLargeError = class extends RecordsError {
3230
+ constructor(detail) {
3231
+ super("too-large", detail);
3232
+ this.name = "RecordTooLargeError";
3233
+ }
3234
+ };
3235
+ /** A filter, order or aggregate names a field no declared index serves. */
3236
+ var UnindexedFilterError = class extends RecordsError {
3237
+ constructor(detail) {
3238
+ super("unindexed-filter", detail);
3239
+ this.name = "UnindexedFilterError";
3240
+ }
3241
+ };
3242
+ /** A bulk delete with no predicate at all. */
3243
+ var FilterRequiredError = class extends RecordsError {
3244
+ constructor(detail) {
3245
+ super("filter-required", detail);
3246
+ this.name = "FilterRequiredError";
3247
+ }
3248
+ };
3249
+ /** The caller declared no such kind (another addon's kind is indistinguishable from none). */
3250
+ var UnknownRecordKindError = class extends RecordsError {
3251
+ constructor(detail) {
3252
+ super("unknown-kind", detail);
3253
+ this.name = "UnknownRecordKindError";
3254
+ }
3255
+ };
3256
+ var RecordNotFoundError = class extends RecordsError {
3257
+ constructor(detail) {
3258
+ super("not-found", detail);
3259
+ this.name = "RecordNotFoundError";
3260
+ }
3261
+ };
3262
+ /** A unique index refused the write. */
3263
+ var RecordUniqueViolationError = class extends RecordsError {
3264
+ constructor(detail) {
3265
+ super("unique-violation", detail);
3266
+ this.name = "RecordUniqueViolationError";
3267
+ }
3268
+ };
3269
+ /** A secret field held a plain string where only a keychain marker may be stored. */
3270
+ var PlaintextSecretError = class extends RecordsError {
3271
+ constructor(detail) {
3272
+ super("plaintext-secret", detail);
3273
+ this.name = "PlaintextSecretError";
3274
+ }
3275
+ };
3276
+ /** A marker whose ref is not the row's own (the D878 rule). */
3277
+ var ForeignSecretMarkerError = class extends RecordsError {
3278
+ constructor(detail) {
3279
+ super("foreign-marker", detail);
3280
+ this.name = "ForeignSecretMarkerError";
3281
+ }
3282
+ };
3283
+ /** The keychain could not store or serve a value: explicit, never an empty string. */
3284
+ var RecordSecretUnavailableError = class extends RecordsError {
3285
+ constructor(detail) {
3286
+ super("secret-unavailable", detail);
3287
+ this.name = "RecordSecretUnavailableError";
3288
+ }
3289
+ };
3290
+ var InvalidRecordError = class extends RecordsError {
3291
+ constructor(detail) {
3292
+ super("invalid-record", detail);
3293
+ this.name = "InvalidRecordError";
3294
+ }
3295
+ };
3296
+ /** A kind declaration the engine refuses (non-additive change, bad shape, wrong file). */
3297
+ var DeclarationRefusedError = class extends RecordsError {
3298
+ constructor(detail) {
3299
+ super("declaration-refused", detail);
3300
+ this.name = "DeclarationRefusedError";
3301
+ }
3302
+ };
3303
+ /** A kind is empty while the legacy table it adopts from still holds rows. */
3304
+ var AdoptionPendingError = class extends RecordsError {
3305
+ constructor(detail) {
3306
+ super("adoption-pending", detail);
3307
+ this.name = "AdoptionPendingError";
3308
+ }
3309
+ };
3310
+ var NoCallerError = class extends RecordsError {
3311
+ constructor(detail) {
3312
+ super("no-caller", detail);
3313
+ this.name = "NoCallerError";
3314
+ }
3315
+ };
3316
+ var BatchTooLargeError = class extends RecordsError {
3317
+ constructor(detail) {
3318
+ super("batch-too-large", detail);
3319
+ this.name = "BatchTooLargeError";
3320
+ }
3321
+ };
3322
+ var FACTORIES = {
3323
+ "rev-conflict": (d) => new RevConflictError(d),
3324
+ "too-large": (d) => new RecordTooLargeError(d),
3325
+ "unindexed-filter": (d) => new UnindexedFilterError(d),
3326
+ "filter-required": (d) => new FilterRequiredError(d),
3327
+ "unknown-kind": (d) => new UnknownRecordKindError(d),
3328
+ "not-found": (d) => new RecordNotFoundError(d),
3329
+ "unique-violation": (d) => new RecordUniqueViolationError(d),
3330
+ "plaintext-secret": (d) => new PlaintextSecretError(d),
3331
+ "foreign-marker": (d) => new ForeignSecretMarkerError(d),
3332
+ "secret-unavailable": (d) => new RecordSecretUnavailableError(d),
3333
+ "invalid-record": (d) => new InvalidRecordError(d),
3334
+ "declaration-refused": (d) => new DeclarationRefusedError(d),
3335
+ "adoption-pending": (d) => new AdoptionPendingError(d),
3336
+ "no-caller": (d) => new NoCallerError(d),
3337
+ "batch-too-large": (d) => new BatchTooLargeError(d)
3338
+ };
3339
+ function isCode(value) {
3340
+ return RECORDS_ERROR_CODES.some((code) => code === value);
3341
+ }
3342
+ /**
3343
+ * Rebuild the typed error from a message that crossed a wire; `null` when the
3344
+ * message is not a records failure.
3345
+ */
3346
+ function recordsErrorFromMessage(message) {
3347
+ if (!message.startsWith(PREFIX)) return null;
3348
+ const colon = message.indexOf(": ");
3349
+ if (colon < 0) return null;
3350
+ const code = message.slice(8, colon);
3351
+ if (!isCode(code)) return null;
3352
+ return FACTORIES[code](message.slice(colon + 2));
3353
+ }
3354
+ /** The records failure inside any thrown value (a wrapped tRPC error included), or the value. */
3355
+ function asRecordsError(err) {
3356
+ if (err instanceof RecordsError) return err;
3357
+ if (err instanceof Error) {
3358
+ const typed = recordsErrorFromMessage(err.message);
3359
+ if (typed !== null) return typed;
3360
+ }
3361
+ return err;
3362
+ }
3363
+ //#endregion
3364
+ //#region src/device/zod-secret.ts
3365
+ /**
3366
+ * Secret declaration on a Zod config schema (D783).
3367
+ *
3368
+ * A field is a secret because its schema SAYS so — `.meta({ secret: true })`,
3369
+ * spelled {@link SECRET_META} — never because its key looks like a credential.
3370
+ * It is the Zod twin of `secret: true` / `type: 'password'` on a config-UI
3371
+ * field (`isSecretConfigField`), and every consumer that treats secrets
3372
+ * specially reads it: the settings form (`zodEntriesToConfigUI`), the paths a
3373
+ * device advertises at `registerDevice` (`secretConfigPaths`, which the
3374
+ * non-admin redaction withholds at any depth), and the keychain later.
3375
+ *
3376
+ * Zod keeps `.meta()` in `z.globalRegistry`, which lives on `globalThis`, so a
3377
+ * declaration made by an addon's own copy of zod is visible here.
3378
+ */
3379
+ /**
3380
+ * `{ secret: true }` — the one spelling of "this field holds a credential".
3381
+ *
3382
+ * Addons write the LITERAL `.meta({ secret: true })` rather than importing
3383
+ * this constant: an addon running against an older `@camstack/types` would
3384
+ * otherwise call `.meta(undefined)`, which in zod v4 is the metadata GETTER
3385
+ * and returns no schema at all.
3386
+ */
3387
+ var SECRET_META = { secret: true };
3388
+ function defOf(schema) {
3389
+ const zodBag = Reflect.get(schema, "_zod");
3390
+ if (typeof zodBag !== "object" || zodBag === null) return {};
3391
+ const def = Reflect.get(zodBag, "def");
3392
+ if (typeof def !== "object" || def === null) return {};
3393
+ return def;
3394
+ }
3395
+ function declaredHere(schema) {
3396
+ return z.globalRegistry.get(schema)?.secret === true;
3397
+ }
3398
+ /** Wrapper kinds whose `innerType` is the field itself. */
3399
+ var WRAPPERS = new Set([
3400
+ "optional",
3401
+ "nullable",
3402
+ "default",
3403
+ "prefault",
3404
+ "catch",
3405
+ "readonly",
3406
+ "nonoptional"
3407
+ ]);
3408
+ /**
3409
+ * The schema layers that make up ONE field: the schema itself and every
3410
+ * wrapper below it (optional / default / nullable / readonly / catch), plus
3411
+ * both sides of a pipe (`z.preprocess` puts the real schema on `out`,
3412
+ * `.transform` on `in`).
3413
+ */
3414
+ function layersOf(schema) {
3415
+ const out = [];
3416
+ const queue = [schema];
3417
+ while (queue.length > 0) {
3418
+ const s = queue.shift();
3419
+ if (!s || out.includes(s)) continue;
3420
+ out.push(s);
3421
+ const def = defOf(s);
3422
+ if (def.type !== void 0 && WRAPPERS.has(def.type) && def.innerType) queue.push(def.innerType);
3423
+ if (def.type === "pipe") {
3424
+ if (def.in) queue.push(def.in);
3425
+ if (def.out) queue.push(def.out);
3426
+ }
3427
+ }
3428
+ return out;
3429
+ }
3430
+ /** True when any layer of this field declares `.meta({ secret: true })`. */
3431
+ function isZodSecret(schema) {
3432
+ return layersOf(schema).some(declaredHere);
3433
+ }
3434
+ /**
3435
+ * Every declared secret path in a config schema: dotted keys, `[]` for "each
3436
+ * element of this array" (`connection.password`, `rows[].token`). A declared
3437
+ * object or array is reported as one path and not descended into — everything
3438
+ * under it is secret.
3439
+ */
3440
+ function collectZodSecretPaths(schema, prefix = "") {
3441
+ if (isZodSecret(schema)) return prefix.length > 0 ? [prefix] : [];
3442
+ const paths = [];
3443
+ for (const layer of layersOf(schema)) {
3444
+ const def = defOf(layer);
3445
+ if (def.type === "object" && def.shape) for (const [key, child] of Object.entries(def.shape)) paths.push(...collectZodSecretPaths(child, prefix ? `${prefix}.${key}` : key));
3446
+ else if (def.type === "array" && def.element) paths.push(...collectZodSecretPaths(def.element, `${prefix}[]`));
3447
+ else if (def.type === "union" && def.options) for (const option of def.options) paths.push(...collectZodSecretPaths(option, prefix));
3448
+ else if (def.type === "intersection") {
3449
+ if (def.left) paths.push(...collectZodSecretPaths(def.left, prefix));
3450
+ if (def.right) paths.push(...collectZodSecretPaths(def.right, prefix));
3451
+ }
3452
+ }
3453
+ return [...new Set(paths)];
3454
+ }
3455
+ //#endregion
3456
+ //#region src/records/secret-paths.ts
3457
+ /**
3458
+ * Secret fields of a record, addressed the way a Zod schema declares them
3459
+ * (`collectZodSecretPaths`): dotted keys, `[]` for "each element of this array"
3460
+ * (`auth.accessToken`, `headers[].value`).
3461
+ *
3462
+ * Array elements are matched by a DECLARED id key (`secretArrayKeys`:
3463
+ * `{ headers: 'name' }`), never by index, so reordering a list keeps every
3464
+ * keychain ref (the same rule as `arrayItemFieldPath`). The concrete path of a
3465
+ * leaf names its element: `headers[X-Api].value`.
3466
+ *
3467
+ * Pure and browser-safe. Nothing here mutates: every transform returns a new value.
3468
+ */
3469
+ /** The array prefixes (declared form, e.g. `headers` or `a.headers`) of a path. */
3470
+ function parseSecretPath(path) {
3471
+ if (path.length === 0) throw new InvalidRecordError("an empty secret path");
3472
+ return path.split(".").map((raw) => {
3473
+ const each = raw.endsWith("[]");
3474
+ const key = each ? raw.slice(0, -2) : raw;
3475
+ if (key.length === 0) throw new InvalidRecordError(`secret path "${path}" has an empty segment`);
3476
+ return {
3477
+ key,
3478
+ each
3479
+ };
3480
+ });
3481
+ }
3482
+ /** The declared array prefixes of `path` that need an id key (`headers`, `a.rows`). */
3483
+ function secretArrayPrefixes(path) {
3484
+ const segments = parseSecretPath(path);
3485
+ const prefixes = [];
3486
+ const walked = [];
3487
+ for (const segment of segments) {
3488
+ walked.push(segment.key);
3489
+ if (segment.each) prefixes.push(walked.join("."));
3490
+ }
3491
+ return prefixes;
3492
+ }
3493
+ function isRecord$2(value) {
3494
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3495
+ }
3496
+ function elementId(element, idKey, declared, prefix) {
3497
+ const id = isRecord$2(element) ? element[idKey] : void 0;
3498
+ if (typeof id !== "string" || id.length === 0) throw new InvalidRecordError(`"${declared}": every element of "${prefix}" needs a non-empty string "${idKey}" to carry a secret`);
3499
+ return id;
3500
+ }
3501
+ /**
3502
+ * Visit every secret leaf PRESENT in `data` (an absent branch has nothing to
3503
+ * visit). `replace` returns the new leaf value, or {@link REMOVE_LEAF}; the
3504
+ * result is a new body, `data` is untouched.
3505
+ */
3506
+ var REMOVE_LEAF = Symbol("remove-leaf");
3507
+ function mapAt(node, segments, index, walkedKeys, concretePrefix, declared, arrayKeys, visit) {
3508
+ if (!isRecord$2(node)) return node;
3509
+ const segment = segments[index];
3510
+ if (segment === void 0) return node;
3511
+ if (!Object.prototype.hasOwnProperty.call(node, segment.key)) return node;
3512
+ const child = node[segment.key];
3513
+ const keys = [...walkedKeys, segment.key];
3514
+ const last = index === segments.length - 1;
3515
+ if (segment.each) {
3516
+ if (!Array.isArray(child)) return node;
3517
+ const prefix = keys.join(".");
3518
+ const idKey = arrayKeys[prefix];
3519
+ if (idKey === void 0) throw new InvalidRecordError(`"${declared}": no id key declared for the array "${prefix}"`);
3520
+ const mapped = child.map((element) => {
3521
+ const id = elementId(element, idKey, declared, prefix);
3522
+ const concrete = `${concretePrefix}${concretePrefix.length > 0 ? "." : ""}${segment.key}[${encodeURIComponent(id)}]`;
3523
+ return last ? element : mapAt(element, segments, index + 1, keys, concrete, declared, arrayKeys, visit);
3524
+ });
3525
+ return {
3526
+ ...node,
3527
+ [segment.key]: mapped
3528
+ };
3529
+ }
3530
+ const concrete = `${concretePrefix}${concretePrefix.length > 0 ? "." : ""}${segment.key}`;
3531
+ if (last) {
3532
+ const replacement = visit({
3533
+ declared,
3534
+ concrete,
3535
+ value: child
3536
+ });
3537
+ if (replacement === REMOVE_LEAF) return Object.fromEntries(Object.entries(node).filter(([key]) => key !== segment.key));
3538
+ return {
3539
+ ...node,
3540
+ [segment.key]: replacement
3541
+ };
3542
+ }
3543
+ return {
3544
+ ...node,
3545
+ [segment.key]: mapAt(child, segments, index + 1, keys, concrete, declared, arrayKeys, visit)
3546
+ };
3547
+ }
3548
+ /** Replace/remove every present secret leaf; returns a NEW body. */
3549
+ function mapSecretLeaves(data, paths, arrayKeys, visit) {
3550
+ let current = data;
3551
+ for (const declared of paths) current = mapAt(current, parseSecretPath(declared), 0, [], "", declared, arrayKeys, visit);
3552
+ return current;
3553
+ }
3554
+ /** Every present secret leaf, read-only. */
3555
+ function collectSecretLeaves(data, paths, arrayKeys) {
3556
+ const found = [];
3557
+ mapSecretLeaves(data, paths, arrayKeys, (leaf) => {
3558
+ found.push(leaf);
3559
+ return leaf.value;
3560
+ });
3561
+ return found;
3562
+ }
3563
+ /**
3564
+ * The keychain collection name a kind's secrets live under. Prefixed so a
3565
+ * record's refs never collide with the refs a legacy collection of the same name
3566
+ * already holds during an adoption.
3567
+ */
3568
+ function recordSecretCollection(kind) {
3569
+ return `${RECORD_SECRET_COLLECTION_PREFIX}${kind}`;
3570
+ }
3571
+ /** The ONE ref a row's secret field may carry: the engine and the facade both build it here. */
3572
+ function recordSecretRef(owner, kind, rowId, concretePath) {
3573
+ return buildSecretRef({
3574
+ owner,
3575
+ scope: {
3576
+ kind: "row",
3577
+ collection: recordSecretCollection(kind),
3578
+ rowId
3579
+ },
3580
+ fieldPath: concretePath
3581
+ });
3582
+ }
3583
+ /** A concrete path built from a flat array item, re-exported for adoption tooling. */
3584
+ var recordArrayItemPath = arrayItemFieldPath;
3585
+ //#endregion
3586
+ //#region src/records/record-kind.ts
3587
+ /**
3588
+ * Record kinds (D881): the declaration an addon makes of one kind of fact, the
3589
+ * Zod row schema that describes it, and the helper that turns the two into the
3590
+ * JSON the engine stores.
3591
+ *
3592
+ * A kind is declared ONCE, next to the code that owns it, and the engine's
3593
+ * reconciler creates its indexes - nothing creates DDL at runtime from a write.
3594
+ * Everything the generic machinery needs (secret fields, the entry descriptor)
3595
+ * is DERIVED from the Zod schema: `.meta({ secret: true })` marks a credential,
3596
+ * never a field name (D879).
3597
+ */
3598
+ /** A JSON field path: `trackId`, `auth.accessToken`. Charset-restricted: it is rendered into DDL. */
3599
+ var RecordFieldPathSchema = z.string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,63}(\.[A-Za-z_][A-Za-z0-9_]{0,63}){0,3}$/);
3600
+ var RecordIndexSchema = z.object({
3601
+ name: z.string().regex(/^[a-z][a-z0-9_]{0,31}$/),
3602
+ fields: z.array(RecordFieldPathSchema).min(1).max(4),
3603
+ unique: z.boolean().optional()
3604
+ }).strict();
3605
+ var RecordRetentionSchema = z.union([
3606
+ z.object({
3607
+ ttlMs: z.number().int().positive(),
3608
+ from: z.enum(["at", "write"])
3609
+ }).strict(),
3610
+ z.object({
3611
+ maxRows: z.number().int().positive().optional(),
3612
+ maxRowsPerDevice: z.number().int().positive().optional()
3613
+ }).strict().refine((r) => r.maxRows !== void 0 || r.maxRowsPerDevice !== void 0, { message: "name maxRows, maxRowsPerDevice or both" }),
3614
+ z.object({
3615
+ owner: z.string().min(1),
3616
+ reason: z.string().min(1)
3617
+ }).strict(),
3618
+ z.object({ none: z.string().min(1) }).strict()
3619
+ ]);
3620
+ /** The descriptor a generic entries UI reads (D881 "generic entries"). */
3621
+ var EntryDescriptorSchema = z.object({
3622
+ title: z.string().min(1),
3623
+ /** The record body field shown as the entry's name. */
3624
+ nameField: z.string().min(1),
3625
+ /** JSON Schema of the entry body; `secret: true` marks a password field. */
3626
+ fields: z.record(z.string(), z.unknown())
3627
+ }).strict();
3628
+ /** What crosses the wire and sits in the engine's catalog: JSON only, no Zod. */
3629
+ var RecordKindDeclarationSchema = z.object({
3630
+ database: z.enum(RECORD_DATABASES).default("settings"),
3631
+ class: z.enum(RECORD_CLASSES),
3632
+ writeTrigger: z.string().min(1),
3633
+ device: z.enum([
3634
+ "required",
3635
+ "optional",
3636
+ "none"
3637
+ ]).default("none"),
3638
+ at: z.enum(["required", "none"]).default("none"),
3639
+ indexes: z.array(RecordIndexSchema).max(8).default([]),
3640
+ retention: RecordRetentionSchema,
3641
+ deviceRemoval: z.enum(["delete", "none"]).default("none"),
3642
+ maxDataBytes: z.number().int().positive().max(RECORD_MAX_DATA_BYTES).default(RECORD_DEFAULT_MAX_DATA_BYTES),
3643
+ /** Derived from the Zod schema; never written by hand. */
3644
+ secretPaths: z.array(z.string().min(1)).default([]),
3645
+ /** The id key of each array that carries a secret (`{ headers: 'name' }`). */
3646
+ secretArrayKeys: z.record(z.string(), z.string()).default({}),
3647
+ /** The legacy table this kind adopts from; the boot guard reads it (D853: no migration code). */
3648
+ adoptsFrom: z.string().min(1).optional(),
3649
+ /** Kinds that must agree through `transact` sit in one file under one family name. */
3650
+ transactFamily: z.string().min(1).optional(),
3651
+ entry: EntryDescriptorSchema.optional()
3652
+ }).strict();
3653
+ /** The kind names: lower-case, dash separated, short enough for an index name. */
3654
+ var RecordKindNameSchema = z.string().regex(/^[a-z][a-z0-9-]{0,47}$/);
3655
+ /** Cross-field rules a declaration must satisfy. Throws {@link DeclarationRefusedError}. */
3656
+ function assertValidDeclaration(name, decl) {
3657
+ const refuse = (why) => {
3658
+ throw new DeclarationRefusedError(`kind "${name}": ${why}`);
3659
+ };
3660
+ if (!RecordKindNameSchema.safeParse(name).success) refuse("the name must be lower-case-dashed");
3661
+ const seen = /* @__PURE__ */ new Set();
3662
+ for (const index of decl.indexes) {
3663
+ if (seen.has(index.name)) refuse(`index name "${index.name}" is declared twice`);
3664
+ seen.add(index.name);
3665
+ }
3666
+ const { retention } = decl;
3667
+ const hasSecrets = decl.secretPaths.length > 0;
3668
+ if ("ttlMs" in retention) {
3669
+ if (retention.from === "at" && decl.at !== "required") refuse("a ttl from \"at\" needs at: \"required\"");
3670
+ if (hasSecrets) refuse("a kind with secret fields cannot use engine TTL (its keychain values would be orphaned)");
3671
+ }
3672
+ if ("maxRows" in retention || "maxRowsPerDevice" in retention) {
3673
+ if (retention.maxRowsPerDevice !== void 0 && decl.device !== "required") refuse("maxRowsPerDevice needs device: \"required\"");
3674
+ if (decl.at !== "required") refuse("a row bound trims the oldest \"at\": it needs at: \"required\"");
3675
+ if (hasSecrets) refuse("a kind with secret fields cannot use an engine row bound");
3676
+ const bound = Math.max(retention.maxRows ?? 0, retention.maxRowsPerDevice ?? 0);
3677
+ if (decl.database === "settings" && bound > 5e4) refuse(`a row bound above ${RECORD_SETTINGS_MAX_ROWS} belongs in database: "events" (a big delete on the settings thread stalls every configuration read)`);
3678
+ }
3679
+ if (decl.deviceRemoval === "delete" && decl.device === "none") refuse("deviceRemoval: \"delete\" needs a device: \"required\" or \"optional\"");
3680
+ for (const path of decl.secretPaths) for (const prefix of secretArrayPrefixes(path)) if (decl.secretArrayKeys[prefix] === void 0) refuse(`secret path "${path}" crosses the array "${prefix}": declare its id key in secretArrayKeys`);
3681
+ }
3682
+ function bodyFieldsOf(schema) {
3683
+ return { ...z.toJSONSchema(schema, {
3684
+ unrepresentable: "any",
3685
+ io: "input"
3686
+ }) };
3687
+ }
3688
+ function isRecordLike(value) {
3689
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3690
+ }
3691
+ /** Does every branch of the body schema carry `field`? (A discriminated union has several.) */
3692
+ function hasNameField(json, field) {
3693
+ const branches = json["oneOf"] ?? json["anyOf"];
3694
+ if (Array.isArray(branches)) return branches.length > 0 && branches.every((b) => isRecordLike(b) && hasNameField(b, field));
3695
+ const properties = json["properties"];
3696
+ return isRecordLike(properties) && Object.prototype.hasOwnProperty.call(properties, field);
3697
+ }
3698
+ /**
3699
+ * Declare the kinds of a package. The keys are the kind names. The result is
3700
+ * what `ctx.records.declare` sends to the engine and what `ctx.records.kind`
3701
+ * types its handle from.
3702
+ */
3703
+ function defineRecordKinds(specs) {
3704
+ const out = {};
3705
+ for (const [name, spec] of Object.entries(specs)) {
3706
+ const secretPaths = collectZodSecretPaths(spec.schema);
3707
+ const nameField = spec.entry?.nameField ?? "name";
3708
+ const fields = bodyFieldsOf(spec.schema);
3709
+ if (spec.entry !== void 0 && !hasNameField(fields, nameField)) throw new DeclarationRefusedError(`kind "${name}": an entry kind's schema needs a "${nameField}" field`);
3710
+ const parsed = RecordKindDeclarationSchema.parse({
3711
+ database: spec.database,
3712
+ class: spec.class,
3713
+ writeTrigger: spec.writeTrigger,
3714
+ device: spec.device,
3715
+ at: spec.at,
3716
+ indexes: spec.indexes === void 0 ? void 0 : [...spec.indexes],
3717
+ retention: spec.retention,
3718
+ deviceRemoval: spec.deviceRemoval,
3719
+ maxDataBytes: spec.maxDataBytes,
3720
+ secretPaths: [...secretPaths],
3721
+ secretArrayKeys: spec.secretArrayKeys === void 0 ? void 0 : { ...spec.secretArrayKeys },
3722
+ adoptsFrom: spec.adoptsFrom,
3723
+ transactFamily: spec.transactFamily,
3724
+ entry: spec.entry === void 0 ? void 0 : {
3725
+ title: spec.entry.title,
3726
+ nameField,
3727
+ fields
3728
+ }
3729
+ });
3730
+ assertValidDeclaration(name, parsed);
3731
+ out[name] = {
3732
+ name,
3733
+ schema: spec.schema,
3734
+ declaration: parsed
3735
+ };
3736
+ }
3737
+ return out;
3738
+ }
3739
+ /** The wire form of a package's kinds: name -> declaration. */
3740
+ function declarationsOf(kinds) {
3741
+ return Object.fromEntries(Object.entries(kinds).map(([name, kind]) => [name, kind.declaration]));
3742
+ }
3743
+ //#endregion
3744
+ //#region src/records/records-access.ts
3745
+ function isRecord$1(value) {
3746
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3747
+ }
3748
+ /** Run a transport call and give a wire failure its typed class back. */
3749
+ async function call(fn) {
3750
+ try {
3751
+ return await fn();
3752
+ } catch (err) {
3753
+ throw asRecordsError(err);
3754
+ }
3755
+ }
3756
+ function zodSummary(error) {
3757
+ return error.issues.slice(0, 5).map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
3758
+ }
3759
+ function toRow(view, data) {
3760
+ return {
3761
+ id: view.id,
3762
+ deviceId: view.deviceId,
3763
+ at: view.at,
3764
+ expiresAt: view.expiresAt,
3765
+ rev: view.rev,
3766
+ updatedAt: view.updatedAt,
3767
+ data
3768
+ };
3769
+ }
3770
+ var KindHandle = class {
3771
+ def;
3772
+ o;
3773
+ name;
3774
+ decl;
3775
+ constructor(def, o) {
3776
+ this.def = def;
3777
+ this.o = o;
3778
+ this.name = def.name;
3779
+ this.decl = def.declaration;
3780
+ }
3781
+ get hasSecrets() {
3782
+ return this.decl.secretPaths.length > 0;
3783
+ }
3784
+ requireSecrets() {
3785
+ if (this.o.secrets === null) throw new RecordSecretUnavailableError(`kind "${this.name}" has secret fields and this process has no keychain door`);
3786
+ return this.o.secrets;
3787
+ }
3788
+ /** Read the body as the schema's type. The engine already redacted the secrets. */
3789
+ typed(view) {
3790
+ return toRow(view, view.data);
3791
+ }
3792
+ /**
3793
+ * Classify and store the secret leaves of a body about to be written. The
3794
+ * keychain is written FIRST (a failure throws before any row is touched), and
3795
+ * what each ref held before is remembered: when the row write is then refused
3796
+ * (a stale `ifRev`, too large, a unique index) `rollback` puts the previous
3797
+ * values back, so a refused write never destroys the secret that was stored.
3798
+ */
3799
+ async storeSecrets(id, body, mode) {
3800
+ if (!this.hasSecrets) return {
3801
+ body,
3802
+ rollback: async () => {}
3803
+ };
3804
+ const secrets = this.requireSecrets();
3805
+ const writes = [];
3806
+ const prepared = mapSecretLeaves(body, this.decl.secretPaths, this.decl.secretArrayKeys, (leaf) => {
3807
+ const intent = classifySecretWrite(leaf.value);
3808
+ if (intent.kind === "clear") return REMOVE_LEAF;
3809
+ if (intent.kind === "keep") {
3810
+ if (mode === "put") return REDACTED_SECRET;
3811
+ if (leaf.value === null) return null;
3812
+ return leaf.concrete.includes("[") ? REDACTED_SECRET : REMOVE_LEAF;
3813
+ }
3814
+ const ref = recordSecretRef(this.o.owner, this.name, id, leaf.concrete);
3815
+ writes.push({
3816
+ ref,
3817
+ value: intent.value
3818
+ });
3819
+ return makeSecretMarker(ref);
3820
+ });
3821
+ const done = [];
3822
+ const rollback = async () => {
3823
+ for (const { ref, previous } of done) try {
3824
+ if (previous === void 0) await secrets.delete([ref]);
3825
+ else await secrets.put(ref, previous);
3826
+ } catch (err) {
3827
+ this.o.logger?.warn("records: could not restore a keychain value after a refused write", { meta: {
3828
+ kind: this.name,
3829
+ error: err instanceof Error ? err.message : "unknown"
3830
+ } });
3831
+ }
3832
+ };
3833
+ for (const write of writes) try {
3834
+ const before = (await secrets.resolve([write.ref]))[write.ref];
3835
+ const previous = before?.kind === "value" ? before.value : void 0;
3836
+ await secrets.put(write.ref, write.value);
3837
+ done.push({
3838
+ ref: write.ref,
3839
+ previous
3840
+ });
3841
+ } catch (err) {
3842
+ await rollback();
3843
+ throw new RecordSecretUnavailableError(`cannot store a secret of ${this.name}/${id}: ${err instanceof Error ? err.message : "the keychain refused"}. Unlock the keychain (System -> Secrets) and save again`);
3844
+ }
3845
+ return {
3846
+ body: prepared,
3847
+ rollback
3848
+ };
3849
+ }
3850
+ async releaseRefs(refs) {
3851
+ if (refs.length === 0 || this.o.secrets === null) return;
3852
+ try {
3853
+ await this.o.secrets.delete(refs);
3854
+ } catch (err) {
3855
+ this.o.logger?.warn("records: could not remove released keychain values", { meta: {
3856
+ kind: this.name,
3857
+ count: refs.length,
3858
+ error: err instanceof Error ? err.message : "unknown"
3859
+ } });
3860
+ }
3861
+ }
3862
+ validate(data, id) {
3863
+ const shaped = this.hasSecrets ? mapSecretLeaves(data, this.decl.secretPaths, this.decl.secretArrayKeys, (leaf) => {
3864
+ const intent = classifySecretWrite(leaf.value);
3865
+ if (intent.kind === "clear") return REMOVE_LEAF;
3866
+ return intent.kind === "keep" ? REDACTED_SECRET : leaf.value;
3867
+ }) : data;
3868
+ const parsed = this.def.schema.safeParse(shaped);
3869
+ if (!parsed.success) throw new InvalidRecordError(`${this.name}/${id}: ${zodSummary(parsed.error)}`);
3870
+ if (!isRecord$1(parsed.data)) throw new InvalidRecordError(`${this.name}/${id}: the body must be an object`);
3871
+ return parsed.data;
3872
+ }
3873
+ async get(id) {
3874
+ const view = await call(() => this.o.transport.get({
3875
+ kind: this.name,
3876
+ id
3877
+ }));
3878
+ return view === null ? null : this.typed(view);
3879
+ }
3880
+ async getMany(ids) {
3881
+ if (ids.length === 0) return [];
3882
+ return (await call(() => this.o.transport.getMany({
3883
+ kind: this.name,
3884
+ ids: [...ids]
3885
+ }))).map((v) => this.typed(v));
3886
+ }
3887
+ async getResolved(id) {
3888
+ const row = await this.get(id);
3889
+ if (row === null) return null;
3890
+ return (await this.resolveRows([row]))[0] ?? row;
3891
+ }
3892
+ async resolveRows(rows) {
3893
+ if (!this.hasSecrets || rows.length === 0) return rows;
3894
+ const secrets = this.requireSecrets();
3895
+ const refsById = await call(() => this.o.transport.secretRefs({
3896
+ kind: this.name,
3897
+ ids: rows.map((r) => r.id)
3898
+ }));
3899
+ const refs = Object.values(refsById).flatMap((byPath) => Object.values(byPath));
3900
+ if (refs.length === 0) return rows;
3901
+ const answers = await secrets.resolve(refs);
3902
+ return rows.map((row) => {
3903
+ const byPath = refsById[row.id] ?? {};
3904
+ const resolved = mapSecretLeaves(row.data, this.decl.secretPaths, this.decl.secretArrayKeys, (leaf) => {
3905
+ const ref = byPath[leaf.concrete];
3906
+ if (ref === void 0) return leaf.value;
3907
+ const answer = answers[ref];
3908
+ if (answer?.kind === "value") return answer.value;
3909
+ const why = answer?.kind === "unavailable" ? answer.reason : answer?.kind ?? "no answer";
3910
+ throw new RecordSecretUnavailableError(`the secret "${leaf.concrete}" of ${this.name}/${row.id} cannot be served (${why})`);
3911
+ });
3912
+ return {
3913
+ ...row,
3914
+ data: resolved
3915
+ };
3916
+ });
3917
+ }
3918
+ async put(input, opts = {}) {
3919
+ const checked = this.validate(input.data, input.id);
3920
+ const { body, rollback } = await this.storeSecrets(input.id, checked, "put");
3921
+ const result = await call(() => this.o.transport.put({
3922
+ kind: this.name,
3923
+ record: {
3924
+ ...input,
3925
+ data: toBody(body)
3926
+ },
3927
+ ...opts.ifRev === void 0 ? {} : { ifRev: opts.ifRev }
3928
+ })).catch(async (err) => {
3929
+ await rollback();
3930
+ throw err;
3931
+ });
3932
+ await this.releaseRefs(result.releasedRefs);
3933
+ return { rev: result.rev };
3934
+ }
3935
+ async putMany(inputs) {
3936
+ if (inputs.length === 0) return { count: 0 };
3937
+ const prepared = [];
3938
+ const rollbacks = [];
3939
+ try {
3940
+ for (const input of inputs) {
3941
+ const checked = this.validate(input.data, input.id);
3942
+ const { body, rollback } = await this.storeSecrets(input.id, checked, "put");
3943
+ rollbacks.push(rollback);
3944
+ prepared.push({
3945
+ ...input,
3946
+ data: toBody(body)
3947
+ });
3948
+ }
3949
+ } catch (err) {
3950
+ for (const rollback of rollbacks) await rollback();
3951
+ throw err;
3952
+ }
3953
+ const result = await call(() => this.o.transport.putMany({
3954
+ kind: this.name,
3955
+ records: prepared
3956
+ })).catch(async (err) => {
3957
+ for (const rollback of rollbacks) await rollback();
3958
+ throw err;
3959
+ });
3960
+ await this.releaseRefs(result.releasedRefs);
3961
+ return { count: result.count };
3962
+ }
3963
+ async patch(id, partial, opts = {}) {
3964
+ const { body, rollback } = await this.storeSecrets(id, partial, "patch");
3965
+ const result = await call(() => this.o.transport.patch({
3966
+ kind: this.name,
3967
+ id,
3968
+ data: toBody(body),
3969
+ ...opts.at === void 0 ? {} : { at: opts.at },
3970
+ ...opts.expiresAt === void 0 ? {} : { expiresAt: opts.expiresAt },
3971
+ ...opts.ifRev === void 0 ? {} : { ifRev: opts.ifRev }
3972
+ })).catch(async (err) => {
3973
+ await rollback();
3974
+ throw err;
3975
+ });
3976
+ await this.releaseRefs(result.releasedRefs);
3977
+ return { rev: result.rev };
3978
+ }
3979
+ async delete(id) {
3980
+ const result = await call(() => this.o.transport.delete({
3981
+ kind: this.name,
3982
+ id
3983
+ }));
3984
+ await this.releaseRefs(result.secretRefs);
3985
+ return result.deleted;
3986
+ }
3987
+ async deleteMany(ids) {
3988
+ if (ids.length === 0) return 0;
3989
+ const result = await call(() => this.o.transport.deleteMany({
3990
+ kind: this.name,
3991
+ ids: [...ids]
3992
+ }));
3993
+ await this.releaseRefs(result.secretRefs);
3994
+ return result.deleted;
3995
+ }
3996
+ async query(q, opts = {}) {
3997
+ const result = await call(() => this.o.transport.query({
3998
+ ...q,
3999
+ kind: this.name,
4000
+ limit: q.limit ?? 100
4001
+ }));
4002
+ const rows = result.records.map((v) => this.typed(v));
4003
+ return {
4004
+ records: opts.resolveSecrets === true ? await this.resolveRows(rows) : rows,
4005
+ nextCursor: result.nextCursor
4006
+ };
4007
+ }
4008
+ async count(q) {
4009
+ return (await call(() => this.o.transport.count({
4010
+ ...q,
4011
+ kind: this.name
4012
+ }))).count;
4013
+ }
4014
+ async histogram(q) {
4015
+ return (await call(() => this.o.transport.histogram({
4016
+ ...q,
4017
+ kind: this.name
4018
+ }))).buckets;
4019
+ }
4020
+ async aggregate(q) {
4021
+ return (await call(() => this.o.transport.aggregate({
4022
+ ...q,
4023
+ kind: this.name
4024
+ }))).rows;
4025
+ }
4026
+ async deleteWhere(q) {
4027
+ const result = await call(() => this.o.transport.deleteWhere({
4028
+ ...q,
4029
+ kind: this.name
4030
+ }));
4031
+ await this.releaseRefs(result.secretRefs);
4032
+ return result.deleted;
4033
+ }
4034
+ async allocateId() {
4035
+ return (await call(() => this.o.transport.allocateId({ kind: this.name }))).id;
4036
+ }
4037
+ };
4038
+ function toBody(value) {
4039
+ if (!isRecord$1(value)) throw new InvalidRecordError("the record body must be an object");
4040
+ return value;
4041
+ }
4042
+ /** Build the owner's records handle. */
4043
+ function createRecordsAccess(options) {
4044
+ const handles = /* @__PURE__ */ new WeakMap();
4045
+ const delegates = /* @__PURE__ */ new Map();
4046
+ return {
4047
+ owner: options.owner,
4048
+ forOwner: options.transportForOwner === void 0 ? null : (other) => {
4049
+ const existing = delegates.get(other);
4050
+ if (existing !== void 0) return existing;
4051
+ const build = options.transportForOwner;
4052
+ if (build === void 0) throw new Error("forOwner: no delegate transport");
4053
+ const delegate = createRecordsAccess({
4054
+ owner: other,
4055
+ transport: build(other),
4056
+ secrets: options.secrets?.forOwner?.(other) ?? null,
4057
+ ...options.logger === void 0 ? {} : { logger: options.logger }
4058
+ });
4059
+ delegates.set(other, delegate);
4060
+ return delegate;
4061
+ },
4062
+ async declare(kinds) {
4063
+ const result = await call(() => options.transport.declareKinds({ kinds: { ...declarationsOf(kinds) } }));
4064
+ const pending = Object.entries(result.kinds).filter((entry) => entry[1].adoptionPending !== null);
4065
+ if (pending.length > 0) throw new AdoptionPendingError(`${pending.map(([name, r]) => r.adoptionPending === null ? name : `${name} (legacy table "${r.adoptionPending.legacyTable}" holds ${r.adoptionPending.legacyRows} rows)`).join(", ")}. Stop the addon and run scripts/hub/records-adopt.ts --copy --apply before starting this build`);
4066
+ return result.kinds;
4067
+ },
4068
+ kind(definition) {
4069
+ const existing = handles.get(definition);
4070
+ if (existing !== void 0) return existing;
4071
+ const handle = new KindHandle(definition, options);
4072
+ handles.set(definition, handle);
4073
+ return handle;
4074
+ },
4075
+ async deleteDevice(deviceId, opts = {}) {
4076
+ const result = await call(() => options.transport.deleteDevice({
4077
+ deviceId,
4078
+ ...opts.kinds === void 0 ? {} : { kinds: [...opts.kinds] }
4079
+ }));
4080
+ if (result.secretRefs.length > 0 && options.secrets !== null) try {
4081
+ await options.secrets.delete(result.secretRefs);
4082
+ } catch (err) {
4083
+ options.logger?.warn("records: could not remove released keychain values", { meta: {
4084
+ count: result.secretRefs.length,
4085
+ error: err instanceof Error ? err.message : "unknown"
4086
+ } });
4087
+ }
4088
+ return result.deleted;
4089
+ }
4090
+ };
4091
+ }
4092
+ //#endregion
4093
+ //#region src/records/entry-kind.ts
4094
+ /**
4095
+ * Entry kinds (D881): every list of user-created entries (notification
4096
+ * targets, brokers, LLM profiles) is ONE record kind with an id, a name and a
4097
+ * kind-specific body, and the admin UI lists/adds/edits/deletes all of them
4098
+ * through the `record-entries` capability with password fields derived from
4099
+ * the schema (`.meta({ secret: true })`).
4100
+ */
4101
+ /** The body of a plain entry: a name and the fields the kind adds. */
4102
+ function entryBody(shape) {
4103
+ return z.object({
4104
+ name: z.string().min(1),
4105
+ ...shape
4106
+ });
4107
+ }
4108
+ /**
4109
+ * Declare one entry kind. An entry is configuration: never trimmed by the
4110
+ * engine, never aged, belonging to no device.
4111
+ */
4112
+ function defineEntryKind(name, spec) {
4113
+ const defined = defineRecordKinds({ [name]: {
4114
+ schema: spec.schema,
4115
+ class: "config",
4116
+ writeTrigger: spec.writeTrigger ?? "an operator adds or edits an entry in the entries UI",
4117
+ retention: { none: "an entry goes only when the operator deletes it" },
4118
+ ...spec.database === void 0 ? {} : { database: spec.database },
4119
+ ...spec.indexes === void 0 ? {} : { indexes: spec.indexes },
4120
+ ...spec.secretArrayKeys === void 0 ? {} : { secretArrayKeys: spec.secretArrayKeys },
4121
+ ...spec.adoptsFrom === void 0 ? {} : { adoptsFrom: spec.adoptsFrom },
4122
+ entry: {
4123
+ title: spec.title,
4124
+ ...spec.nameField === void 0 ? {} : { nameField: spec.nameField }
4125
+ }
4126
+ } })[name];
4127
+ if (defined === void 0) throw new DeclarationRefusedError(`entry kind "${name}" was not built`);
4128
+ return defined;
4129
+ }
4130
+ //#endregion
4131
+ //#region src/records/settings-brokers-adopts-from.ts
4132
+ /**
4133
+ * Legacy source for broker entry adoption (B2): brokers live in addon-settings
4134
+ * as one row `<addonId>.brokers` whose value is an array until records-adopt
4135
+ * copies them into the entry kind.
4136
+ */
4137
+ var SETTINGS_BROKERS_ADOPTS_PREFIX = "@settings-brokers/";
4138
+ /** The `adoptsFrom` value for an addon's broker entry kind. */
4139
+ function settingsBrokersAdoptsFrom(addonId) {
4140
+ return `${SETTINGS_BROKERS_ADOPTS_PREFIX}${addonId}`;
4141
+ }
4142
+ /** When non-null, `from` names an addon-settings brokers blob, not a SQL table. */
4143
+ function parseSettingsBrokersAdoptsFrom(from) {
4144
+ if (!from.startsWith("@settings-brokers/")) return null;
4145
+ const addonId = from.slice(18);
4146
+ return addonId.length > 0 ? addonId : null;
4147
+ }
4148
+ //#endregion
4149
+ //#region src/records/settings-array-adopts-from.ts
4150
+ /**
4151
+ * Legacy source for entry adoption (B3): a list stored under addon-settings
4152
+ * `<addonId>.<key>` until records-adopt copies rows into the entry kind.
4153
+ */
4154
+ var SETTINGS_ARRAY_ADOPTS_PREFIX = "@settings-array/";
4155
+ /** The `adoptsFrom` value for an addon-settings array field. */
4156
+ function settingsArrayAdoptsFrom(addonId, settingsKey) {
4157
+ return `${SETTINGS_ARRAY_ADOPTS_PREFIX}${addonId}/${settingsKey}`;
4158
+ }
4159
+ /** When non-null, `from` names an addon-settings array blob, not a SQL table. */
4160
+ function parseSettingsArrayAdoptsFrom(from) {
4161
+ if (!from.startsWith("@settings-array/")) return null;
4162
+ const rest = from.slice(16);
4163
+ const slash = rest.indexOf("/");
4164
+ if (slash <= 0 || slash >= rest.length - 1) return null;
4165
+ const addonId = rest.slice(0, slash);
4166
+ const settingsKey = rest.slice(slash + 1);
4167
+ if (addonId.length === 0 || settingsKey.length === 0) return null;
4168
+ return {
4169
+ addonId,
4170
+ settingsKey
4171
+ };
4172
+ }
4173
+ //#endregion
4174
+ //#region src/records/in-memory-records.ts
4175
+ /**
4176
+ * In-memory `RecordsAccess` for specs. Kinds are declared by the caller.
4177
+ * Lives in `@camstack/types` so a spec does not import another package's source.
4178
+ */
4179
+ function isRecord(value) {
4180
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4181
+ }
4182
+ function markersOf(decl, body) {
4183
+ const out = /* @__PURE__ */ new Map();
4184
+ mapSecretLeaves(body, decl.secretPaths, decl.secretArrayKeys, (leaf) => {
4185
+ if (isSecretMarker(leaf.value)) out.set(leaf.concrete, leaf.value.$secret);
4186
+ return leaf.value;
4187
+ });
4188
+ return out;
4189
+ }
4190
+ function makeSpecKeychain(owner) {
4191
+ const values = /* @__PURE__ */ new Map();
4192
+ return { access: {
4193
+ owner,
4194
+ ref: (scope, fieldPath) => buildSecretRef({
4195
+ owner,
4196
+ scope,
4197
+ fieldPath
4198
+ }),
4199
+ resolve: async (refs) => {
4200
+ const out = {};
4201
+ for (const ref of refs) {
4202
+ const value = values.get(ref);
4203
+ out[ref] = value === void 0 ? { kind: "missing" } : {
4204
+ kind: "value",
4205
+ value,
4206
+ version: 1
4207
+ };
4208
+ }
4209
+ return out;
4210
+ },
4211
+ put: async (ref, value) => {
4212
+ values.set(ref, value);
4213
+ return 1;
4214
+ },
4215
+ delete: async (refs) => {
4216
+ let deleted = 0;
4217
+ for (const ref of refs) if (values.delete(ref)) deleted += 1;
4218
+ return deleted;
4219
+ },
4220
+ state: async () => ({ state: "ready" }),
4221
+ onChange: () => () => void 0,
4222
+ forOwner: null
4223
+ } };
4224
+ }
4225
+ function makeInMemoryRecords(owner = "spec") {
4226
+ const decls = /* @__PURE__ */ new Map();
4227
+ const tables = /* @__PURE__ */ new Map();
4228
+ let clock = 1;
4229
+ let writesFail = false;
4230
+ let readsFail = false;
4231
+ const table = (kind) => {
4232
+ let t = tables.get(kind);
4233
+ if (t === void 0) {
4234
+ t = /* @__PURE__ */ new Map();
4235
+ tables.set(kind, t);
4236
+ }
4237
+ return t;
4238
+ };
4239
+ const declOf = (kind) => {
4240
+ const decl = decls.get(kind);
4241
+ if (decl === void 0) throw new Error(`kind "${kind}" is not declared`);
4242
+ return decl;
4243
+ };
4244
+ const redact = (decl, body) => {
4245
+ if (decl.secretPaths.length === 0) return body;
4246
+ const out = mapSecretLeaves(body, decl.secretPaths, decl.secretArrayKeys, (leaf) => leaf.value === null ? null : REDACTED_SECRET);
4247
+ return isRecord(out) ? out : body;
4248
+ };
4249
+ const view = (kind, row) => ({
4250
+ id: row.id,
4251
+ deviceId: null,
4252
+ at: row.at,
4253
+ expiresAt: null,
4254
+ rev: row.rev,
4255
+ updatedAt: row.updatedAt,
4256
+ data: redact(declOf(kind), row.data)
4257
+ });
4258
+ const enforce = (kind, id, body, stored) => {
4259
+ const decl = declOf(kind);
4260
+ if (decl.secretPaths.length === 0) return {
4261
+ body,
4262
+ released: []
4263
+ };
4264
+ const before = stored === null ? /* @__PURE__ */ new Map() : markersOf(decl, stored);
4265
+ const next = mapSecretLeaves(body, decl.secretPaths, decl.secretArrayKeys, (leaf) => {
4266
+ const expected = recordSecretRef(owner, kind, id, leaf.concrete);
4267
+ if (isSecretMarker(leaf.value)) {
4268
+ if (leaf.value.$secret !== expected) throw new Error("foreign secret marker");
4269
+ return leaf.value;
4270
+ }
4271
+ if (leaf.value === "__camstack_redacted__") {
4272
+ const keep = before.get(leaf.concrete);
4273
+ return keep === void 0 ? REMOVE_LEAF : {
4274
+ $secret: keep,
4275
+ v: 1
4276
+ };
4277
+ }
4278
+ if (leaf.value === null || leaf.value === void 0) return REMOVE_LEAF;
4279
+ throw new Error(`${kind}/${id}: a secret field takes a keychain marker, never a value`);
4280
+ });
4281
+ if (!isRecord(next)) throw new Error("the body must be an object");
4282
+ const after = markersOf(decl, next);
4283
+ return {
4284
+ body: next,
4285
+ released: [...before.entries()].filter(([p, ref]) => after.get(p) !== ref).map(([, r]) => r)
4286
+ };
4287
+ };
4288
+ const write = (kind, input) => {
4289
+ if (writesFail) throw new Error("records engine unreachable");
4290
+ if (declOf(kind).at === "required" && input.at === void 0) throw new Error(`${kind}/${input.id}: the kind needs "at" on every write`);
4291
+ const prev = table(kind).get(input.id);
4292
+ const { body, released } = enforce(kind, input.id, input.data, prev?.data ?? null);
4293
+ const rev = (prev?.rev ?? 0) + 1;
4294
+ clock += 1;
4295
+ table(kind).set(input.id, {
4296
+ id: input.id,
4297
+ at: input.at ?? null,
4298
+ rev,
4299
+ updatedAt: clock,
4300
+ data: body
4301
+ });
4302
+ return {
4303
+ rev,
4304
+ released
4305
+ };
4306
+ };
4307
+ const unimplemented = (op) => {
4308
+ throw new Error(`the fake records transport does not implement ${op}`);
4309
+ };
4310
+ return {
4311
+ records: createRecordsAccess({
4312
+ owner,
4313
+ transport: {
4314
+ declareKinds: async ({ kinds }) => {
4315
+ const out = {};
4316
+ let n = 0;
4317
+ for (const [name, decl] of Object.entries(kinds)) {
4318
+ decls.set(name, decl);
4319
+ n += 1;
4320
+ out[name] = {
4321
+ kindId: n,
4322
+ state: "created",
4323
+ createdIndexes: decl.indexes.map((i) => i.name),
4324
+ adoptionPending: null
4325
+ };
4326
+ }
4327
+ return { kinds: out };
4328
+ },
4329
+ get: async ({ kind, id }) => {
4330
+ if (readsFail) throw new Error("records engine unreachable");
4331
+ const row = table(kind).get(id);
4332
+ return row === void 0 ? null : view(kind, row);
4333
+ },
4334
+ getMany: async ({ kind, ids }) => ids.flatMap((id) => {
4335
+ const row = table(kind).get(id);
4336
+ return row === void 0 ? [] : [view(kind, row)];
4337
+ }),
4338
+ secretRefs: async ({ kind, ids }) => {
4339
+ const decl = declOf(kind);
4340
+ const out = {};
4341
+ for (const id of ids) {
4342
+ const row = table(kind).get(id);
4343
+ if (row !== void 0) out[id] = Object.fromEntries(markersOf(decl, row.data));
4344
+ }
4345
+ return out;
4346
+ },
4347
+ put: async ({ kind, record, ifRev }) => {
4348
+ if (ifRev !== void 0 && (table(kind).get(record.id)?.rev ?? 0) !== ifRev) throw new Error("stale ifRev");
4349
+ const { rev, released } = write(kind, record);
4350
+ return {
4351
+ rev,
4352
+ releasedRefs: released
4353
+ };
4354
+ },
4355
+ putMany: async ({ kind, records }) => {
4356
+ const released = [];
4357
+ for (const record of records) released.push(...write(kind, record).released);
4358
+ return {
4359
+ count: records.length,
4360
+ releasedRefs: released
4361
+ };
4362
+ },
4363
+ patch: async () => unimplemented("patch"),
4364
+ delete: async ({ kind, id }) => {
4365
+ if (writesFail) throw new Error("records engine unreachable");
4366
+ const row = table(kind).get(id);
4367
+ if (row === void 0) return {
4368
+ deleted: false,
4369
+ secretRefs: []
4370
+ };
4371
+ table(kind).delete(id);
4372
+ return {
4373
+ deleted: true,
4374
+ secretRefs: [...markersOf(declOf(kind), row.data).values()]
4375
+ };
4376
+ },
4377
+ deleteMany: async ({ kind, ids }) => {
4378
+ let deleted = 0;
4379
+ const refs = [];
4380
+ for (const id of ids) {
4381
+ const row = table(kind).get(id);
4382
+ if (row === void 0) continue;
4383
+ table(kind).delete(id);
4384
+ deleted += 1;
4385
+ refs.push(...markersOf(declOf(kind), row.data).values());
4386
+ }
4387
+ return {
4388
+ deleted,
4389
+ secretRefs: refs
4390
+ };
4391
+ },
4392
+ query: async (q) => {
4393
+ if (readsFail) throw new Error("records engine unreachable");
4394
+ const decl = declOf(q.kind);
4395
+ const asked = Object.keys(q.where ?? {});
4396
+ if (asked.length > 0) {
4397
+ if (!decl.indexes.some((index) => {
4398
+ const leading = new Set(index.fields.slice(0, asked.length));
4399
+ return asked.length <= index.fields.length && asked.every((f) => leading.has(f));
4400
+ })) throw new Error(`${q.kind}: no declared index serves [${asked.join(", ")}]`);
4401
+ }
4402
+ let rows = [...table(q.kind).values()];
4403
+ for (const [field, wanted] of Object.entries(q.where ?? {})) rows = rows.filter((r) => r.data[field] === wanted);
4404
+ const byAt = q.order === "at" || q.order === void 0 && decl.at === "required";
4405
+ rows.sort((a, b) => byAt ? (a.at ?? 0) - (b.at ?? 0) : a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
4406
+ if (q.desc === true) rows.reverse();
4407
+ const start = q.cursor === void 0 ? 0 : Number(q.cursor);
4408
+ const page = rows.slice(start, start + q.limit);
4409
+ const more = start + q.limit < rows.length;
4410
+ return {
4411
+ records: page.map((r) => view(q.kind, r)),
4412
+ nextCursor: more ? String(start + q.limit) : null
4413
+ };
4414
+ },
4415
+ count: async ({ kind }) => ({ count: table(kind).size }),
4416
+ histogram: async () => unimplemented("histogram"),
4417
+ aggregate: async () => unimplemented("aggregate"),
4418
+ deleteWhere: async () => unimplemented("deleteWhere"),
4419
+ deleteDevice: async () => unimplemented("deleteDevice"),
4420
+ allocateId: async () => unimplemented("allocateId")
4421
+ },
4422
+ secrets: makeSpecKeychain(owner).access
4423
+ }),
4424
+ tables,
4425
+ failWrites: (on) => {
4426
+ writesFail = on;
4427
+ },
4428
+ failReads: (on) => {
4429
+ readsFail = on;
4430
+ },
4431
+ seed: (kind, row) => {
4432
+ table(kind).set(row.id, {
4433
+ id: row.id,
4434
+ at: row.at ?? null,
4435
+ rev: 1,
4436
+ updatedAt: 1,
4437
+ data: row.data
4438
+ });
4439
+ }
4440
+ };
4441
+ }
4442
+ //#endregion
3125
4443
  //#region src/capabilities/schemas/streaming-shared.ts
3126
4444
  /** Shared Zod schemas used across streaming capabilities. */
3127
4445
  var CamProfileSchema = z.enum([
@@ -4281,6 +5599,30 @@ function describeCustomActions(catalog) {
4281
5599
  return out;
4282
5600
  }
4283
5601
  //#endregion
5602
+ //#region src/capabilities/caller-stamp.ts
5603
+ /**
5604
+ * Every cap whose provider reads a `callerAddonId` in its input (the keychain's
5605
+ * owner check, device-history's `not-owner`, records' owner).
5606
+ *
5607
+ * The stamp is set ONLY by the transport (`stampCallerAddonId`, or stated by a
5608
+ * hub in-process caller). The generated HTTP/tRPC mount parses input with
5609
+ * `.loose()`, so without this a session could add the key itself and act as
5610
+ * another addon. The mount strips it for these caps.
5611
+ */
5612
+ var CALLER_STAMPED_CAPABILITIES = [
5613
+ "keychain",
5614
+ "device-history",
5615
+ "records",
5616
+ "integrations",
5617
+ "device-manager"
5618
+ ];
5619
+ /** A copy of `input` without the caller stamp. Anything that is not a plain object passes through. */
5620
+ function withoutCallerStamp(input) {
5621
+ if (input === null || typeof input !== "object" || Array.isArray(input)) return input;
5622
+ if (!Object.prototype.hasOwnProperty.call(input, "callerAddonId")) return input;
5623
+ return Object.fromEntries(Object.entries(input).filter(([key]) => key !== "callerAddonId"));
5624
+ }
5625
+ //#endregion
4284
5626
  //#region src/device/children-batch-max.ts
4285
5627
  /**
4286
5628
  * Most parents one `getChildrenBatch` may name.
@@ -4537,94 +5879,6 @@ var RUNTIME_DEFAULTS = {
4537
5879
  "auth.tokenExpiry": "30d"
4538
5880
  };
4539
5881
  //#endregion
4540
- //#region src/device/zod-secret.ts
4541
- /**
4542
- * Secret declaration on a Zod config schema (D783).
4543
- *
4544
- * A field is a secret because its schema SAYS so — `.meta({ secret: true })`,
4545
- * spelled {@link SECRET_META} — never because its key looks like a credential.
4546
- * It is the Zod twin of `secret: true` / `type: 'password'` on a config-UI
4547
- * field (`isSecretConfigField`), and every consumer that treats secrets
4548
- * specially reads it: the settings form (`zodEntriesToConfigUI`), the paths a
4549
- * device advertises at `registerDevice` (`secretConfigPaths`, which the
4550
- * non-admin redaction withholds at any depth), and the keychain later.
4551
- *
4552
- * Zod keeps `.meta()` in `z.globalRegistry`, which lives on `globalThis`, so a
4553
- * declaration made by an addon's own copy of zod is visible here.
4554
- */
4555
- /**
4556
- * `{ secret: true }` — the one spelling of "this field holds a credential".
4557
- *
4558
- * Addons write the LITERAL `.meta({ secret: true })` rather than importing
4559
- * this constant: an addon running against an older `@camstack/types` would
4560
- * otherwise call `.meta(undefined)`, which in zod v4 is the metadata GETTER
4561
- * and returns no schema at all.
4562
- */
4563
- var SECRET_META = { secret: true };
4564
- function defOf(schema) {
4565
- return schema._zod?.def ?? {};
4566
- }
4567
- function declaredHere(schema) {
4568
- return z.globalRegistry.get(schema)?.secret === true;
4569
- }
4570
- /** Wrapper kinds whose `innerType` is the field itself. */
4571
- var WRAPPERS = new Set([
4572
- "optional",
4573
- "nullable",
4574
- "default",
4575
- "prefault",
4576
- "catch",
4577
- "readonly",
4578
- "nonoptional"
4579
- ]);
4580
- /**
4581
- * The schema layers that make up ONE field: the schema itself and every
4582
- * wrapper below it (optional / default / nullable / readonly / catch), plus
4583
- * both sides of a pipe (`z.preprocess` puts the real schema on `out`,
4584
- * `.transform` on `in`).
4585
- */
4586
- function layersOf(schema) {
4587
- const out = [];
4588
- const queue = [schema];
4589
- while (queue.length > 0) {
4590
- const s = queue.shift();
4591
- if (!s || out.includes(s)) continue;
4592
- out.push(s);
4593
- const def = defOf(s);
4594
- if (def.type !== void 0 && WRAPPERS.has(def.type) && def.innerType) queue.push(def.innerType);
4595
- if (def.type === "pipe") {
4596
- if (def.in) queue.push(def.in);
4597
- if (def.out) queue.push(def.out);
4598
- }
4599
- }
4600
- return out;
4601
- }
4602
- /** True when any layer of this field declares `.meta({ secret: true })`. */
4603
- function isZodSecret(schema) {
4604
- return layersOf(schema).some(declaredHere);
4605
- }
4606
- /**
4607
- * Every declared secret path in a config schema: dotted keys, `[]` for "each
4608
- * element of this array" (`connection.password`, `rows[].token`). A declared
4609
- * object or array is reported as one path and not descended into — everything
4610
- * under it is secret.
4611
- */
4612
- function collectZodSecretPaths(schema, prefix = "") {
4613
- if (isZodSecret(schema)) return prefix.length > 0 ? [prefix] : [];
4614
- const paths = [];
4615
- for (const layer of layersOf(schema)) {
4616
- const def = defOf(layer);
4617
- if (def.type === "object" && def.shape) for (const [key, child] of Object.entries(def.shape)) paths.push(...collectZodSecretPaths(child, prefix ? `${prefix}.${key}` : key));
4618
- else if (def.type === "array" && def.element) paths.push(...collectZodSecretPaths(def.element, `${prefix}[]`));
4619
- else if (def.type === "union" && def.options) for (const option of def.options) paths.push(...collectZodSecretPaths(option, prefix));
4620
- else if (def.type === "intersection") {
4621
- if (def.left) paths.push(...collectZodSecretPaths(def.left, prefix));
4622
- if (def.right) paths.push(...collectZodSecretPaths(def.right, prefix));
4623
- }
4624
- }
4625
- return [...new Set(paths)];
4626
- }
4627
- //#endregion
4628
5882
  //#region src/device/device-state-handle.ts
4629
5883
  var DEVICE_STATE_EVENT_CATEGORY = "device.state-changed";
4630
5884
  /**
@@ -4871,6 +6125,50 @@ function isSource(x) {
4871
6125
  return typeof x.read === "function" && typeof x.watch === "function";
4872
6126
  }
4873
6127
  //#endregion
6128
+ //#region src/helpers/addon-slice-handle.ts
6129
+ /** Structural bridge: every `AddonApi` client carries `deviceState` (+ optional `live`). */
6130
+ function addonSliceHandleApi(api) {
6131
+ return api;
6132
+ }
6133
+ //#endregion
6134
+ //#region src/helpers/trpc-leaf.ts
6135
+ function isTrpcProcedureLeaf(value) {
6136
+ if (typeof value !== "object" || value === null) return false;
6137
+ const record = value;
6138
+ return (typeof record.query === "function" || typeof record.mutate === "function" || typeof record.subscribe === "function") && !Array.isArray(value);
6139
+ }
6140
+ function readCapRecord(api, capProp) {
6141
+ const cap = Reflect.get(api, capProp);
6142
+ if (typeof cap !== "object" || cap === null || Array.isArray(cap)) return void 0;
6143
+ return cap;
6144
+ }
6145
+ function readTrpcLeaf(api, capProp, method) {
6146
+ const capRecord = readCapRecord(api, capProp);
6147
+ if (!capRecord) throw new Error(`tRPC client has no router '${capProp}'`);
6148
+ const leaf = capRecord[method];
6149
+ if (!isTrpcProcedureLeaf(leaf)) throw new Error(`tRPC client has no '${capProp}.${method}'`);
6150
+ return leaf;
6151
+ }
6152
+ /**
6153
+ * Invoke `api.<capProp>.<method>.{query|mutate|subscribe}(input)`.
6154
+ * `Result` is the generated proxy method's return. The leaf itself is only
6155
+ * `unknown` (the client is a structural bag), so the assertion is the one
6156
+ * boundary between that bag and the typed proxy.
6157
+ */
6158
+ function invokeTrpcLeaf(api, capProp, method, kind, input, push) {
6159
+ const fn = readTrpcLeaf(api, capProp, method);
6160
+ if (kind === "mutation") {
6161
+ if (typeof fn.mutate !== "function") throw new Error(`tRPC '${capProp}.${method}' has no mutate()`);
6162
+ return fn.mutate(input);
6163
+ }
6164
+ if (kind === "subscription") {
6165
+ if (typeof fn.subscribe !== "function") throw new Error(`tRPC '${capProp}.${method}' has no subscribe()`);
6166
+ return fn.subscribe(input, push);
6167
+ }
6168
+ if (typeof fn.query !== "function") throw new Error(`tRPC '${capProp}.${method}' has no query()`);
6169
+ return fn.query(input);
6170
+ }
6171
+ //#endregion
4874
6172
  //#region src/generated/device-proxy.ts
4875
6173
  /**
4876
6174
  * Build a DeviceProxy that pre-binds deviceId + nodeId on every method call
@@ -4888,8 +6186,7 @@ function isSource(x) {
4888
6186
  * field on the returned object.
4889
6187
  */
4890
6188
  function createDeviceProxy(api, binding, opts) {
4891
- const typedApi = api;
4892
- const stateSource = opts?.stateSource ?? createLazyTrpcSource(api);
6189
+ const stateSource = opts?.stateSource ?? createLazyTrpcSource(addonSliceHandleApi(api));
4893
6190
  /** Merge `{deviceId, nodeId?}` into the caller-supplied input. */
4894
6191
  function mergeInput(input, nodeId) {
4895
6192
  const base = typeof input === "object" && input !== null ? input : {};
@@ -4902,20 +6199,8 @@ function createDeviceProxy(api, binding, opts) {
4902
6199
  deviceId: binding.deviceId
4903
6200
  };
4904
6201
  }
4905
- /**
4906
- * Invoke `api.<capProp>.<method>.{query|mutate|subscribe}(merged)`.
4907
- * Returns `any` so the caller-side per-method declaration assigns
4908
- * cleanly into the strongly-typed `InferDeviceProxyCap<...>` shape on
4909
- * the `DeviceProxy` interface — the proxy's contract is enforced by
4910
- * the interface, not the dispatch helper.
4911
- */
4912
6202
  function callLeaf(capProp, method, kind, merged, push) {
4913
- const leaf = typedApi[capProp]?.[method];
4914
- if (!leaf) throw new Error(`DeviceProxy: api has no '${capProp}.${method}'`);
4915
- const fn = leaf;
4916
- if (kind === "mutation") return fn.mutate(merged);
4917
- if (kind === "subscription") return fn.subscribe(merged, push);
4918
- return fn.query(merged);
6203
+ return invokeTrpcLeaf(api, capProp, method, kind, merged, push);
4919
6204
  }
4920
6205
  /**
4921
6206
  * Device-scoped cap dispatch. Looks up the binding entry for `capName`
@@ -6187,4 +7472,4 @@ function sleepCancellable(ms, signal) {
6187
7472
  });
6188
7473
  }
6189
7474
  //#endregion
6190
- export { resolveCapMount as $, normalizeAddonInitResult as $t, HF_BASE_URL as A, isSecretClear as An, makeSourceBrokerId as At, deviceCustomAction as B, isSecretConfigField as Bn, registerKnownSecret as Bt, createLazyTrpcSource as C, WELL_KNOWN_TAB_MAP as Cn, ProfileSlotSchema as Ct, collectZodSecretPaths as D, resolveHydratedFieldValue as Dn, SubscribeAudioChunksInputSchema as Dt, SECRET_META as E, hydrateSchema as En, StreamSourceSchema as Et, viewerUiCapability as F, toSecretFieldView as Fn, createSecretsAccess as Ft, HISTORY_DEFAULT_MIN_INTERVAL_MS as G, isAudioChunkFormat as Gn, PEER_BYTES_STALL_MS as Gt, DEFAULT_RUNTIME_STATE_DURABILITY as H, AUDIO_CHUNK_FORMATS as Hn, shortSecretRefHash as Ht, DEVICE_CHILDREN_BATCH_MAX as I, REDACTED_SECRET as In, MIN_SCRUBBED_LENGTH as It, event as J, DATAPLANE_SECRET_HEADER as Jt, HISTORY_UNIT_LABELS as K, PEER_BYTES_TICKET_TTL_MS as Kt, customAction as L, collectKeychainStoredKeys as Ln, clearKnownSecrets as Lt, RUNTIME_DEFAULTS as M, isSecretMarker as Mn, selectAssignedProfileSlots as Mt, RawStateResultSchema as N, isSecretMarkerLike as Nn, resolveSecretViewsIn as Nt, isZodSecret as O, SECRET_CLEAR as On, SubscribeAudioChunksResultSchema as Ot, deviceOpsCapability as P, makeSecretMarker as Pn, REVALIDATE_AFTER_MS as Pt, optionalMethod as Q, classifyStoreError as Qt, defineCustomActions as R, collectSecretConfigKeys as Rn, forgetKnownSecret as Rt, createEventBusSliceSource as S, WELL_KNOWN_TABS as Sn, ProfileRtspEntrySchema as St, createSliceHandle as T, collectHydratedFieldValues as Tn, StreamSourceEntrySchema$1 as Tt, DEVICE_SETTINGS_CONTRIBUTION_METHODS as U, audioChunkBytesPerSample as Un, PEER_BYTES_CHUNK_BYTES as Ut, adminUiCapability as V, schemaDeclaresAnyField as Vn, scrubKnownSecrets as Vt, DEVICE_STATUS_METHOD as W, expandAudioChunkToF32le as Wn, PEER_BYTES_MAX_OUTSTANDING as Wt, isDeviceConfigCap as X, DisposerChain as Xt, expandCapMethods as Y, SHARE_VIEW_KINDS as Yt, method as Z, BaseAddon as Zt, readErrorI18n as _, normalizeNodeId as _n, CamStreamKindSchema as _t, asJsonArray as a, collectSecretMarkerRefs as an, MODEL_FORMATS as at, isDeviceScopedCap as b, emitReadiness as bn, DecodedAudioChunkSchema as bt, asString as c, transformSecretWrite as cn, emitDownForOwnedCaps as ct, parseJsonUnknown as d, buildSecretRef as dn, AudioChunkFormatSchema as dt, mergeSecretStatePaths as en, systemMethod as et, hfModelUrl as f, formatSecretScope as fn, AudioStreamPickSchema as ft, ErrorI18nPayloadSchema as g, parseSecretRef as gn, CamProfileSchema as gt, ErrorCodeSchema as h, normalizeSecretOwner as hn, CAM_PROFILE_ORDER as ht, asBoolean as i, KeychainWriteRefusedError as in, toNodeId as it, HF_REPO as j, isSecretFieldView as jn, parseProfileBrokerId as jt, DEFAULT_TOKEN_EXPIRY as k, classifySecretWrite as kn, makeProfileBrokerId as kt, parseJsonArray as l, SECRET_REF_SCHEME as ln, readinessKey as lt, CamstackError as m, isSecretRef as mn, BrokerStatusSchema as mt, sleepCancellable as n, secretTreeFromPaths as nn, nodePin as nt, asJsonObject as o, isSecretRefOwnedBy as on, ReadinessRegistry as ot, BOOT_RECOVERY_BACKOFF_MS as p, globalSecretScope as pn, BrokerStatsSchema as pt, PROVIDER_PIN_FIELD as q, PeerBytesTicketSchema as qt, maskUrlCredentials as r, secretTreeFromSchema as rn, readNodePin as rt, asNumber as s, resolveSecretMarkers as sn, ReadinessTimeoutError as st, sleep as t, parseSecretStatePath as tn, CAP_NODE_PIN_CONTEXT_KEY as tt, parseJsonObject as u, arrayItemFieldPath as un, scopeKey as ut, userError as v, createDurableState as vn, CamStreamResolutionSchema as vt, createMirrorSource as w, collectHydratedFieldEntries as wn, ProfileSlotStatusSchema as wt, createDeviceProxy as x, isEvent as xn, FrameHandleSchema as xt, DEVICE_SCOPED_CAPS as y, createEvent as yn, CameraStreamSchema as yt, describeCustomActions as z, isKeychainStoredField as zn, knownSecretCount as zt };
7475
+ export { optionalMethod as $, PEER_BYTES_CHUNK_BYTES as $n, schemaDeclaresAnyField as $r, REMOVE_LEAF as $t, HF_REPO as A, RECORD_BATCH_MAX_BYTES as An, emitReadiness as Ar, makeProfileBrokerId as At, describeCustomActions as B, RECORD_SECRET_COLLECTION_PREFIX as Bn, SECRET_CLEAR as Br, settingsBrokersAdoptsFrom as Bt, addonSliceHandleApi as C, RecordsError as Cn, globalSecretScope as Cr, ProfileRtspEntrySchema as Ct, createSliceHandle as D, asRecordsError as Dn, normalizeNodeId as Dr, StreamSourceSchema as Dt, createMirrorSource as E, UnknownRecordKindError as En, parseSecretRef as Er, StreamSourceEntrySchema$1 as Et, DEVICE_CHILDREN_BATCH_MAX as F, RECORD_ID_MAX_LENGTH as Fn, collectHydratedFieldValues as Fr, SETTINGS_ARRAY_ADOPTS_PREFIX as Ft, DEVICE_STATUS_METHOD as G, createSecretsAccess as Gn, isSecretMarkerLike as Gr, RecordFieldPathSchema as Gt, adminUiCapability as H, RECORD_SWEEP_INTERVAL_MS as Hn, isSecretClear as Hr, entryBody as Ht, CALLER_STAMPED_CAPABILITIES as I, RECORD_MAX_DATA_BYTES as In, dehydrateConfigField as Ir, parseSettingsArrayAdoptsFrom as It, PROVIDER_PIN_FIELD as J, forgetKnownSecret as Jn, REDACTED_SECRET as Jr, RecordKindNameSchema as Jt, HISTORY_DEFAULT_MIN_INTERVAL_MS as K, MIN_SCRUBBED_LENGTH as Kn, makeSecretMarker as Kr, RecordIndexSchema as Kt, withoutCallerStamp as L, RECORD_MAX_INDEXES as Ln, dehydrateSchema as Lr, settingsArrayAdoptsFrom as Lt, RawStateResultSchema as M, RECORD_DATABASES as Mn, WELL_KNOWN_TABS as Mr, parseProfileBrokerId as Mt, deviceOpsCapability as N, RECORD_DEFAULT_MAX_DATA_BYTES as Nn, WELL_KNOWN_TAB_MAP as Nr, selectAssignedProfileSlots as Nt, DEFAULT_TOKEN_EXPIRY as O, recordsErrorFromMessage as On, createDurableState as Or, SubscribeAudioChunksInputSchema as Ot, viewerUiCapability as P, RECORD_DELETE_BATCH as Pn, collectHydratedFieldEntries as Pr, makeInMemoryRecords as Pt, method as Q, shortSecretRefHash as Qn, isSecretConfigField as Qr, defineRecordKinds as Qt, customAction as R, RECORD_MAX_INDEX_FIELDS as Rn, hydrateSchema as Rr, SETTINGS_BROKERS_ADOPTS_PREFIX as Rt, invokeTrpcLeaf as S, RecordUniqueViolationError as Sn, formatSecretScope as Sr, FrameHandleSchema as St, createLazyTrpcSource as T, UnindexedFilterError as Tn, normalizeSecretOwner as Tr, ProfileSlotStatusSchema as Tt, DEFAULT_RUNTIME_STATE_DURABILITY as U, resolveSecretViewsIn as Un, isSecretFieldView as Ur, createRecordsAccess as Ut, deviceCustomAction as V, RECORD_SETTINGS_MAX_ROWS as Vn, classifySecretWrite as Vr, defineEntryKind as Vt, DEVICE_SETTINGS_CONTRIBUTION_METHODS as W, REVALIDATE_AFTER_MS as Wn, isSecretMarker as Wr, EntryDescriptorSchema as Wt, expandCapMethods as X, registerKnownSecret as Xn, collectSecretConfigKeys as Xr, assertValidDeclaration as Xt, event as Y, knownSecretCount as Yn, collectKeychainStoredKeys as Yr, RecordRetentionSchema as Yt, isDeviceConfigCap as Z, scrubKnownSecrets as Zn, isKeychainStoredField as Zr, declarationsOf as Zt, readErrorI18n as _, PlaintextSecretError as _n, resolveSecretMarkers as _r, CamProfileSchema as _t, asJsonArray as a, recordSecretRef as an, SHARE_VIEW_KINDS as ar, toNodeId as at, isDeviceScopedCap as b, RecordSecretUnavailableError as bn, arrayItemFieldPath as br, CameraStreamSchema as bt, asString as c, collectZodSecretPaths as cn, classifyStoreError as cr, ReadinessTimeoutError as ct, parseJsonUnknown as d, BatchTooLargeError as dn, parseSecretStatePath as dr, scopeKey as dt, AUDIO_CHUNK_FORMATS as ei, collectSecretLeaves as en, PEER_BYTES_MAX_OUTSTANDING as er, resolveCapMount as et, hfModelUrl as f, DeclarationRefusedError as fn, secretTreeFromPaths as fr, AudioChunkFormatSchema as ft, ErrorI18nPayloadSchema as g, NoCallerError as gn, isSecretRefOwnedBy as gr, CAM_PROFILE_ORDER as gt, ErrorCodeSchema as h, InvalidRecordError as hn, collectSecretMarkerRefs as hr, BrokerStatusSchema as ht, asBoolean as i, recordSecretCollection as in, DATAPLANE_SECRET_HEADER as ir, readNodePin as it, RUNTIME_DEFAULTS as j, RECORD_CLASSES as jn, isEvent as jr, makeSourceBrokerId as jt, HF_BASE_URL as k, RECORD_BATCH_MAX as kn, createEvent as kr, SubscribeAudioChunksResultSchema as kt, parseJsonArray as l, isZodSecret as ln, normalizeAddonInitResult as lr, emitDownForOwnedCaps as lt, CamstackError as m, ForeignSecretMarkerError as mn, KeychainWriteRefusedError as mr, BrokerStatsSchema as mt, sleepCancellable as n, expandAudioChunkToF32le as ni, parseSecretPath as nn, PEER_BYTES_TICKET_TTL_MS as nr, CAP_NODE_PIN_CONTEXT_KEY as nt, asJsonObject as o, secretArrayPrefixes as on, DisposerChain as or, MODEL_FORMATS as ot, BOOT_RECOVERY_BACKOFF_MS as p, FilterRequiredError as pn, secretTreeFromSchema as pr, AudioStreamPickSchema as pt, HISTORY_UNIT_LABELS as q, clearKnownSecrets as qn, toSecretFieldView as qr, RecordKindDeclarationSchema as qt, maskUrlCredentials as r, isAudioChunkFormat as ri, recordArrayItemPath as rn, PeerBytesTicketSchema as rr, nodePin as rt, asNumber as s, SECRET_META as sn, BaseAddon as sr, ReadinessRegistry as st, sleep as t, audioChunkBytesPerSample as ti, mapSecretLeaves as tn, PEER_BYTES_STALL_MS as tr, systemMethod as tt, parseJsonObject as u, AdoptionPendingError as un, mergeSecretStatePaths as ur, readinessKey as ut, userError as v, RECORDS_ERROR_CODES as vn, transformSecretWrite as vr, CamStreamKindSchema as vt, createEventBusSliceSource as w, RevConflictError as wn, isSecretRef as wr, ProfileSlotSchema as wt, createDeviceProxy as x, RecordTooLargeError as xn, buildSecretRef as xr, DecodedAudioChunkSchema as xt, DEVICE_SCOPED_CAPS as y, RecordNotFoundError as yn, SECRET_REF_SCHEME as yr, CamStreamResolutionSchema as yt, defineCustomActions as z, RECORD_QUERY_MAX as zn, resolveHydratedFieldValue as zr, parseSettingsBrokersAdoptsFrom as zt };