@camstack/types 1.2.379 → 1.2.380

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.
@@ -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$5(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$5(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$5(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$5(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$5(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$4(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$4(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$4(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$4(value) && value["$secretClear"] === true;
265
265
  }
266
266
  function isSecretFieldView(value) {
267
- return isRecord$2(value) && value["set"] === true && isSecretMarkerLike(value);
267
+ return isRecord$4(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
@@ -1018,7 +1018,7 @@ var KeychainWriteRefusedError = class extends Error {
1018
1018
  }
1019
1019
  };
1020
1020
  var KEEP = { kind: "keep" };
1021
- function isRecord$1(value) {
1021
+ function isRecord$3(value) {
1022
1022
  return typeof value === "object" && value !== null && !Array.isArray(value);
1023
1023
  }
1024
1024
  function defaultMintId() {
@@ -1031,7 +1031,7 @@ function collectSecretMarkerRefs(value, out = []) {
1031
1031
  return out;
1032
1032
  }
1033
1033
  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);
1034
+ else if (isRecord$3(value)) for (const child of Object.values(value)) collectSecretMarkerRefs(child, out);
1035
1035
  return out;
1036
1036
  }
1037
1037
  async function storedValueEquals(secrets, marker, candidate) {
@@ -1086,7 +1086,7 @@ function rowId(row, idKey) {
1086
1086
  return null;
1087
1087
  }
1088
1088
  async function writeArray(ctx, node, incoming, stored, fieldPath) {
1089
- const storedRows = Array.isArray(stored) ? stored.filter(isRecord$1) : [];
1089
+ const storedRows = Array.isArray(stored) ? stored.filter(isRecord$3) : [];
1090
1090
  if (!Array.isArray(incoming)) {
1091
1091
  ctx.deletes.push(...collectSecretMarkerRefs(storedRows));
1092
1092
  return {
@@ -1102,7 +1102,7 @@ async function writeArray(ctx, node, incoming, stored, fieldPath) {
1102
1102
  const kept = /* @__PURE__ */ new Set();
1103
1103
  const rows = [];
1104
1104
  for (const row of incoming) {
1105
- if (!isRecord$1(row)) {
1105
+ if (!isRecord$3(row)) {
1106
1106
  rows.push(row);
1107
1107
  continue;
1108
1108
  }
@@ -1127,7 +1127,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
1127
1127
  case "leaf": return writeLeaf(ctx, incoming, stored, fieldPath);
1128
1128
  case "array": return writeArray(ctx, node, incoming, stored, fieldPath);
1129
1129
  case "object": {
1130
- if (!isRecord$1(incoming)) {
1130
+ if (!isRecord$3(incoming)) {
1131
1131
  if (incoming === void 0) return KEEP;
1132
1132
  ctx.deletes.push(...collectSecretMarkerRefs(stored));
1133
1133
  return {
@@ -1135,7 +1135,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
1135
1135
  value: incoming
1136
1136
  };
1137
1137
  }
1138
- const storedObj = isRecord$1(stored) ? stored : {};
1138
+ const storedObj = isRecord$3(stored) ? stored : {};
1139
1139
  return {
1140
1140
  kind: "value",
1141
1141
  value: await writeMembers(ctx, node.children, incoming, storedObj, (m) => `${fieldPath}.${m}`)
@@ -1258,7 +1258,7 @@ async function resolveSecretMarkers(value, secrets, options = {}) {
1258
1258
  value: items
1259
1259
  };
1260
1260
  }
1261
- if (isRecord$1(v)) {
1261
+ if (isRecord$3(v)) {
1262
1262
  const out = {};
1263
1263
  for (const [k, child] of Object.entries(v)) {
1264
1264
  const s = substitute(child);
@@ -1292,7 +1292,7 @@ var SecretOverwriteRefusedError = class extends Error {
1292
1292
  this.name = "SecretOverwriteRefusedError";
1293
1293
  }
1294
1294
  };
1295
- function isRecord(value) {
1295
+ function isRecord$2(value) {
1296
1296
  return typeof value === "object" && value !== null && !Array.isArray(value);
1297
1297
  }
1298
1298
  function resolvedValue(pass, marker) {
@@ -1321,7 +1321,7 @@ function inArray(pass, incoming, stored) {
1321
1321
  return incoming.map((item, index) => {
1322
1322
  const twin = stored[index];
1323
1323
  if (isSecretMarker(twin)) return typeof item === "string" && item === resolvedValue(pass, twin) ? twin : item;
1324
- if (isRecord(item) && isRecord(twin)) return inArrayRow(pass, item, twin);
1324
+ if (isRecord$2(item) && isRecord$2(twin)) return inArrayRow(pass, item, twin);
1325
1325
  if (Array.isArray(item) && Array.isArray(twin)) return inArray(pass, item, twin);
1326
1326
  return item;
1327
1327
  });
@@ -1332,7 +1332,7 @@ function inArrayRow(pass, incoming, stored) {
1332
1332
  const twin = stored[key];
1333
1333
  if (isSecretMarker(twin)) {
1334
1334
  if (typeof value === "string" && value === resolvedValue(pass, twin)) out[key] = twin;
1335
- } else if (isRecord(value) && isRecord(twin)) out[key] = inArrayRow(pass, value, twin);
1335
+ } else if (isRecord$2(value) && isRecord$2(twin)) out[key] = inArrayRow(pass, value, twin);
1336
1336
  else if (Array.isArray(value) && Array.isArray(twin)) out[key] = inArray(pass, value, twin);
1337
1337
  }
1338
1338
  return out;
@@ -1340,7 +1340,7 @@ function inArrayRow(pass, incoming, stored) {
1340
1340
  async function walk(pass, incoming, stored) {
1341
1341
  if (isSecretMarker(stored)) return atMarker(pass, incoming, stored);
1342
1342
  if (Array.isArray(incoming) && Array.isArray(stored)) return inArray(pass, incoming, stored);
1343
- if (!isRecord(incoming) || !isRecord(stored)) return incoming;
1343
+ if (!isRecord$2(incoming) || !isRecord$2(stored)) return incoming;
1344
1344
  const out = { ...incoming };
1345
1345
  for (const [key, value] of Object.entries(incoming)) out[key] = await walk(pass, value, stored[key]);
1346
1346
  return out;
@@ -1371,7 +1371,7 @@ async function restoreUnchangedSecrets(input) {
1371
1371
  function isJsonEqual(a, b) {
1372
1372
  if (Object.is(a, b)) return true;
1373
1373
  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)) {
1374
+ if (isRecord$2(a) && isRecord$2(b)) {
1375
1375
  const keys = Object.keys(a);
1376
1376
  if (keys.length !== Object.keys(b).length) return false;
1377
1377
  return keys.every((k) => Object.prototype.hasOwnProperty.call(b, k) && isJsonEqual(a[k], b[k]));
@@ -1395,7 +1395,7 @@ function markerKeysOf(blob, owner) {
1395
1395
  }
1396
1396
  function nodeFromStored(value, owner) {
1397
1397
  if (isSecretMarker(value)) return isSecretRefOwnedBy(value.$secret, owner) ? { kind: "leaf" } : null;
1398
- if (!isRecord(value)) return null;
1398
+ if (!isRecord$2(value)) return null;
1399
1399
  const children = /* @__PURE__ */ new Map();
1400
1400
  for (const [key, child] of Object.entries(value)) {
1401
1401
  const node = nodeFromStored(child, owner);
@@ -3122,183 +3122,1158 @@ async function resolveSecretViewsIn(args, secrets) {
3122
3122
  return swap(args).value;
3123
3123
  }
3124
3124
  //#endregion
3125
- //#region src/capabilities/schemas/streaming-shared.ts
3126
- /** Shared Zod schemas used across streaming capabilities. */
3127
- var CamProfileSchema = zod.z.enum([
3128
- "high",
3129
- "mid",
3130
- "low"
3131
- ]);
3132
- /** Canonical ordering. Hard-coded; never sorted. */
3133
- var CAM_PROFILE_ORDER = [
3134
- "high",
3135
- "mid",
3136
- "low"
3125
+ //#region src/records/constants.ts
3126
+ /** Limits and names of `ctx.records` (D881). One authority; the engine and the facade read it. */
3127
+ /** The files a kind may live in. `history` is device-history's (D850), never records. */
3128
+ var RECORD_DATABASES = ["settings", "events"];
3129
+ /** The classes of a kind: the `@durable` vocabulary, one authority (replaces the annotation). */
3130
+ var RECORD_CLASSES = [
3131
+ "config",
3132
+ "ledger",
3133
+ "audit",
3134
+ "mirror",
3135
+ "ephemeral"
3137
3136
  ];
3137
+ var RECORD_DEFAULT_MAX_DATA_BYTES = 64 * 1024;
3138
+ var RECORD_MAX_DATA_BYTES = 1024 * 1024;
3139
+ var RECORD_ID_MAX_LENGTH = 256;
3140
+ var RECORD_BATCH_MAX = 1e3;
3141
+ var RECORD_BATCH_MAX_BYTES = 4 * 1024 * 1024;
3142
+ var RECORD_QUERY_MAX = 1e3;
3143
+ /** Rows one DELETE statement removes before the serving thread yields. */
3144
+ var RECORD_DELETE_BATCH = 5e3;
3145
+ /** A kind in the `settings` file may not bound itself above this (D447: high volume is `events`). */
3146
+ var RECORD_SETTINGS_MAX_ROWS = 5e4;
3147
+ var RECORD_MAX_INDEXES = 8;
3148
+ var RECORD_MAX_INDEX_FIELDS = 4;
3149
+ /** The engine's TTL sweep cadence. */
3150
+ var RECORD_SWEEP_INTERVAL_MS = 10 * 6e4;
3151
+ /** The `Column`-free proof prefix: a ref collection for a kind's secret fields. */
3152
+ var RECORD_SECRET_COLLECTION_PREFIX = "records:";
3153
+ //#endregion
3154
+ //#region src/records/errors.ts
3138
3155
  /**
3139
- * Which rung a per-camera consumer listens on: an explicit profile, or `auto`.
3156
+ * The named failures of `ctx.records` (D881).
3140
3157
  *
3141
- * `auto` is a REAL value, not an absent one — it means "resolve it by the rule
3142
- * that consumer owns". It lives beside `CamProfile` because a rung is the only
3143
- * operator-facing way to name a stream: a cam-stream id is broker-internal and
3144
- * moves when a slot is reassigned, so a stored id silently stops meaning what
3145
- * the operator picked. Today's one user is the audio analyser, whose rule is
3146
- * "the lowest AVAILABLE native rung" (D537).
3158
+ * A records call crosses a worker thread, a UDS channel and a tRPC router, and
3159
+ * an error class does not survive any of them - only its message does. So
3160
+ * every message STARTS with a stable code, `records/<code>: <detail>`, and
3161
+ * {@link recordsErrorFromMessage} rebuilds the typed class on the caller's side.
3162
+ * A failed read is never `[]` or `undefined`: it throws one of these.
3147
3163
  */
3148
- var AudioStreamPickSchema = zod.z.union([CamProfileSchema, zod.z.literal("auto")]);
3149
- var CamStreamKindSchema = zod.z.enum([
3150
- "pull-rtsp",
3151
- "pull-rtmp",
3152
- "pull-http",
3153
- "pull-flv",
3154
- "pull-rfc4571",
3155
- "push-annexb",
3156
- "derived"
3157
- ]);
3158
- var CamStreamResolutionSchema = zod.z.object({
3159
- width: zod.z.number().int().positive(),
3160
- height: zod.z.number().int().positive()
3161
- });
3162
- var CameraStreamSchema = zod.z.object({
3163
- /** Stable, provider-assigned id unique within the (deviceId) scope. */
3164
- camStreamId: zod.z.string().min(1),
3165
- deviceId: zod.z.number().int().nonnegative(),
3166
- kind: CamStreamKindSchema,
3167
- /** Required for pull-* kinds. Ignored for push-annexb. */
3168
- url: zod.z.string().optional(),
3169
- codec: zod.z.string().optional(),
3170
- resolution: CamStreamResolutionSchema.optional(),
3171
- fps: zod.z.number().positive().optional(),
3172
- /** Human label surfaced in the Admin UI "Camera Stream" dropdown. */
3173
- label: zod.z.string().optional(),
3174
- /**
3175
- * Device-level features the publisher advertised (e.g. `battery-operated`).
3176
- * The broker, snapshot orchestrator, and prebuffer manager all consult
3177
- * this list to derive policy — relaxed stall watchdog for battery
3178
- * cams, prebuffer off by default, longer snapshot rate-limit, etc.
3179
- *
3180
- * Single source of truth replacing per-stream flags like the
3181
- * historical `allowStall`: if the publisher knows the camera is
3182
- * battery-powered, every downstream service derives the right policy
3183
- * from this list.
3184
- */
3185
- deviceFeatures: zod.z.array(zod.z.string()).optional(),
3186
- /**
3187
- * Whether this stream participates in the broker's automatic profile
3188
- * assignment (`computeInitialAssignment`). Defaults to `true`. Publishers
3189
- * use `false` when they want a stream to be SELECTABLE in the UI but not
3190
- * picked by default — e.g. Reolink publishes its native Baichuan streams
3191
- * as `autoEligible: true` (the recommended path) and its RTSP / RTMP
3192
- * mirrors as `autoEligible: false` (still pickable per slot, just not
3193
- * the auto choice). Manual `assignProfile` calls remain valid for
3194
- * non-eligible streams.
3195
- */
3196
- autoEligible: zod.z.boolean().optional(),
3197
- /**
3198
- * The profile slot the PUBLISHER says this stream is: `low` for a stream
3199
- * whose only sensible role is the low-bandwidth one, `high` for a main
3200
- * stream. Consulted by the broker's automatic ranking
3201
- * (`rankInitialAssignment`) BEFORE the pixel-count heuristic, and only there:
3202
- * an operator's manual assignment still wins, and an absent hint is the
3203
- * pixel-ranked default every camera had before this field existed.
3204
- *
3205
- * Why it exists: a camera with ONE stream ranked to `mid` — the slot no
3206
- * storage class is written for on its own (`recordings` is high|mid,
3207
- * `recordingsLow` is low) and the one profile scrub does not read. The robot
3208
- * camera's single 720p relay is a `low` in every respect except the slot the
3209
- * heuristic put it in.
3210
- */
3211
- profileHint: CamProfileSchema.optional(),
3212
- /**
3213
- * Transport-specific opaque metadata. The broker passes it through to
3214
- * the source reader without inspecting it. Currently used by
3215
- * `pull-rfc4571` streams to carry the upstream SDP (so the reader can
3216
- * route RTP packets to the right depacketizer without an in-band
3217
- * DESCRIBE phase). Other kinds typically leave it undefined.
3218
- */
3219
- metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
3220
- });
3221
- var ProfileSlotStatusSchema = zod.z.enum([
3222
- "unassigned",
3223
- "idle",
3224
- "connecting",
3225
- "streaming",
3226
- "error"
3227
- ]);
3228
- var ProfileSlotSchema = zod.z.object({
3229
- deviceId: zod.z.number().int().nonnegative(),
3230
- profile: CamProfileSchema,
3231
- /** Broker id the rest of the system addresses: `${deviceId}/${profile}`. */
3232
- brokerId: zod.z.string(),
3233
- /** `null` when the profile is unassigned. */
3234
- sourceCamStreamId: zod.z.string().nullable(),
3235
- status: ProfileSlotStatusSchema,
3236
- resolution: CamStreamResolutionSchema.optional(),
3237
- codec: zod.z.string().optional(),
3238
- preBufferSec: zod.z.number().nonnegative().optional(),
3239
- errorMessage: zod.z.string().optional()
3240
- });
3241
- /** The canonical consumer-facing broker id for a device profile. */
3242
- function makeProfileBrokerId(deviceId, profile) {
3243
- return `${deviceId}/${profile}`;
3164
+ /** Every code a records failure carries. */
3165
+ var RECORDS_ERROR_CODES = [
3166
+ "rev-conflict",
3167
+ "too-large",
3168
+ "unindexed-filter",
3169
+ "filter-required",
3170
+ "unknown-kind",
3171
+ "not-found",
3172
+ "unique-violation",
3173
+ "plaintext-secret",
3174
+ "foreign-marker",
3175
+ "secret-unavailable",
3176
+ "invalid-record",
3177
+ "declaration-refused",
3178
+ "adoption-pending",
3179
+ "no-caller",
3180
+ "batch-too-large"
3181
+ ];
3182
+ var PREFIX = "records/";
3183
+ /** The base of every records failure. `detail` is the human part of the message. */
3184
+ var RecordsError = class extends Error {
3185
+ code;
3186
+ detail;
3187
+ constructor(code, detail) {
3188
+ super(`${PREFIX}${code}: ${detail}`);
3189
+ this.name = "RecordsError";
3190
+ this.code = code;
3191
+ this.detail = detail;
3192
+ }
3193
+ };
3194
+ /** A write guarded by `ifRev` found another revision (or an existing row for `ifRev: 0`). */
3195
+ var RevConflictError = class extends RecordsError {
3196
+ constructor(detail) {
3197
+ super("rev-conflict", detail);
3198
+ this.name = "RevConflictError";
3199
+ }
3200
+ };
3201
+ /** `data` exceeds the kind's `maxDataBytes`. Bytes are never record fields (D613). */
3202
+ var RecordTooLargeError = class extends RecordsError {
3203
+ constructor(detail) {
3204
+ super("too-large", detail);
3205
+ this.name = "RecordTooLargeError";
3206
+ }
3207
+ };
3208
+ /** A filter, order or aggregate names a field no declared index serves. */
3209
+ var UnindexedFilterError = class extends RecordsError {
3210
+ constructor(detail) {
3211
+ super("unindexed-filter", detail);
3212
+ this.name = "UnindexedFilterError";
3213
+ }
3214
+ };
3215
+ /** A bulk delete with no predicate at all. */
3216
+ var FilterRequiredError = class extends RecordsError {
3217
+ constructor(detail) {
3218
+ super("filter-required", detail);
3219
+ this.name = "FilterRequiredError";
3220
+ }
3221
+ };
3222
+ /** The caller declared no such kind (another addon's kind is indistinguishable from none). */
3223
+ var UnknownRecordKindError = class extends RecordsError {
3224
+ constructor(detail) {
3225
+ super("unknown-kind", detail);
3226
+ this.name = "UnknownRecordKindError";
3227
+ }
3228
+ };
3229
+ var RecordNotFoundError = class extends RecordsError {
3230
+ constructor(detail) {
3231
+ super("not-found", detail);
3232
+ this.name = "RecordNotFoundError";
3233
+ }
3234
+ };
3235
+ /** A unique index refused the write. */
3236
+ var RecordUniqueViolationError = class extends RecordsError {
3237
+ constructor(detail) {
3238
+ super("unique-violation", detail);
3239
+ this.name = "RecordUniqueViolationError";
3240
+ }
3241
+ };
3242
+ /** A secret field held a plain string where only a keychain marker may be stored. */
3243
+ var PlaintextSecretError = class extends RecordsError {
3244
+ constructor(detail) {
3245
+ super("plaintext-secret", detail);
3246
+ this.name = "PlaintextSecretError";
3247
+ }
3248
+ };
3249
+ /** A marker whose ref is not the row's own (the D878 rule). */
3250
+ var ForeignSecretMarkerError = class extends RecordsError {
3251
+ constructor(detail) {
3252
+ super("foreign-marker", detail);
3253
+ this.name = "ForeignSecretMarkerError";
3254
+ }
3255
+ };
3256
+ /** The keychain could not store or serve a value: explicit, never an empty string. */
3257
+ var RecordSecretUnavailableError = class extends RecordsError {
3258
+ constructor(detail) {
3259
+ super("secret-unavailable", detail);
3260
+ this.name = "RecordSecretUnavailableError";
3261
+ }
3262
+ };
3263
+ var InvalidRecordError = class extends RecordsError {
3264
+ constructor(detail) {
3265
+ super("invalid-record", detail);
3266
+ this.name = "InvalidRecordError";
3267
+ }
3268
+ };
3269
+ /** A kind declaration the engine refuses (non-additive change, bad shape, wrong file). */
3270
+ var DeclarationRefusedError = class extends RecordsError {
3271
+ constructor(detail) {
3272
+ super("declaration-refused", detail);
3273
+ this.name = "DeclarationRefusedError";
3274
+ }
3275
+ };
3276
+ /** A kind is empty while the legacy table it adopts from still holds rows. */
3277
+ var AdoptionPendingError = class extends RecordsError {
3278
+ constructor(detail) {
3279
+ super("adoption-pending", detail);
3280
+ this.name = "AdoptionPendingError";
3281
+ }
3282
+ };
3283
+ var NoCallerError = class extends RecordsError {
3284
+ constructor(detail) {
3285
+ super("no-caller", detail);
3286
+ this.name = "NoCallerError";
3287
+ }
3288
+ };
3289
+ var BatchTooLargeError = class extends RecordsError {
3290
+ constructor(detail) {
3291
+ super("batch-too-large", detail);
3292
+ this.name = "BatchTooLargeError";
3293
+ }
3294
+ };
3295
+ var FACTORIES = {
3296
+ "rev-conflict": (d) => new RevConflictError(d),
3297
+ "too-large": (d) => new RecordTooLargeError(d),
3298
+ "unindexed-filter": (d) => new UnindexedFilterError(d),
3299
+ "filter-required": (d) => new FilterRequiredError(d),
3300
+ "unknown-kind": (d) => new UnknownRecordKindError(d),
3301
+ "not-found": (d) => new RecordNotFoundError(d),
3302
+ "unique-violation": (d) => new RecordUniqueViolationError(d),
3303
+ "plaintext-secret": (d) => new PlaintextSecretError(d),
3304
+ "foreign-marker": (d) => new ForeignSecretMarkerError(d),
3305
+ "secret-unavailable": (d) => new RecordSecretUnavailableError(d),
3306
+ "invalid-record": (d) => new InvalidRecordError(d),
3307
+ "declaration-refused": (d) => new DeclarationRefusedError(d),
3308
+ "adoption-pending": (d) => new AdoptionPendingError(d),
3309
+ "no-caller": (d) => new NoCallerError(d),
3310
+ "batch-too-large": (d) => new BatchTooLargeError(d)
3311
+ };
3312
+ function isCode(value) {
3313
+ return RECORDS_ERROR_CODES.some((code) => code === value);
3244
3314
  }
3245
3315
  /**
3246
- * The broker id keying a physical SOURCE stream: `${deviceId}/${camStreamId}`.
3247
- * This is the broker's internal source key (`brokerIdFor` in the manager) — a
3248
- * `camStreamId` like `native:main` — as opposed to the public profile alias
3249
- * {@link makeProfileBrokerId}. Used to resolve a source's restream endpoint
3250
- * (e.g. routing a transcode's ffmpeg input through the broker so it rides the
3251
- * single source dial instead of opening a second camera connection).
3316
+ * Rebuild the typed error from a message that crossed a wire; `null` when the
3317
+ * message is not a records failure.
3252
3318
  */
3253
- function makeSourceBrokerId(deviceId, camStreamId) {
3254
- return `${deviceId}/${camStreamId}`;
3319
+ function recordsErrorFromMessage(message) {
3320
+ if (!message.startsWith(PREFIX)) return null;
3321
+ const colon = message.indexOf(": ");
3322
+ if (colon < 0) return null;
3323
+ const code = message.slice(8, colon);
3324
+ if (!isCode(code)) return null;
3325
+ return FACTORIES[code](message.slice(colon + 2));
3326
+ }
3327
+ /** The records failure inside any thrown value (a wrapped tRPC error included), or the value. */
3328
+ function asRecordsError(err) {
3329
+ if (err instanceof RecordsError) return err;
3330
+ if (err instanceof Error) {
3331
+ const typed = recordsErrorFromMessage(err.message);
3332
+ if (typed !== null) return typed;
3333
+ }
3334
+ return err;
3255
3335
  }
3336
+ //#endregion
3337
+ //#region src/device/zod-secret.ts
3256
3338
  /**
3257
- * Inverse of {@link makeProfileBrokerId}. Returns `null` when the string is
3258
- * not a canonical `${deviceId}/${profile}` id — e.g. a broker-internal
3259
- * cam-stream id (`5/native:main`), a derived/adaptive ref, or a malformed
3260
- * value. So a caller can safely distinguish "addresses a public profile"
3261
- * from "addresses something broker-internal".
3339
+ * Secret declaration on a Zod config schema (D783).
3340
+ *
3341
+ * A field is a secret because its schema SAYS so — `.meta({ secret: true })`,
3342
+ * spelled {@link SECRET_META} — never because its key looks like a credential.
3343
+ * It is the Zod twin of `secret: true` / `type: 'password'` on a config-UI
3344
+ * field (`isSecretConfigField`), and every consumer that treats secrets
3345
+ * specially reads it: the settings form (`zodEntriesToConfigUI`), the paths a
3346
+ * device advertises at `registerDevice` (`secretConfigPaths`, which the
3347
+ * non-admin redaction withholds at any depth), and the keychain later.
3348
+ *
3349
+ * Zod keeps `.meta()` in `z.globalRegistry`, which lives on `globalThis`, so a
3350
+ * declaration made by an addon's own copy of zod is visible here.
3262
3351
  */
3263
- function parseProfileBrokerId(brokerId) {
3264
- const slash = brokerId.indexOf("/");
3265
- if (slash <= 0) return null;
3266
- const idPart = brokerId.slice(0, slash);
3267
- const profilePart = brokerId.slice(slash + 1);
3268
- if (!/^\d+$/.test(idPart)) return null;
3269
- const parsed = CamProfileSchema.safeParse(profilePart);
3270
- if (!parsed.success) return null;
3271
- return {
3272
- deviceId: Number(idPart),
3273
- profile: parsed.data
3274
- };
3275
- }
3276
3352
  /**
3277
- * The profile slots worth consuming/recording: ASSIGNED only
3278
- * (`sourceCamStreamId != null`), DEDUPED by physical source so the same
3279
- * camera encoder is never subscribed/recorded twice, ordered high→mid→low.
3280
- * Optionally scoped to one `deviceId`. Pure; never mutates the input.
3353
+ * `{ secret: true }` — the one spelling of "this field holds a credential".
3281
3354
  *
3282
- * Recording `main` and `mid` when both point at the same `sourceCamStreamId`
3283
- * would dial the camera's internal stream twice for no benefit — this is the
3284
- * dedup that prevents that.
3355
+ * Addons write the LITERAL `.meta({ secret: true })` rather than importing
3356
+ * this constant: an addon running against an older `@camstack/types` would
3357
+ * otherwise call `.meta(undefined)`, which in zod v4 is the metadata GETTER
3358
+ * and returns no schema at all.
3285
3359
  */
3286
- function selectAssignedProfileSlots(slots, deviceId) {
3287
- const ordered = [...slots].filter((s) => deviceId === void 0 || s.deviceId === deviceId).toSorted((a, b) => CAM_PROFILE_ORDER.indexOf(a.profile) - CAM_PROFILE_ORDER.indexOf(b.profile));
3288
- const seenSources = /* @__PURE__ */ new Set();
3360
+ var SECRET_META = { secret: true };
3361
+ function defOf(schema) {
3362
+ return schema._zod?.def ?? {};
3363
+ }
3364
+ function declaredHere(schema) {
3365
+ return zod.z.globalRegistry.get(schema)?.secret === true;
3366
+ }
3367
+ /** Wrapper kinds whose `innerType` is the field itself. */
3368
+ var WRAPPERS = new Set([
3369
+ "optional",
3370
+ "nullable",
3371
+ "default",
3372
+ "prefault",
3373
+ "catch",
3374
+ "readonly",
3375
+ "nonoptional"
3376
+ ]);
3377
+ /**
3378
+ * The schema layers that make up ONE field: the schema itself and every
3379
+ * wrapper below it (optional / default / nullable / readonly / catch), plus
3380
+ * both sides of a pipe (`z.preprocess` puts the real schema on `out`,
3381
+ * `.transform` on `in`).
3382
+ */
3383
+ function layersOf(schema) {
3289
3384
  const out = [];
3290
- for (const s of ordered) {
3291
- const src = s.sourceCamStreamId;
3292
- if (src === null) continue;
3293
- if (seenSources.has(src)) continue;
3294
- seenSources.add(src);
3385
+ const queue = [schema];
3386
+ while (queue.length > 0) {
3387
+ const s = queue.shift();
3388
+ if (!s || out.includes(s)) continue;
3295
3389
  out.push(s);
3390
+ const def = defOf(s);
3391
+ if (def.type !== void 0 && WRAPPERS.has(def.type) && def.innerType) queue.push(def.innerType);
3392
+ if (def.type === "pipe") {
3393
+ if (def.in) queue.push(def.in);
3394
+ if (def.out) queue.push(def.out);
3395
+ }
3296
3396
  }
3297
3397
  return out;
3298
3398
  }
3399
+ /** True when any layer of this field declares `.meta({ secret: true })`. */
3400
+ function isZodSecret(schema) {
3401
+ return layersOf(schema).some(declaredHere);
3402
+ }
3299
3403
  /**
3300
- * Zod schema for StreamSourceEntry — the canonical stream descriptor
3301
- * exposed by ICameraDevice.getStreamSources() and consumed by the broker.
3404
+ * Every declared secret path in a config schema: dotted keys, `[]` for "each
3405
+ * element of this array" (`connection.password`, `rows[].token`). A declared
3406
+ * object or array is reported as one path and not descended into — everything
3407
+ * under it is secret.
3408
+ */
3409
+ function collectZodSecretPaths(schema, prefix = "") {
3410
+ if (isZodSecret(schema)) return prefix.length > 0 ? [prefix] : [];
3411
+ const paths = [];
3412
+ for (const layer of layersOf(schema)) {
3413
+ const def = defOf(layer);
3414
+ if (def.type === "object" && def.shape) for (const [key, child] of Object.entries(def.shape)) paths.push(...collectZodSecretPaths(child, prefix ? `${prefix}.${key}` : key));
3415
+ else if (def.type === "array" && def.element) paths.push(...collectZodSecretPaths(def.element, `${prefix}[]`));
3416
+ else if (def.type === "union" && def.options) for (const option of def.options) paths.push(...collectZodSecretPaths(option, prefix));
3417
+ else if (def.type === "intersection") {
3418
+ if (def.left) paths.push(...collectZodSecretPaths(def.left, prefix));
3419
+ if (def.right) paths.push(...collectZodSecretPaths(def.right, prefix));
3420
+ }
3421
+ }
3422
+ return [...new Set(paths)];
3423
+ }
3424
+ //#endregion
3425
+ //#region src/records/secret-paths.ts
3426
+ /**
3427
+ * Secret fields of a record, addressed the way a Zod schema declares them
3428
+ * (`collectZodSecretPaths`): dotted keys, `[]` for "each element of this array"
3429
+ * (`auth.accessToken`, `headers[].value`).
3430
+ *
3431
+ * Array elements are matched by a DECLARED id key (`secretArrayKeys`:
3432
+ * `{ headers: 'name' }`), never by index, so reordering a list keeps every
3433
+ * keychain ref (the same rule as `arrayItemFieldPath`). The concrete path of a
3434
+ * leaf names its element: `headers[X-Api].value`.
3435
+ *
3436
+ * Pure and browser-safe. Nothing here mutates: every transform returns a new value.
3437
+ */
3438
+ /** The array prefixes (declared form, e.g. `headers` or `a.headers`) of a path. */
3439
+ function parseSecretPath(path) {
3440
+ if (path.length === 0) throw new InvalidRecordError("an empty secret path");
3441
+ return path.split(".").map((raw) => {
3442
+ const each = raw.endsWith("[]");
3443
+ const key = each ? raw.slice(0, -2) : raw;
3444
+ if (key.length === 0) throw new InvalidRecordError(`secret path "${path}" has an empty segment`);
3445
+ return {
3446
+ key,
3447
+ each
3448
+ };
3449
+ });
3450
+ }
3451
+ /** The declared array prefixes of `path` that need an id key (`headers`, `a.rows`). */
3452
+ function secretArrayPrefixes(path) {
3453
+ const segments = parseSecretPath(path);
3454
+ const prefixes = [];
3455
+ const walked = [];
3456
+ for (const segment of segments) {
3457
+ walked.push(segment.key);
3458
+ if (segment.each) prefixes.push(walked.join("."));
3459
+ }
3460
+ return prefixes;
3461
+ }
3462
+ function isRecord$1(value) {
3463
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3464
+ }
3465
+ function elementId(element, idKey, declared, prefix) {
3466
+ const id = isRecord$1(element) ? element[idKey] : void 0;
3467
+ 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`);
3468
+ return id;
3469
+ }
3470
+ /**
3471
+ * Visit every secret leaf PRESENT in `data` (an absent branch has nothing to
3472
+ * visit). `replace` returns the new leaf value, or {@link REMOVE_LEAF}; the
3473
+ * result is a new body, `data` is untouched.
3474
+ */
3475
+ var REMOVE_LEAF = Symbol("remove-leaf");
3476
+ function mapAt(node, segments, index, walkedKeys, concretePrefix, declared, arrayKeys, visit) {
3477
+ if (!isRecord$1(node)) return node;
3478
+ const segment = segments[index];
3479
+ if (segment === void 0) return node;
3480
+ if (!Object.prototype.hasOwnProperty.call(node, segment.key)) return node;
3481
+ const child = node[segment.key];
3482
+ const keys = [...walkedKeys, segment.key];
3483
+ const last = index === segments.length - 1;
3484
+ if (segment.each) {
3485
+ if (!Array.isArray(child)) return node;
3486
+ const prefix = keys.join(".");
3487
+ const idKey = arrayKeys[prefix];
3488
+ if (idKey === void 0) throw new InvalidRecordError(`"${declared}": no id key declared for the array "${prefix}"`);
3489
+ const mapped = child.map((element) => {
3490
+ const id = elementId(element, idKey, declared, prefix);
3491
+ const concrete = `${concretePrefix}${concretePrefix.length > 0 ? "." : ""}${segment.key}[${encodeURIComponent(id)}]`;
3492
+ return last ? element : mapAt(element, segments, index + 1, keys, concrete, declared, arrayKeys, visit);
3493
+ });
3494
+ return {
3495
+ ...node,
3496
+ [segment.key]: mapped
3497
+ };
3498
+ }
3499
+ const concrete = `${concretePrefix}${concretePrefix.length > 0 ? "." : ""}${segment.key}`;
3500
+ if (last) {
3501
+ const replacement = visit({
3502
+ declared,
3503
+ concrete,
3504
+ value: child
3505
+ });
3506
+ if (replacement === REMOVE_LEAF) return Object.fromEntries(Object.entries(node).filter(([key]) => key !== segment.key));
3507
+ return {
3508
+ ...node,
3509
+ [segment.key]: replacement
3510
+ };
3511
+ }
3512
+ return {
3513
+ ...node,
3514
+ [segment.key]: mapAt(child, segments, index + 1, keys, concrete, declared, arrayKeys, visit)
3515
+ };
3516
+ }
3517
+ /** Replace/remove every present secret leaf; returns a NEW body. */
3518
+ function mapSecretLeaves(data, paths, arrayKeys, visit) {
3519
+ let current = data;
3520
+ for (const declared of paths) current = mapAt(current, parseSecretPath(declared), 0, [], "", declared, arrayKeys, visit);
3521
+ return current;
3522
+ }
3523
+ /** Every present secret leaf, read-only. */
3524
+ function collectSecretLeaves(data, paths, arrayKeys) {
3525
+ const found = [];
3526
+ mapSecretLeaves(data, paths, arrayKeys, (leaf) => {
3527
+ found.push(leaf);
3528
+ return leaf.value;
3529
+ });
3530
+ return found;
3531
+ }
3532
+ /**
3533
+ * The keychain collection name a kind's secrets live under. Prefixed so a
3534
+ * record's refs never collide with the refs a legacy collection of the same name
3535
+ * already holds during an adoption.
3536
+ */
3537
+ function recordSecretCollection(kind) {
3538
+ return `${RECORD_SECRET_COLLECTION_PREFIX}${kind}`;
3539
+ }
3540
+ /** The ONE ref a row's secret field may carry: the engine and the facade both build it here. */
3541
+ function recordSecretRef(owner, kind, rowId, concretePath) {
3542
+ return buildSecretRef({
3543
+ owner,
3544
+ scope: {
3545
+ kind: "row",
3546
+ collection: recordSecretCollection(kind),
3547
+ rowId
3548
+ },
3549
+ fieldPath: concretePath
3550
+ });
3551
+ }
3552
+ /** A concrete path built from a flat array item, re-exported for adoption tooling. */
3553
+ var recordArrayItemPath = arrayItemFieldPath;
3554
+ //#endregion
3555
+ //#region src/records/record-kind.ts
3556
+ /**
3557
+ * Record kinds (D881): the declaration an addon makes of one kind of fact, the
3558
+ * Zod row schema that describes it, and the helper that turns the two into the
3559
+ * JSON the engine stores.
3560
+ *
3561
+ * A kind is declared ONCE, next to the code that owns it, and the engine's
3562
+ * reconciler creates its indexes - nothing creates DDL at runtime from a write.
3563
+ * Everything the generic machinery needs (secret fields, the entry descriptor)
3564
+ * is DERIVED from the Zod schema: `.meta({ secret: true })` marks a credential,
3565
+ * never a field name (D879).
3566
+ */
3567
+ /** A JSON field path: `trackId`, `auth.accessToken`. Charset-restricted: it is rendered into DDL. */
3568
+ var RecordFieldPathSchema = zod.z.string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,63}(\.[A-Za-z_][A-Za-z0-9_]{0,63}){0,3}$/);
3569
+ var RecordIndexSchema = zod.z.object({
3570
+ name: zod.z.string().regex(/^[a-z][a-z0-9_]{0,31}$/),
3571
+ fields: zod.z.array(RecordFieldPathSchema).min(1).max(4),
3572
+ unique: zod.z.boolean().optional()
3573
+ }).strict();
3574
+ var RecordRetentionSchema = zod.z.union([
3575
+ zod.z.object({
3576
+ ttlMs: zod.z.number().int().positive(),
3577
+ from: zod.z.enum(["at", "write"])
3578
+ }).strict(),
3579
+ zod.z.object({
3580
+ maxRows: zod.z.number().int().positive().optional(),
3581
+ maxRowsPerDevice: zod.z.number().int().positive().optional()
3582
+ }).strict().refine((r) => r.maxRows !== void 0 || r.maxRowsPerDevice !== void 0, { message: "name maxRows, maxRowsPerDevice or both" }),
3583
+ zod.z.object({
3584
+ owner: zod.z.string().min(1),
3585
+ reason: zod.z.string().min(1)
3586
+ }).strict(),
3587
+ zod.z.object({ none: zod.z.string().min(1) }).strict()
3588
+ ]);
3589
+ /** The descriptor a generic entries UI reads (D881 "generic entries"). */
3590
+ var EntryDescriptorSchema = zod.z.object({
3591
+ title: zod.z.string().min(1),
3592
+ /** The record body field shown as the entry's name. */
3593
+ nameField: zod.z.string().min(1),
3594
+ /** JSON Schema of the entry body; `secret: true` marks a password field. */
3595
+ fields: zod.z.record(zod.z.string(), zod.z.unknown())
3596
+ }).strict();
3597
+ /** What crosses the wire and sits in the engine's catalog: JSON only, no Zod. */
3598
+ var RecordKindDeclarationSchema = zod.z.object({
3599
+ database: zod.z.enum(RECORD_DATABASES).default("settings"),
3600
+ class: zod.z.enum(RECORD_CLASSES),
3601
+ writeTrigger: zod.z.string().min(1),
3602
+ device: zod.z.enum([
3603
+ "required",
3604
+ "optional",
3605
+ "none"
3606
+ ]).default("none"),
3607
+ at: zod.z.enum(["required", "none"]).default("none"),
3608
+ indexes: zod.z.array(RecordIndexSchema).max(8).default([]),
3609
+ retention: RecordRetentionSchema,
3610
+ deviceRemoval: zod.z.enum(["delete", "none"]).default("none"),
3611
+ maxDataBytes: zod.z.number().int().positive().max(RECORD_MAX_DATA_BYTES).default(RECORD_DEFAULT_MAX_DATA_BYTES),
3612
+ /** Derived from the Zod schema; never written by hand. */
3613
+ secretPaths: zod.z.array(zod.z.string().min(1)).default([]),
3614
+ /** The id key of each array that carries a secret (`{ headers: 'name' }`). */
3615
+ secretArrayKeys: zod.z.record(zod.z.string(), zod.z.string()).default({}),
3616
+ /** The legacy table this kind adopts from; the boot guard reads it (D853: no migration code). */
3617
+ adoptsFrom: zod.z.string().min(1).optional(),
3618
+ /** Kinds that must agree through `transact` sit in one file under one family name. */
3619
+ transactFamily: zod.z.string().min(1).optional(),
3620
+ entry: EntryDescriptorSchema.optional()
3621
+ }).strict();
3622
+ /** The kind names: lower-case, dash separated, short enough for an index name. */
3623
+ var RecordKindNameSchema = zod.z.string().regex(/^[a-z][a-z0-9-]{0,47}$/);
3624
+ /** Cross-field rules a declaration must satisfy. Throws {@link DeclarationRefusedError}. */
3625
+ function assertValidDeclaration(name, decl) {
3626
+ const refuse = (why) => {
3627
+ throw new DeclarationRefusedError(`kind "${name}": ${why}`);
3628
+ };
3629
+ if (!RecordKindNameSchema.safeParse(name).success) refuse("the name must be lower-case-dashed");
3630
+ const seen = /* @__PURE__ */ new Set();
3631
+ for (const index of decl.indexes) {
3632
+ if (seen.has(index.name)) refuse(`index name "${index.name}" is declared twice`);
3633
+ seen.add(index.name);
3634
+ }
3635
+ const { retention } = decl;
3636
+ const hasSecrets = decl.secretPaths.length > 0;
3637
+ if ("ttlMs" in retention) {
3638
+ if (retention.from === "at" && decl.at !== "required") refuse("a ttl from \"at\" needs at: \"required\"");
3639
+ if (hasSecrets) refuse("a kind with secret fields cannot use engine TTL (its keychain values would be orphaned)");
3640
+ }
3641
+ if ("maxRows" in retention || "maxRowsPerDevice" in retention) {
3642
+ if (retention.maxRowsPerDevice !== void 0 && decl.device !== "required") refuse("maxRowsPerDevice needs device: \"required\"");
3643
+ if (decl.at !== "required") refuse("a row bound trims the oldest \"at\": it needs at: \"required\"");
3644
+ if (hasSecrets) refuse("a kind with secret fields cannot use an engine row bound");
3645
+ const bound = Math.max(retention.maxRows ?? 0, retention.maxRowsPerDevice ?? 0);
3646
+ 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)`);
3647
+ }
3648
+ if (decl.deviceRemoval === "delete" && decl.device === "none") refuse("deviceRemoval: \"delete\" needs a device: \"required\" or \"optional\"");
3649
+ 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`);
3650
+ }
3651
+ function bodyFieldsOf(schema) {
3652
+ return { ...zod.z.toJSONSchema(schema, {
3653
+ unrepresentable: "any",
3654
+ io: "input"
3655
+ }) };
3656
+ }
3657
+ function isRecordLike(value) {
3658
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3659
+ }
3660
+ /** Does every branch of the body schema carry `field`? (A discriminated union has several.) */
3661
+ function hasNameField(json, field) {
3662
+ const branches = json["oneOf"] ?? json["anyOf"];
3663
+ if (Array.isArray(branches)) return branches.length > 0 && branches.every((b) => isRecordLike(b) && hasNameField(b, field));
3664
+ const properties = json["properties"];
3665
+ return isRecordLike(properties) && Object.prototype.hasOwnProperty.call(properties, field);
3666
+ }
3667
+ /**
3668
+ * Declare the kinds of a package. The keys are the kind names. The result is
3669
+ * what `ctx.records.declare` sends to the engine and what `ctx.records.kind`
3670
+ * types its handle from.
3671
+ */
3672
+ function defineRecordKinds(specs) {
3673
+ const out = {};
3674
+ for (const [name, spec] of Object.entries(specs)) {
3675
+ const secretPaths = collectZodSecretPaths(spec.schema);
3676
+ const nameField = spec.entry?.nameField ?? "name";
3677
+ const fields = bodyFieldsOf(spec.schema);
3678
+ if (spec.entry !== void 0 && !hasNameField(fields, nameField)) throw new DeclarationRefusedError(`kind "${name}": an entry kind's schema needs a "${nameField}" field`);
3679
+ const parsed = RecordKindDeclarationSchema.parse({
3680
+ database: spec.database,
3681
+ class: spec.class,
3682
+ writeTrigger: spec.writeTrigger,
3683
+ device: spec.device,
3684
+ at: spec.at,
3685
+ indexes: spec.indexes === void 0 ? void 0 : [...spec.indexes],
3686
+ retention: spec.retention,
3687
+ deviceRemoval: spec.deviceRemoval,
3688
+ maxDataBytes: spec.maxDataBytes,
3689
+ secretPaths: [...secretPaths],
3690
+ secretArrayKeys: spec.secretArrayKeys === void 0 ? void 0 : { ...spec.secretArrayKeys },
3691
+ adoptsFrom: spec.adoptsFrom,
3692
+ transactFamily: spec.transactFamily,
3693
+ entry: spec.entry === void 0 ? void 0 : {
3694
+ title: spec.entry.title,
3695
+ nameField,
3696
+ fields
3697
+ }
3698
+ });
3699
+ assertValidDeclaration(name, parsed);
3700
+ out[name] = {
3701
+ name,
3702
+ schema: spec.schema,
3703
+ declaration: parsed
3704
+ };
3705
+ }
3706
+ return out;
3707
+ }
3708
+ /** The wire form of a package's kinds: name -> declaration. */
3709
+ function declarationsOf(kinds) {
3710
+ return Object.fromEntries(Object.entries(kinds).map(([name, kind]) => [name, kind.declaration]));
3711
+ }
3712
+ //#endregion
3713
+ //#region src/records/records-access.ts
3714
+ function isRecord(value) {
3715
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3716
+ }
3717
+ /** Run a transport call and give a wire failure its typed class back. */
3718
+ async function call(fn) {
3719
+ try {
3720
+ return await fn();
3721
+ } catch (err) {
3722
+ throw asRecordsError(err);
3723
+ }
3724
+ }
3725
+ function zodSummary(error) {
3726
+ return error.issues.slice(0, 5).map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
3727
+ }
3728
+ function toRow(view, data) {
3729
+ return {
3730
+ id: view.id,
3731
+ deviceId: view.deviceId,
3732
+ at: view.at,
3733
+ expiresAt: view.expiresAt,
3734
+ rev: view.rev,
3735
+ updatedAt: view.updatedAt,
3736
+ data
3737
+ };
3738
+ }
3739
+ var KindHandle = class {
3740
+ def;
3741
+ o;
3742
+ name;
3743
+ decl;
3744
+ constructor(def, o) {
3745
+ this.def = def;
3746
+ this.o = o;
3747
+ this.name = def.name;
3748
+ this.decl = def.declaration;
3749
+ }
3750
+ get hasSecrets() {
3751
+ return this.decl.secretPaths.length > 0;
3752
+ }
3753
+ requireSecrets() {
3754
+ if (this.o.secrets === null) throw new RecordSecretUnavailableError(`kind "${this.name}" has secret fields and this process has no keychain door`);
3755
+ return this.o.secrets;
3756
+ }
3757
+ /** Read the body as the schema's type. The engine already redacted the secrets. */
3758
+ typed(view) {
3759
+ return toRow(view, view.data);
3760
+ }
3761
+ /**
3762
+ * Classify and store the secret leaves of a body about to be written. The
3763
+ * keychain is written FIRST (a failure throws before any row is touched), and
3764
+ * what each ref held before is remembered: when the row write is then refused
3765
+ * (a stale `ifRev`, too large, a unique index) `rollback` puts the previous
3766
+ * values back, so a refused write never destroys the secret that was stored.
3767
+ */
3768
+ async storeSecrets(id, body, mode) {
3769
+ if (!this.hasSecrets) return {
3770
+ body,
3771
+ rollback: async () => {}
3772
+ };
3773
+ const secrets = this.requireSecrets();
3774
+ const writes = [];
3775
+ const prepared = mapSecretLeaves(body, this.decl.secretPaths, this.decl.secretArrayKeys, (leaf) => {
3776
+ const intent = classifySecretWrite(leaf.value);
3777
+ if (intent.kind === "clear") return REMOVE_LEAF;
3778
+ if (intent.kind === "keep") {
3779
+ if (mode === "put") return REDACTED_SECRET;
3780
+ if (leaf.value === null) return null;
3781
+ return leaf.concrete.includes("[") ? REDACTED_SECRET : REMOVE_LEAF;
3782
+ }
3783
+ const ref = recordSecretRef(this.o.owner, this.name, id, leaf.concrete);
3784
+ writes.push({
3785
+ ref,
3786
+ value: intent.value
3787
+ });
3788
+ return makeSecretMarker(ref);
3789
+ });
3790
+ const done = [];
3791
+ const rollback = async () => {
3792
+ for (const { ref, previous } of done) try {
3793
+ if (previous === void 0) await secrets.delete([ref]);
3794
+ else await secrets.put(ref, previous);
3795
+ } catch (err) {
3796
+ this.o.logger?.warn("records: could not restore a keychain value after a refused write", { meta: {
3797
+ kind: this.name,
3798
+ error: err instanceof Error ? err.message : "unknown"
3799
+ } });
3800
+ }
3801
+ };
3802
+ for (const write of writes) try {
3803
+ const before = (await secrets.resolve([write.ref]))[write.ref];
3804
+ const previous = before?.kind === "value" ? before.value : void 0;
3805
+ await secrets.put(write.ref, write.value);
3806
+ done.push({
3807
+ ref: write.ref,
3808
+ previous
3809
+ });
3810
+ } catch (err) {
3811
+ await rollback();
3812
+ 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`);
3813
+ }
3814
+ return {
3815
+ body: prepared,
3816
+ rollback
3817
+ };
3818
+ }
3819
+ async releaseRefs(refs) {
3820
+ if (refs.length === 0 || this.o.secrets === null) return;
3821
+ try {
3822
+ await this.o.secrets.delete(refs);
3823
+ } catch (err) {
3824
+ this.o.logger?.warn("records: could not remove released keychain values", { meta: {
3825
+ kind: this.name,
3826
+ count: refs.length,
3827
+ error: err instanceof Error ? err.message : "unknown"
3828
+ } });
3829
+ }
3830
+ }
3831
+ validate(data, id) {
3832
+ const shaped = this.hasSecrets ? mapSecretLeaves(data, this.decl.secretPaths, this.decl.secretArrayKeys, (leaf) => {
3833
+ const intent = classifySecretWrite(leaf.value);
3834
+ if (intent.kind === "clear") return REMOVE_LEAF;
3835
+ return intent.kind === "keep" ? REDACTED_SECRET : leaf.value;
3836
+ }) : data;
3837
+ const parsed = this.def.schema.safeParse(shaped);
3838
+ if (!parsed.success) throw new InvalidRecordError(`${this.name}/${id}: ${zodSummary(parsed.error)}`);
3839
+ if (!isRecord(parsed.data)) throw new InvalidRecordError(`${this.name}/${id}: the body must be an object`);
3840
+ return parsed.data;
3841
+ }
3842
+ async get(id) {
3843
+ const view = await call(() => this.o.transport.get({
3844
+ kind: this.name,
3845
+ id
3846
+ }));
3847
+ return view === null ? null : this.typed(view);
3848
+ }
3849
+ async getMany(ids) {
3850
+ if (ids.length === 0) return [];
3851
+ return (await call(() => this.o.transport.getMany({
3852
+ kind: this.name,
3853
+ ids: [...ids]
3854
+ }))).map((v) => this.typed(v));
3855
+ }
3856
+ async getResolved(id) {
3857
+ const row = await this.get(id);
3858
+ if (row === null) return null;
3859
+ return (await this.resolveRows([row]))[0] ?? row;
3860
+ }
3861
+ async resolveRows(rows) {
3862
+ if (!this.hasSecrets || rows.length === 0) return rows;
3863
+ const secrets = this.requireSecrets();
3864
+ const refsById = await call(() => this.o.transport.secretRefs({
3865
+ kind: this.name,
3866
+ ids: rows.map((r) => r.id)
3867
+ }));
3868
+ const refs = Object.values(refsById).flatMap((byPath) => Object.values(byPath));
3869
+ if (refs.length === 0) return rows;
3870
+ const answers = await secrets.resolve(refs);
3871
+ return rows.map((row) => {
3872
+ const byPath = refsById[row.id] ?? {};
3873
+ const resolved = mapSecretLeaves(row.data, this.decl.secretPaths, this.decl.secretArrayKeys, (leaf) => {
3874
+ const ref = byPath[leaf.concrete];
3875
+ if (ref === void 0) return leaf.value;
3876
+ const answer = answers[ref];
3877
+ if (answer?.kind === "value") return answer.value;
3878
+ const why = answer?.kind === "unavailable" ? answer.reason : answer?.kind ?? "no answer";
3879
+ throw new RecordSecretUnavailableError(`the secret "${leaf.concrete}" of ${this.name}/${row.id} cannot be served (${why})`);
3880
+ });
3881
+ return {
3882
+ ...row,
3883
+ data: resolved
3884
+ };
3885
+ });
3886
+ }
3887
+ async put(input, opts = {}) {
3888
+ const checked = this.validate(input.data, input.id);
3889
+ const { body, rollback } = await this.storeSecrets(input.id, checked, "put");
3890
+ const result = await call(() => this.o.transport.put({
3891
+ kind: this.name,
3892
+ record: {
3893
+ ...input,
3894
+ data: toBody(body)
3895
+ },
3896
+ ...opts.ifRev === void 0 ? {} : { ifRev: opts.ifRev }
3897
+ })).catch(async (err) => {
3898
+ await rollback();
3899
+ throw err;
3900
+ });
3901
+ await this.releaseRefs(result.releasedRefs);
3902
+ return { rev: result.rev };
3903
+ }
3904
+ async putMany(inputs) {
3905
+ if (inputs.length === 0) return { count: 0 };
3906
+ const prepared = [];
3907
+ const rollbacks = [];
3908
+ try {
3909
+ for (const input of inputs) {
3910
+ const checked = this.validate(input.data, input.id);
3911
+ const { body, rollback } = await this.storeSecrets(input.id, checked, "put");
3912
+ rollbacks.push(rollback);
3913
+ prepared.push({
3914
+ ...input,
3915
+ data: toBody(body)
3916
+ });
3917
+ }
3918
+ } catch (err) {
3919
+ for (const rollback of rollbacks) await rollback();
3920
+ throw err;
3921
+ }
3922
+ const result = await call(() => this.o.transport.putMany({
3923
+ kind: this.name,
3924
+ records: prepared
3925
+ })).catch(async (err) => {
3926
+ for (const rollback of rollbacks) await rollback();
3927
+ throw err;
3928
+ });
3929
+ await this.releaseRefs(result.releasedRefs);
3930
+ return { count: result.count };
3931
+ }
3932
+ async patch(id, partial, opts = {}) {
3933
+ const { body, rollback } = await this.storeSecrets(id, partial, "patch");
3934
+ const result = await call(() => this.o.transport.patch({
3935
+ kind: this.name,
3936
+ id,
3937
+ data: toBody(body),
3938
+ ...opts.at === void 0 ? {} : { at: opts.at },
3939
+ ...opts.expiresAt === void 0 ? {} : { expiresAt: opts.expiresAt },
3940
+ ...opts.ifRev === void 0 ? {} : { ifRev: opts.ifRev }
3941
+ })).catch(async (err) => {
3942
+ await rollback();
3943
+ throw err;
3944
+ });
3945
+ await this.releaseRefs(result.releasedRefs);
3946
+ return { rev: result.rev };
3947
+ }
3948
+ async delete(id) {
3949
+ const result = await call(() => this.o.transport.delete({
3950
+ kind: this.name,
3951
+ id
3952
+ }));
3953
+ await this.releaseRefs(result.secretRefs);
3954
+ return result.deleted;
3955
+ }
3956
+ async deleteMany(ids) {
3957
+ if (ids.length === 0) return 0;
3958
+ const result = await call(() => this.o.transport.deleteMany({
3959
+ kind: this.name,
3960
+ ids: [...ids]
3961
+ }));
3962
+ await this.releaseRefs(result.secretRefs);
3963
+ return result.deleted;
3964
+ }
3965
+ async query(q, opts = {}) {
3966
+ const result = await call(() => this.o.transport.query({
3967
+ ...q,
3968
+ kind: this.name,
3969
+ limit: q.limit ?? 100
3970
+ }));
3971
+ const rows = result.records.map((v) => this.typed(v));
3972
+ return {
3973
+ records: opts.resolveSecrets === true ? await this.resolveRows(rows) : rows,
3974
+ nextCursor: result.nextCursor
3975
+ };
3976
+ }
3977
+ async count(q) {
3978
+ return (await call(() => this.o.transport.count({
3979
+ ...q,
3980
+ kind: this.name
3981
+ }))).count;
3982
+ }
3983
+ async histogram(q) {
3984
+ return (await call(() => this.o.transport.histogram({
3985
+ ...q,
3986
+ kind: this.name
3987
+ }))).buckets;
3988
+ }
3989
+ async aggregate(q) {
3990
+ return (await call(() => this.o.transport.aggregate({
3991
+ ...q,
3992
+ kind: this.name
3993
+ }))).rows;
3994
+ }
3995
+ async deleteWhere(q) {
3996
+ const result = await call(() => this.o.transport.deleteWhere({
3997
+ ...q,
3998
+ kind: this.name
3999
+ }));
4000
+ await this.releaseRefs(result.secretRefs);
4001
+ return result.deleted;
4002
+ }
4003
+ async allocateId() {
4004
+ return (await call(() => this.o.transport.allocateId({ kind: this.name }))).id;
4005
+ }
4006
+ };
4007
+ function toBody(value) {
4008
+ if (!isRecord(value)) throw new InvalidRecordError("the record body must be an object");
4009
+ return value;
4010
+ }
4011
+ /** Build the owner's records handle. */
4012
+ function createRecordsAccess(options) {
4013
+ const handles = /* @__PURE__ */ new WeakMap();
4014
+ const delegates = /* @__PURE__ */ new Map();
4015
+ return {
4016
+ owner: options.owner,
4017
+ forOwner: options.transportForOwner === void 0 ? null : (other) => {
4018
+ const existing = delegates.get(other);
4019
+ if (existing !== void 0) return existing;
4020
+ const build = options.transportForOwner;
4021
+ if (build === void 0) throw new Error("forOwner: no delegate transport");
4022
+ const delegate = createRecordsAccess({
4023
+ owner: other,
4024
+ transport: build(other),
4025
+ secrets: options.secrets?.forOwner?.(other) ?? null,
4026
+ ...options.logger === void 0 ? {} : { logger: options.logger }
4027
+ });
4028
+ delegates.set(other, delegate);
4029
+ return delegate;
4030
+ },
4031
+ async declare(kinds) {
4032
+ const result = await call(() => options.transport.declareKinds({ kinds: { ...declarationsOf(kinds) } }));
4033
+ const pending = Object.entries(result.kinds).filter((entry) => entry[1].adoptionPending !== null);
4034
+ 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`);
4035
+ return result.kinds;
4036
+ },
4037
+ kind(definition) {
4038
+ const existing = handles.get(definition);
4039
+ if (existing !== void 0) return existing;
4040
+ const handle = new KindHandle(definition, options);
4041
+ handles.set(definition, handle);
4042
+ return handle;
4043
+ },
4044
+ async deleteDevice(deviceId, opts = {}) {
4045
+ const result = await call(() => options.transport.deleteDevice({
4046
+ deviceId,
4047
+ ...opts.kinds === void 0 ? {} : { kinds: [...opts.kinds] }
4048
+ }));
4049
+ if (result.secretRefs.length > 0 && options.secrets !== null) try {
4050
+ await options.secrets.delete(result.secretRefs);
4051
+ } catch (err) {
4052
+ options.logger?.warn("records: could not remove released keychain values", { meta: {
4053
+ count: result.secretRefs.length,
4054
+ error: err instanceof Error ? err.message : "unknown"
4055
+ } });
4056
+ }
4057
+ return result.deleted;
4058
+ }
4059
+ };
4060
+ }
4061
+ //#endregion
4062
+ //#region src/records/entry-kind.ts
4063
+ /**
4064
+ * Entry kinds (D881): every list of user-created entries (notification
4065
+ * targets, brokers, LLM profiles) is ONE record kind with an id, a name and a
4066
+ * kind-specific body, and the admin UI lists/adds/edits/deletes all of them
4067
+ * through the `record-entries` capability with password fields derived from
4068
+ * the schema (`.meta({ secret: true })`).
4069
+ */
4070
+ /** The body of a plain entry: a name and the fields the kind adds. */
4071
+ function entryBody(shape) {
4072
+ return zod.z.object({
4073
+ name: zod.z.string().min(1),
4074
+ ...shape
4075
+ });
4076
+ }
4077
+ /**
4078
+ * Declare one entry kind. An entry is configuration: never trimmed by the
4079
+ * engine, never aged, belonging to no device.
4080
+ */
4081
+ function defineEntryKind(name, spec) {
4082
+ const defined = defineRecordKinds({ [name]: {
4083
+ schema: spec.schema,
4084
+ class: "config",
4085
+ writeTrigger: spec.writeTrigger ?? "an operator adds or edits an entry in the entries UI",
4086
+ retention: { none: "an entry goes only when the operator deletes it" },
4087
+ ...spec.database === void 0 ? {} : { database: spec.database },
4088
+ ...spec.indexes === void 0 ? {} : { indexes: spec.indexes },
4089
+ ...spec.secretArrayKeys === void 0 ? {} : { secretArrayKeys: spec.secretArrayKeys },
4090
+ ...spec.adoptsFrom === void 0 ? {} : { adoptsFrom: spec.adoptsFrom },
4091
+ entry: {
4092
+ title: spec.title,
4093
+ ...spec.nameField === void 0 ? {} : { nameField: spec.nameField }
4094
+ }
4095
+ } })[name];
4096
+ if (defined === void 0) throw new DeclarationRefusedError(`entry kind "${name}" was not built`);
4097
+ return defined;
4098
+ }
4099
+ //#endregion
4100
+ //#region src/capabilities/schemas/streaming-shared.ts
4101
+ /** Shared Zod schemas used across streaming capabilities. */
4102
+ var CamProfileSchema = zod.z.enum([
4103
+ "high",
4104
+ "mid",
4105
+ "low"
4106
+ ]);
4107
+ /** Canonical ordering. Hard-coded; never sorted. */
4108
+ var CAM_PROFILE_ORDER = [
4109
+ "high",
4110
+ "mid",
4111
+ "low"
4112
+ ];
4113
+ /**
4114
+ * Which rung a per-camera consumer listens on: an explicit profile, or `auto`.
4115
+ *
4116
+ * `auto` is a REAL value, not an absent one — it means "resolve it by the rule
4117
+ * that consumer owns". It lives beside `CamProfile` because a rung is the only
4118
+ * operator-facing way to name a stream: a cam-stream id is broker-internal and
4119
+ * moves when a slot is reassigned, so a stored id silently stops meaning what
4120
+ * the operator picked. Today's one user is the audio analyser, whose rule is
4121
+ * "the lowest AVAILABLE native rung" (D537).
4122
+ */
4123
+ var AudioStreamPickSchema = zod.z.union([CamProfileSchema, zod.z.literal("auto")]);
4124
+ var CamStreamKindSchema = zod.z.enum([
4125
+ "pull-rtsp",
4126
+ "pull-rtmp",
4127
+ "pull-http",
4128
+ "pull-flv",
4129
+ "pull-rfc4571",
4130
+ "push-annexb",
4131
+ "derived"
4132
+ ]);
4133
+ var CamStreamResolutionSchema = zod.z.object({
4134
+ width: zod.z.number().int().positive(),
4135
+ height: zod.z.number().int().positive()
4136
+ });
4137
+ var CameraStreamSchema = zod.z.object({
4138
+ /** Stable, provider-assigned id unique within the (deviceId) scope. */
4139
+ camStreamId: zod.z.string().min(1),
4140
+ deviceId: zod.z.number().int().nonnegative(),
4141
+ kind: CamStreamKindSchema,
4142
+ /** Required for pull-* kinds. Ignored for push-annexb. */
4143
+ url: zod.z.string().optional(),
4144
+ codec: zod.z.string().optional(),
4145
+ resolution: CamStreamResolutionSchema.optional(),
4146
+ fps: zod.z.number().positive().optional(),
4147
+ /** Human label surfaced in the Admin UI "Camera Stream" dropdown. */
4148
+ label: zod.z.string().optional(),
4149
+ /**
4150
+ * Device-level features the publisher advertised (e.g. `battery-operated`).
4151
+ * The broker, snapshot orchestrator, and prebuffer manager all consult
4152
+ * this list to derive policy — relaxed stall watchdog for battery
4153
+ * cams, prebuffer off by default, longer snapshot rate-limit, etc.
4154
+ *
4155
+ * Single source of truth replacing per-stream flags like the
4156
+ * historical `allowStall`: if the publisher knows the camera is
4157
+ * battery-powered, every downstream service derives the right policy
4158
+ * from this list.
4159
+ */
4160
+ deviceFeatures: zod.z.array(zod.z.string()).optional(),
4161
+ /**
4162
+ * Whether this stream participates in the broker's automatic profile
4163
+ * assignment (`computeInitialAssignment`). Defaults to `true`. Publishers
4164
+ * use `false` when they want a stream to be SELECTABLE in the UI but not
4165
+ * picked by default — e.g. Reolink publishes its native Baichuan streams
4166
+ * as `autoEligible: true` (the recommended path) and its RTSP / RTMP
4167
+ * mirrors as `autoEligible: false` (still pickable per slot, just not
4168
+ * the auto choice). Manual `assignProfile` calls remain valid for
4169
+ * non-eligible streams.
4170
+ */
4171
+ autoEligible: zod.z.boolean().optional(),
4172
+ /**
4173
+ * The profile slot the PUBLISHER says this stream is: `low` for a stream
4174
+ * whose only sensible role is the low-bandwidth one, `high` for a main
4175
+ * stream. Consulted by the broker's automatic ranking
4176
+ * (`rankInitialAssignment`) BEFORE the pixel-count heuristic, and only there:
4177
+ * an operator's manual assignment still wins, and an absent hint is the
4178
+ * pixel-ranked default every camera had before this field existed.
4179
+ *
4180
+ * Why it exists: a camera with ONE stream ranked to `mid` — the slot no
4181
+ * storage class is written for on its own (`recordings` is high|mid,
4182
+ * `recordingsLow` is low) and the one profile scrub does not read. The robot
4183
+ * camera's single 720p relay is a `low` in every respect except the slot the
4184
+ * heuristic put it in.
4185
+ */
4186
+ profileHint: CamProfileSchema.optional(),
4187
+ /**
4188
+ * Transport-specific opaque metadata. The broker passes it through to
4189
+ * the source reader without inspecting it. Currently used by
4190
+ * `pull-rfc4571` streams to carry the upstream SDP (so the reader can
4191
+ * route RTP packets to the right depacketizer without an in-band
4192
+ * DESCRIBE phase). Other kinds typically leave it undefined.
4193
+ */
4194
+ metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
4195
+ });
4196
+ var ProfileSlotStatusSchema = zod.z.enum([
4197
+ "unassigned",
4198
+ "idle",
4199
+ "connecting",
4200
+ "streaming",
4201
+ "error"
4202
+ ]);
4203
+ var ProfileSlotSchema = zod.z.object({
4204
+ deviceId: zod.z.number().int().nonnegative(),
4205
+ profile: CamProfileSchema,
4206
+ /** Broker id the rest of the system addresses: `${deviceId}/${profile}`. */
4207
+ brokerId: zod.z.string(),
4208
+ /** `null` when the profile is unassigned. */
4209
+ sourceCamStreamId: zod.z.string().nullable(),
4210
+ status: ProfileSlotStatusSchema,
4211
+ resolution: CamStreamResolutionSchema.optional(),
4212
+ codec: zod.z.string().optional(),
4213
+ preBufferSec: zod.z.number().nonnegative().optional(),
4214
+ errorMessage: zod.z.string().optional()
4215
+ });
4216
+ /** The canonical consumer-facing broker id for a device profile. */
4217
+ function makeProfileBrokerId(deviceId, profile) {
4218
+ return `${deviceId}/${profile}`;
4219
+ }
4220
+ /**
4221
+ * The broker id keying a physical SOURCE stream: `${deviceId}/${camStreamId}`.
4222
+ * This is the broker's internal source key (`brokerIdFor` in the manager) — a
4223
+ * `camStreamId` like `native:main` — as opposed to the public profile alias
4224
+ * {@link makeProfileBrokerId}. Used to resolve a source's restream endpoint
4225
+ * (e.g. routing a transcode's ffmpeg input through the broker so it rides the
4226
+ * single source dial instead of opening a second camera connection).
4227
+ */
4228
+ function makeSourceBrokerId(deviceId, camStreamId) {
4229
+ return `${deviceId}/${camStreamId}`;
4230
+ }
4231
+ /**
4232
+ * Inverse of {@link makeProfileBrokerId}. Returns `null` when the string is
4233
+ * not a canonical `${deviceId}/${profile}` id — e.g. a broker-internal
4234
+ * cam-stream id (`5/native:main`), a derived/adaptive ref, or a malformed
4235
+ * value. So a caller can safely distinguish "addresses a public profile"
4236
+ * from "addresses something broker-internal".
4237
+ */
4238
+ function parseProfileBrokerId(brokerId) {
4239
+ const slash = brokerId.indexOf("/");
4240
+ if (slash <= 0) return null;
4241
+ const idPart = brokerId.slice(0, slash);
4242
+ const profilePart = brokerId.slice(slash + 1);
4243
+ if (!/^\d+$/.test(idPart)) return null;
4244
+ const parsed = CamProfileSchema.safeParse(profilePart);
4245
+ if (!parsed.success) return null;
4246
+ return {
4247
+ deviceId: Number(idPart),
4248
+ profile: parsed.data
4249
+ };
4250
+ }
4251
+ /**
4252
+ * The profile slots worth consuming/recording: ASSIGNED only
4253
+ * (`sourceCamStreamId != null`), DEDUPED by physical source so the same
4254
+ * camera encoder is never subscribed/recorded twice, ordered high→mid→low.
4255
+ * Optionally scoped to one `deviceId`. Pure; never mutates the input.
4256
+ *
4257
+ * Recording `main` and `mid` when both point at the same `sourceCamStreamId`
4258
+ * would dial the camera's internal stream twice for no benefit — this is the
4259
+ * dedup that prevents that.
4260
+ */
4261
+ function selectAssignedProfileSlots(slots, deviceId) {
4262
+ const ordered = [...slots].filter((s) => deviceId === void 0 || s.deviceId === deviceId).toSorted((a, b) => CAM_PROFILE_ORDER.indexOf(a.profile) - CAM_PROFILE_ORDER.indexOf(b.profile));
4263
+ const seenSources = /* @__PURE__ */ new Set();
4264
+ const out = [];
4265
+ for (const s of ordered) {
4266
+ const src = s.sourceCamStreamId;
4267
+ if (src === null) continue;
4268
+ if (seenSources.has(src)) continue;
4269
+ seenSources.add(src);
4270
+ out.push(s);
4271
+ }
4272
+ return out;
4273
+ }
4274
+ /**
4275
+ * Zod schema for StreamSourceEntry — the canonical stream descriptor
4276
+ * exposed by ICameraDevice.getStreamSources() and consumed by the broker.
3302
4277
  */
3303
4278
  var StreamSourceEntrySchema$1 = zod.z.object({
3304
4279
  id: zod.z.string(),
@@ -4507,123 +5482,35 @@ var DEFAULT_TOKEN_EXPIRY = "30d";
4507
5482
  * Moved from @camstack/system/config-schema to @camstack/types so that
4508
5483
  * @camstack/system can reference it without a cross-package kernel import.
4509
5484
  */
4510
- var RUNTIME_DEFAULTS = {
4511
- "features.streaming": true,
4512
- "features.notifications": true,
4513
- "features.objectDetection": false,
4514
- "features.remoteAccess": true,
4515
- "features.agentCluster": false,
4516
- "features.smartHome": true,
4517
- "features.recordings": true,
4518
- "features.backup": true,
4519
- "features.repl": true,
4520
- "retention.detectionEventsDays": 30,
4521
- "retention.audioLevelsDays": 7,
4522
- "logging.level": "info",
4523
- "logging.retentionDays": 30,
4524
- "eventBus.ringBufferSize": 1e4,
4525
- "storage.provider": "sqlite-storage",
4526
- "storage.locations": {
4527
- data: "camstack-data/data",
4528
- media: "camstack-data/media",
4529
- recordings: "camstack-data/recordings",
4530
- cache: "/tmp/camstack-cache",
4531
- logs: "camstack-data/logs",
4532
- models: "camstack-data/models"
4533
- },
4534
- providers: [],
4535
- "ffmpeg.hwAccel": "auto",
4536
- "ffmpeg.threadCount": 0,
4537
- "auth.tokenExpiry": "30d"
4538
- };
4539
- //#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 zod.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
- }
5485
+ var RUNTIME_DEFAULTS = {
5486
+ "features.streaming": true,
5487
+ "features.notifications": true,
5488
+ "features.objectDetection": false,
5489
+ "features.remoteAccess": true,
5490
+ "features.agentCluster": false,
5491
+ "features.smartHome": true,
5492
+ "features.recordings": true,
5493
+ "features.backup": true,
5494
+ "features.repl": true,
5495
+ "retention.detectionEventsDays": 30,
5496
+ "retention.audioLevelsDays": 7,
5497
+ "logging.level": "info",
5498
+ "logging.retentionDays": 30,
5499
+ "eventBus.ringBufferSize": 1e4,
5500
+ "storage.provider": "sqlite-storage",
5501
+ "storage.locations": {
5502
+ data: "camstack-data/data",
5503
+ media: "camstack-data/media",
5504
+ recordings: "camstack-data/recordings",
5505
+ cache: "/tmp/camstack-cache",
5506
+ logs: "camstack-data/logs",
5507
+ models: "camstack-data/models"
5508
+ },
5509
+ providers: [],
5510
+ "ffmpeg.hwAccel": "auto",
5511
+ "ffmpeg.threadCount": 0,
5512
+ "auth.tokenExpiry": "30d"
5513
+ };
4627
5514
  //#endregion
4628
5515
  //#region src/device/device-state-handle.ts
4629
5516
  var DEVICE_STATE_EVENT_CATEGORY = "device.state-changed";
@@ -6193,6 +7080,12 @@ Object.defineProperty(exports, "AUDIO_CHUNK_FORMATS", {
6193
7080
  return AUDIO_CHUNK_FORMATS;
6194
7081
  }
6195
7082
  });
7083
+ Object.defineProperty(exports, "AdoptionPendingError", {
7084
+ enumerable: true,
7085
+ get: function() {
7086
+ return AdoptionPendingError;
7087
+ }
7088
+ });
6196
7089
  Object.defineProperty(exports, "AudioChunkFormatSchema", {
6197
7090
  enumerable: true,
6198
7091
  get: function() {
@@ -6217,6 +7110,12 @@ Object.defineProperty(exports, "BaseAddon", {
6217
7110
  return BaseAddon;
6218
7111
  }
6219
7112
  });
7113
+ Object.defineProperty(exports, "BatchTooLargeError", {
7114
+ enumerable: true,
7115
+ get: function() {
7116
+ return BatchTooLargeError;
7117
+ }
7118
+ });
6220
7119
  Object.defineProperty(exports, "BrokerStatsSchema", {
6221
7120
  enumerable: true,
6222
7121
  get: function() {
@@ -6313,6 +7212,12 @@ Object.defineProperty(exports, "DEVICE_STATUS_METHOD", {
6313
7212
  return DEVICE_STATUS_METHOD;
6314
7213
  }
6315
7214
  });
7215
+ Object.defineProperty(exports, "DeclarationRefusedError", {
7216
+ enumerable: true,
7217
+ get: function() {
7218
+ return DeclarationRefusedError;
7219
+ }
7220
+ });
6316
7221
  Object.defineProperty(exports, "DecodedAudioChunkSchema", {
6317
7222
  enumerable: true,
6318
7223
  get: function() {
@@ -6325,6 +7230,12 @@ Object.defineProperty(exports, "DisposerChain", {
6325
7230
  return DisposerChain;
6326
7231
  }
6327
7232
  });
7233
+ Object.defineProperty(exports, "EntryDescriptorSchema", {
7234
+ enumerable: true,
7235
+ get: function() {
7236
+ return EntryDescriptorSchema;
7237
+ }
7238
+ });
6328
7239
  Object.defineProperty(exports, "ErrorCodeSchema", {
6329
7240
  enumerable: true,
6330
7241
  get: function() {
@@ -6337,6 +7248,18 @@ Object.defineProperty(exports, "ErrorI18nPayloadSchema", {
6337
7248
  return ErrorI18nPayloadSchema;
6338
7249
  }
6339
7250
  });
7251
+ Object.defineProperty(exports, "FilterRequiredError", {
7252
+ enumerable: true,
7253
+ get: function() {
7254
+ return FilterRequiredError;
7255
+ }
7256
+ });
7257
+ Object.defineProperty(exports, "ForeignSecretMarkerError", {
7258
+ enumerable: true,
7259
+ get: function() {
7260
+ return ForeignSecretMarkerError;
7261
+ }
7262
+ });
6340
7263
  Object.defineProperty(exports, "FrameHandleSchema", {
6341
7264
  enumerable: true,
6342
7265
  get: function() {
@@ -6367,6 +7290,12 @@ Object.defineProperty(exports, "HISTORY_UNIT_LABELS", {
6367
7290
  return HISTORY_UNIT_LABELS;
6368
7291
  }
6369
7292
  });
7293
+ Object.defineProperty(exports, "InvalidRecordError", {
7294
+ enumerable: true,
7295
+ get: function() {
7296
+ return InvalidRecordError;
7297
+ }
7298
+ });
6370
7299
  Object.defineProperty(exports, "KeychainWriteRefusedError", {
6371
7300
  enumerable: true,
6372
7301
  get: function() {
@@ -6385,6 +7314,12 @@ Object.defineProperty(exports, "MODEL_FORMATS", {
6385
7314
  return MODEL_FORMATS;
6386
7315
  }
6387
7316
  });
7317
+ Object.defineProperty(exports, "NoCallerError", {
7318
+ enumerable: true,
7319
+ get: function() {
7320
+ return NoCallerError;
7321
+ }
7322
+ });
6388
7323
  Object.defineProperty(exports, "PEER_BYTES_CHUNK_BYTES", {
6389
7324
  enumerable: true,
6390
7325
  get: function() {
@@ -6421,6 +7356,12 @@ Object.defineProperty(exports, "PeerBytesTicketSchema", {
6421
7356
  return PeerBytesTicketSchema;
6422
7357
  }
6423
7358
  });
7359
+ Object.defineProperty(exports, "PlaintextSecretError", {
7360
+ enumerable: true,
7361
+ get: function() {
7362
+ return PlaintextSecretError;
7363
+ }
7364
+ });
6424
7365
  Object.defineProperty(exports, "ProfileRtspEntrySchema", {
6425
7366
  enumerable: true,
6426
7367
  get: function() {
@@ -6439,12 +7380,108 @@ Object.defineProperty(exports, "ProfileSlotStatusSchema", {
6439
7380
  return ProfileSlotStatusSchema;
6440
7381
  }
6441
7382
  });
7383
+ Object.defineProperty(exports, "RECORDS_ERROR_CODES", {
7384
+ enumerable: true,
7385
+ get: function() {
7386
+ return RECORDS_ERROR_CODES;
7387
+ }
7388
+ });
7389
+ Object.defineProperty(exports, "RECORD_BATCH_MAX", {
7390
+ enumerable: true,
7391
+ get: function() {
7392
+ return RECORD_BATCH_MAX;
7393
+ }
7394
+ });
7395
+ Object.defineProperty(exports, "RECORD_BATCH_MAX_BYTES", {
7396
+ enumerable: true,
7397
+ get: function() {
7398
+ return RECORD_BATCH_MAX_BYTES;
7399
+ }
7400
+ });
7401
+ Object.defineProperty(exports, "RECORD_CLASSES", {
7402
+ enumerable: true,
7403
+ get: function() {
7404
+ return RECORD_CLASSES;
7405
+ }
7406
+ });
7407
+ Object.defineProperty(exports, "RECORD_DATABASES", {
7408
+ enumerable: true,
7409
+ get: function() {
7410
+ return RECORD_DATABASES;
7411
+ }
7412
+ });
7413
+ Object.defineProperty(exports, "RECORD_DEFAULT_MAX_DATA_BYTES", {
7414
+ enumerable: true,
7415
+ get: function() {
7416
+ return RECORD_DEFAULT_MAX_DATA_BYTES;
7417
+ }
7418
+ });
7419
+ Object.defineProperty(exports, "RECORD_DELETE_BATCH", {
7420
+ enumerable: true,
7421
+ get: function() {
7422
+ return RECORD_DELETE_BATCH;
7423
+ }
7424
+ });
7425
+ Object.defineProperty(exports, "RECORD_ID_MAX_LENGTH", {
7426
+ enumerable: true,
7427
+ get: function() {
7428
+ return RECORD_ID_MAX_LENGTH;
7429
+ }
7430
+ });
7431
+ Object.defineProperty(exports, "RECORD_MAX_DATA_BYTES", {
7432
+ enumerable: true,
7433
+ get: function() {
7434
+ return RECORD_MAX_DATA_BYTES;
7435
+ }
7436
+ });
7437
+ Object.defineProperty(exports, "RECORD_MAX_INDEXES", {
7438
+ enumerable: true,
7439
+ get: function() {
7440
+ return RECORD_MAX_INDEXES;
7441
+ }
7442
+ });
7443
+ Object.defineProperty(exports, "RECORD_MAX_INDEX_FIELDS", {
7444
+ enumerable: true,
7445
+ get: function() {
7446
+ return RECORD_MAX_INDEX_FIELDS;
7447
+ }
7448
+ });
7449
+ Object.defineProperty(exports, "RECORD_QUERY_MAX", {
7450
+ enumerable: true,
7451
+ get: function() {
7452
+ return RECORD_QUERY_MAX;
7453
+ }
7454
+ });
7455
+ Object.defineProperty(exports, "RECORD_SECRET_COLLECTION_PREFIX", {
7456
+ enumerable: true,
7457
+ get: function() {
7458
+ return RECORD_SECRET_COLLECTION_PREFIX;
7459
+ }
7460
+ });
7461
+ Object.defineProperty(exports, "RECORD_SETTINGS_MAX_ROWS", {
7462
+ enumerable: true,
7463
+ get: function() {
7464
+ return RECORD_SETTINGS_MAX_ROWS;
7465
+ }
7466
+ });
7467
+ Object.defineProperty(exports, "RECORD_SWEEP_INTERVAL_MS", {
7468
+ enumerable: true,
7469
+ get: function() {
7470
+ return RECORD_SWEEP_INTERVAL_MS;
7471
+ }
7472
+ });
6442
7473
  Object.defineProperty(exports, "REDACTED_SECRET", {
6443
7474
  enumerable: true,
6444
7475
  get: function() {
6445
7476
  return REDACTED_SECRET;
6446
7477
  }
6447
7478
  });
7479
+ Object.defineProperty(exports, "REMOVE_LEAF", {
7480
+ enumerable: true,
7481
+ get: function() {
7482
+ return REMOVE_LEAF;
7483
+ }
7484
+ });
6448
7485
  Object.defineProperty(exports, "REVALIDATE_AFTER_MS", {
6449
7486
  enumerable: true,
6450
7487
  get: function() {
@@ -6475,6 +7512,72 @@ Object.defineProperty(exports, "ReadinessTimeoutError", {
6475
7512
  return ReadinessTimeoutError;
6476
7513
  }
6477
7514
  });
7515
+ Object.defineProperty(exports, "RecordFieldPathSchema", {
7516
+ enumerable: true,
7517
+ get: function() {
7518
+ return RecordFieldPathSchema;
7519
+ }
7520
+ });
7521
+ Object.defineProperty(exports, "RecordIndexSchema", {
7522
+ enumerable: true,
7523
+ get: function() {
7524
+ return RecordIndexSchema;
7525
+ }
7526
+ });
7527
+ Object.defineProperty(exports, "RecordKindDeclarationSchema", {
7528
+ enumerable: true,
7529
+ get: function() {
7530
+ return RecordKindDeclarationSchema;
7531
+ }
7532
+ });
7533
+ Object.defineProperty(exports, "RecordKindNameSchema", {
7534
+ enumerable: true,
7535
+ get: function() {
7536
+ return RecordKindNameSchema;
7537
+ }
7538
+ });
7539
+ Object.defineProperty(exports, "RecordNotFoundError", {
7540
+ enumerable: true,
7541
+ get: function() {
7542
+ return RecordNotFoundError;
7543
+ }
7544
+ });
7545
+ Object.defineProperty(exports, "RecordRetentionSchema", {
7546
+ enumerable: true,
7547
+ get: function() {
7548
+ return RecordRetentionSchema;
7549
+ }
7550
+ });
7551
+ Object.defineProperty(exports, "RecordSecretUnavailableError", {
7552
+ enumerable: true,
7553
+ get: function() {
7554
+ return RecordSecretUnavailableError;
7555
+ }
7556
+ });
7557
+ Object.defineProperty(exports, "RecordTooLargeError", {
7558
+ enumerable: true,
7559
+ get: function() {
7560
+ return RecordTooLargeError;
7561
+ }
7562
+ });
7563
+ Object.defineProperty(exports, "RecordUniqueViolationError", {
7564
+ enumerable: true,
7565
+ get: function() {
7566
+ return RecordUniqueViolationError;
7567
+ }
7568
+ });
7569
+ Object.defineProperty(exports, "RecordsError", {
7570
+ enumerable: true,
7571
+ get: function() {
7572
+ return RecordsError;
7573
+ }
7574
+ });
7575
+ Object.defineProperty(exports, "RevConflictError", {
7576
+ enumerable: true,
7577
+ get: function() {
7578
+ return RevConflictError;
7579
+ }
7580
+ });
6478
7581
  Object.defineProperty(exports, "SECRET_CLEAR", {
6479
7582
  enumerable: true,
6480
7583
  get: function() {
@@ -6523,6 +7626,18 @@ Object.defineProperty(exports, "SubscribeAudioChunksResultSchema", {
6523
7626
  return SubscribeAudioChunksResultSchema;
6524
7627
  }
6525
7628
  });
7629
+ Object.defineProperty(exports, "UnindexedFilterError", {
7630
+ enumerable: true,
7631
+ get: function() {
7632
+ return UnindexedFilterError;
7633
+ }
7634
+ });
7635
+ Object.defineProperty(exports, "UnknownRecordKindError", {
7636
+ enumerable: true,
7637
+ get: function() {
7638
+ return UnknownRecordKindError;
7639
+ }
7640
+ });
6526
7641
  Object.defineProperty(exports, "WELL_KNOWN_TABS", {
6527
7642
  enumerable: true,
6528
7643
  get: function() {
@@ -6571,12 +7686,24 @@ Object.defineProperty(exports, "asNumber", {
6571
7686
  return asNumber;
6572
7687
  }
6573
7688
  });
7689
+ Object.defineProperty(exports, "asRecordsError", {
7690
+ enumerable: true,
7691
+ get: function() {
7692
+ return asRecordsError;
7693
+ }
7694
+ });
6574
7695
  Object.defineProperty(exports, "asString", {
6575
7696
  enumerable: true,
6576
7697
  get: function() {
6577
7698
  return asString;
6578
7699
  }
6579
7700
  });
7701
+ Object.defineProperty(exports, "assertValidDeclaration", {
7702
+ enumerable: true,
7703
+ get: function() {
7704
+ return assertValidDeclaration;
7705
+ }
7706
+ });
6580
7707
  Object.defineProperty(exports, "audioChunkBytesPerSample", {
6581
7708
  enumerable: true,
6582
7709
  get: function() {
@@ -6631,6 +7758,12 @@ Object.defineProperty(exports, "collectSecretConfigKeys", {
6631
7758
  return collectSecretConfigKeys;
6632
7759
  }
6633
7760
  });
7761
+ Object.defineProperty(exports, "collectSecretLeaves", {
7762
+ enumerable: true,
7763
+ get: function() {
7764
+ return collectSecretLeaves;
7765
+ }
7766
+ });
6634
7767
  Object.defineProperty(exports, "collectSecretMarkerRefs", {
6635
7768
  enumerable: true,
6636
7769
  get: function() {
@@ -6679,6 +7812,12 @@ Object.defineProperty(exports, "createMirrorSource", {
6679
7812
  return createMirrorSource;
6680
7813
  }
6681
7814
  });
7815
+ Object.defineProperty(exports, "createRecordsAccess", {
7816
+ enumerable: true,
7817
+ get: function() {
7818
+ return createRecordsAccess;
7819
+ }
7820
+ });
6682
7821
  Object.defineProperty(exports, "createSecretsAccess", {
6683
7822
  enumerable: true,
6684
7823
  get: function() {
@@ -6697,12 +7836,30 @@ Object.defineProperty(exports, "customAction", {
6697
7836
  return customAction;
6698
7837
  }
6699
7838
  });
7839
+ Object.defineProperty(exports, "declarationsOf", {
7840
+ enumerable: true,
7841
+ get: function() {
7842
+ return declarationsOf;
7843
+ }
7844
+ });
6700
7845
  Object.defineProperty(exports, "defineCustomActions", {
6701
7846
  enumerable: true,
6702
7847
  get: function() {
6703
7848
  return defineCustomActions;
6704
7849
  }
6705
7850
  });
7851
+ Object.defineProperty(exports, "defineEntryKind", {
7852
+ enumerable: true,
7853
+ get: function() {
7854
+ return defineEntryKind;
7855
+ }
7856
+ });
7857
+ Object.defineProperty(exports, "defineRecordKinds", {
7858
+ enumerable: true,
7859
+ get: function() {
7860
+ return defineRecordKinds;
7861
+ }
7862
+ });
6706
7863
  Object.defineProperty(exports, "describeCustomActions", {
6707
7864
  enumerable: true,
6708
7865
  get: function() {
@@ -6733,6 +7890,12 @@ Object.defineProperty(exports, "emitReadiness", {
6733
7890
  return emitReadiness;
6734
7891
  }
6735
7892
  });
7893
+ Object.defineProperty(exports, "entryBody", {
7894
+ enumerable: true,
7895
+ get: function() {
7896
+ return entryBody;
7897
+ }
7898
+ });
6736
7899
  Object.defineProperty(exports, "event", {
6737
7900
  enumerable: true,
6738
7901
  get: function() {
@@ -6883,6 +8046,12 @@ Object.defineProperty(exports, "makeSourceBrokerId", {
6883
8046
  return makeSourceBrokerId;
6884
8047
  }
6885
8048
  });
8049
+ Object.defineProperty(exports, "mapSecretLeaves", {
8050
+ enumerable: true,
8051
+ get: function() {
8052
+ return mapSecretLeaves;
8053
+ }
8054
+ });
6886
8055
  Object.defineProperty(exports, "maskUrlCredentials", {
6887
8056
  enumerable: true,
6888
8057
  get: function() {
@@ -6955,6 +8124,12 @@ Object.defineProperty(exports, "parseProfileBrokerId", {
6955
8124
  return parseProfileBrokerId;
6956
8125
  }
6957
8126
  });
8127
+ Object.defineProperty(exports, "parseSecretPath", {
8128
+ enumerable: true,
8129
+ get: function() {
8130
+ return parseSecretPath;
8131
+ }
8132
+ });
6958
8133
  Object.defineProperty(exports, "parseSecretRef", {
6959
8134
  enumerable: true,
6960
8135
  get: function() {
@@ -6985,6 +8160,30 @@ Object.defineProperty(exports, "readinessKey", {
6985
8160
  return readinessKey;
6986
8161
  }
6987
8162
  });
8163
+ Object.defineProperty(exports, "recordArrayItemPath", {
8164
+ enumerable: true,
8165
+ get: function() {
8166
+ return recordArrayItemPath;
8167
+ }
8168
+ });
8169
+ Object.defineProperty(exports, "recordSecretCollection", {
8170
+ enumerable: true,
8171
+ get: function() {
8172
+ return recordSecretCollection;
8173
+ }
8174
+ });
8175
+ Object.defineProperty(exports, "recordSecretRef", {
8176
+ enumerable: true,
8177
+ get: function() {
8178
+ return recordSecretRef;
8179
+ }
8180
+ });
8181
+ Object.defineProperty(exports, "recordsErrorFromMessage", {
8182
+ enumerable: true,
8183
+ get: function() {
8184
+ return recordsErrorFromMessage;
8185
+ }
8186
+ });
6988
8187
  Object.defineProperty(exports, "registerKnownSecret", {
6989
8188
  enumerable: true,
6990
8189
  get: function() {
@@ -7033,6 +8232,12 @@ Object.defineProperty(exports, "scrubKnownSecrets", {
7033
8232
  return scrubKnownSecrets;
7034
8233
  }
7035
8234
  });
8235
+ Object.defineProperty(exports, "secretArrayPrefixes", {
8236
+ enumerable: true,
8237
+ get: function() {
8238
+ return secretArrayPrefixes;
8239
+ }
8240
+ });
7036
8241
  Object.defineProperty(exports, "secretTreeFromPaths", {
7037
8242
  enumerable: true,
7038
8243
  get: function() {