@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.
- package/dist/addon.d.ts +3 -0
- package/dist/addon.js +67 -2
- package/dist/addon.mjs +5 -3
- package/dist/capabilities/caller-stamp.d.ts +12 -0
- package/dist/capabilities/index.d.ts +7 -2
- package/dist/capabilities/record-entries.cap.d.ts +84 -0
- package/dist/capabilities/records.cap.d.ts +399 -0
- package/dist/capabilities/storage-admin.cap.d.ts +268 -0
- package/dist/client.js +57 -32
- package/dist/client.mjs +57 -32
- package/dist/device/device-context.d.ts +2 -0
- package/dist/ffmpeg/fmp4-fragment-child.d.ts +2 -2
- package/dist/ffmpeg/process.d.ts +21 -0
- package/dist/generated/addon-api.d.ts +191 -0
- package/dist/generated/cap-input-defaults.d.ts +1 -1
- package/dist/generated/capability-router-map.d.ts +8 -2
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/generated/method-device-selectors.d.ts +2 -2
- package/dist/generated/system-proxy.d.ts +2 -0
- package/dist/helpers/addon-slice-handle.d.ts +4 -0
- package/dist/helpers/trpc-leaf.d.ts +17 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +724 -32
- package/dist/index.mjs +646 -33
- package/dist/interfaces/addon-peer-bytes.d.ts +19 -2
- package/dist/interfaces/addon.d.ts +13 -0
- package/dist/interfaces/config-ui.d.ts +4 -0
- package/dist/interfaces/event-bus.d.ts +32 -3
- package/dist/interfaces/storage.d.ts +1 -1
- package/dist/node.d.ts +2 -2
- package/dist/node.js +4 -0
- package/dist/node.mjs +4 -1
- package/dist/records/constants.d.ts +23 -0
- package/dist/records/entry-kind.d.ts +31 -0
- package/dist/records/errors.d.ts +81 -0
- package/dist/records/in-memory-records.d.ts +21 -0
- package/dist/records/index.d.ts +9 -0
- package/dist/records/record-kind.d.ts +144 -0
- package/dist/records/records-access.d.ts +153 -0
- package/dist/records/secret-paths.d.ts +52 -0
- package/dist/records/settings-array-adopts-from.d.ts +12 -0
- package/dist/records/settings-brokers-adopts-from.d.ts +10 -0
- package/dist/{sleep-DQYi915G.js → sleep-D8yJVc4r.js} +1971 -290
- package/dist/{sleep-D-Q2_Mcd.mjs → sleep-bZIhUvjd.mjs} +1413 -128
- 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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
261
|
+
return isRecord$5(value) && Object.prototype.hasOwnProperty.call(value, "$secret");
|
|
262
262
|
}
|
|
263
263
|
function isSecretClear(value) {
|
|
264
|
-
return isRecord$
|
|
264
|
+
return isRecord$5(value) && value["$secretClear"] === true;
|
|
265
265
|
}
|
|
266
266
|
function isSecretFieldView(value) {
|
|
267
|
-
return isRecord$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
|
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,185 +3149,1476 @@ async function resolveSecretViewsIn(args, secrets) {
|
|
|
3122
3149
|
return swap(args).value;
|
|
3123
3150
|
}
|
|
3124
3151
|
//#endregion
|
|
3125
|
-
//#region src/
|
|
3126
|
-
/**
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
"
|
|
3135
|
-
"
|
|
3136
|
-
"low"
|
|
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"
|
|
3137
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
|
|
3138
3182
|
/**
|
|
3139
|
-
*
|
|
3183
|
+
* The named failures of `ctx.records` (D881).
|
|
3140
3184
|
*
|
|
3141
|
-
*
|
|
3142
|
-
*
|
|
3143
|
-
*
|
|
3144
|
-
*
|
|
3145
|
-
*
|
|
3146
|
-
* "the lowest AVAILABLE native rung" (D537).
|
|
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.
|
|
3147
3190
|
*/
|
|
3148
|
-
|
|
3149
|
-
var
|
|
3150
|
-
"
|
|
3151
|
-
"
|
|
3152
|
-
"
|
|
3153
|
-
"
|
|
3154
|
-
"
|
|
3155
|
-
"
|
|
3156
|
-
"
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
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);
|
|
3244
3341
|
}
|
|
3245
3342
|
/**
|
|
3246
|
-
*
|
|
3247
|
-
*
|
|
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).
|
|
3343
|
+
* Rebuild the typed error from a message that crossed a wire; `null` when the
|
|
3344
|
+
* message is not a records failure.
|
|
3252
3345
|
*/
|
|
3253
|
-
function
|
|
3254
|
-
return
|
|
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;
|
|
3255
3362
|
}
|
|
3363
|
+
//#endregion
|
|
3364
|
+
//#region src/device/zod-secret.ts
|
|
3256
3365
|
/**
|
|
3257
|
-
*
|
|
3258
|
-
*
|
|
3259
|
-
*
|
|
3260
|
-
*
|
|
3261
|
-
*
|
|
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.
|
|
3262
3378
|
*/
|
|
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
3379
|
/**
|
|
3277
|
-
*
|
|
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.
|
|
3380
|
+
* `{ secret: true }` — the one spelling of "this field holds a credential".
|
|
3281
3381
|
*
|
|
3282
|
-
*
|
|
3283
|
-
*
|
|
3284
|
-
*
|
|
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.
|
|
3285
3386
|
*/
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
const
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
if (seenSources.has(src)) continue;
|
|
3294
|
-
seenSources.add(src);
|
|
3295
|
-
out.push(s);
|
|
3296
|
-
}
|
|
3297
|
-
return out;
|
|
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;
|
|
3298
3394
|
}
|
|
3395
|
+
function declaredHere(schema) {
|
|
3396
|
+
return zod.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
|
+
]);
|
|
3299
3408
|
/**
|
|
3300
|
-
*
|
|
3301
|
-
*
|
|
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`).
|
|
3302
3413
|
*/
|
|
3303
|
-
|
|
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 = zod.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 = zod.z.object({
|
|
3601
|
+
name: zod.z.string().regex(/^[a-z][a-z0-9_]{0,31}$/),
|
|
3602
|
+
fields: zod.z.array(RecordFieldPathSchema).min(1).max(4),
|
|
3603
|
+
unique: zod.z.boolean().optional()
|
|
3604
|
+
}).strict();
|
|
3605
|
+
var RecordRetentionSchema = zod.z.union([
|
|
3606
|
+
zod.z.object({
|
|
3607
|
+
ttlMs: zod.z.number().int().positive(),
|
|
3608
|
+
from: zod.z.enum(["at", "write"])
|
|
3609
|
+
}).strict(),
|
|
3610
|
+
zod.z.object({
|
|
3611
|
+
maxRows: zod.z.number().int().positive().optional(),
|
|
3612
|
+
maxRowsPerDevice: zod.z.number().int().positive().optional()
|
|
3613
|
+
}).strict().refine((r) => r.maxRows !== void 0 || r.maxRowsPerDevice !== void 0, { message: "name maxRows, maxRowsPerDevice or both" }),
|
|
3614
|
+
zod.z.object({
|
|
3615
|
+
owner: zod.z.string().min(1),
|
|
3616
|
+
reason: zod.z.string().min(1)
|
|
3617
|
+
}).strict(),
|
|
3618
|
+
zod.z.object({ none: zod.z.string().min(1) }).strict()
|
|
3619
|
+
]);
|
|
3620
|
+
/** The descriptor a generic entries UI reads (D881 "generic entries"). */
|
|
3621
|
+
var EntryDescriptorSchema = zod.z.object({
|
|
3622
|
+
title: zod.z.string().min(1),
|
|
3623
|
+
/** The record body field shown as the entry's name. */
|
|
3624
|
+
nameField: zod.z.string().min(1),
|
|
3625
|
+
/** JSON Schema of the entry body; `secret: true` marks a password field. */
|
|
3626
|
+
fields: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
3627
|
+
}).strict();
|
|
3628
|
+
/** What crosses the wire and sits in the engine's catalog: JSON only, no Zod. */
|
|
3629
|
+
var RecordKindDeclarationSchema = zod.z.object({
|
|
3630
|
+
database: zod.z.enum(RECORD_DATABASES).default("settings"),
|
|
3631
|
+
class: zod.z.enum(RECORD_CLASSES),
|
|
3632
|
+
writeTrigger: zod.z.string().min(1),
|
|
3633
|
+
device: zod.z.enum([
|
|
3634
|
+
"required",
|
|
3635
|
+
"optional",
|
|
3636
|
+
"none"
|
|
3637
|
+
]).default("none"),
|
|
3638
|
+
at: zod.z.enum(["required", "none"]).default("none"),
|
|
3639
|
+
indexes: zod.z.array(RecordIndexSchema).max(8).default([]),
|
|
3640
|
+
retention: RecordRetentionSchema,
|
|
3641
|
+
deviceRemoval: zod.z.enum(["delete", "none"]).default("none"),
|
|
3642
|
+
maxDataBytes: zod.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: zod.z.array(zod.z.string().min(1)).default([]),
|
|
3645
|
+
/** The id key of each array that carries a secret (`{ headers: 'name' }`). */
|
|
3646
|
+
secretArrayKeys: zod.z.record(zod.z.string(), zod.z.string()).default({}),
|
|
3647
|
+
/** The legacy table this kind adopts from; the boot guard reads it (D853: no migration code). */
|
|
3648
|
+
adoptsFrom: zod.z.string().min(1).optional(),
|
|
3649
|
+
/** Kinds that must agree through `transact` sit in one file under one family name. */
|
|
3650
|
+
transactFamily: zod.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 = zod.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 { ...zod.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 zod.z.object({
|
|
4104
|
+
name: zod.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
|
|
4443
|
+
//#region src/capabilities/schemas/streaming-shared.ts
|
|
4444
|
+
/** Shared Zod schemas used across streaming capabilities. */
|
|
4445
|
+
var CamProfileSchema = zod.z.enum([
|
|
4446
|
+
"high",
|
|
4447
|
+
"mid",
|
|
4448
|
+
"low"
|
|
4449
|
+
]);
|
|
4450
|
+
/** Canonical ordering. Hard-coded; never sorted. */
|
|
4451
|
+
var CAM_PROFILE_ORDER = [
|
|
4452
|
+
"high",
|
|
4453
|
+
"mid",
|
|
4454
|
+
"low"
|
|
4455
|
+
];
|
|
4456
|
+
/**
|
|
4457
|
+
* Which rung a per-camera consumer listens on: an explicit profile, or `auto`.
|
|
4458
|
+
*
|
|
4459
|
+
* `auto` is a REAL value, not an absent one — it means "resolve it by the rule
|
|
4460
|
+
* that consumer owns". It lives beside `CamProfile` because a rung is the only
|
|
4461
|
+
* operator-facing way to name a stream: a cam-stream id is broker-internal and
|
|
4462
|
+
* moves when a slot is reassigned, so a stored id silently stops meaning what
|
|
4463
|
+
* the operator picked. Today's one user is the audio analyser, whose rule is
|
|
4464
|
+
* "the lowest AVAILABLE native rung" (D537).
|
|
4465
|
+
*/
|
|
4466
|
+
var AudioStreamPickSchema = zod.z.union([CamProfileSchema, zod.z.literal("auto")]);
|
|
4467
|
+
var CamStreamKindSchema = zod.z.enum([
|
|
4468
|
+
"pull-rtsp",
|
|
4469
|
+
"pull-rtmp",
|
|
4470
|
+
"pull-http",
|
|
4471
|
+
"pull-flv",
|
|
4472
|
+
"pull-rfc4571",
|
|
4473
|
+
"push-annexb",
|
|
4474
|
+
"derived"
|
|
4475
|
+
]);
|
|
4476
|
+
var CamStreamResolutionSchema = zod.z.object({
|
|
4477
|
+
width: zod.z.number().int().positive(),
|
|
4478
|
+
height: zod.z.number().int().positive()
|
|
4479
|
+
});
|
|
4480
|
+
var CameraStreamSchema = zod.z.object({
|
|
4481
|
+
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
4482
|
+
camStreamId: zod.z.string().min(1),
|
|
4483
|
+
deviceId: zod.z.number().int().nonnegative(),
|
|
4484
|
+
kind: CamStreamKindSchema,
|
|
4485
|
+
/** Required for pull-* kinds. Ignored for push-annexb. */
|
|
4486
|
+
url: zod.z.string().optional(),
|
|
4487
|
+
codec: zod.z.string().optional(),
|
|
4488
|
+
resolution: CamStreamResolutionSchema.optional(),
|
|
4489
|
+
fps: zod.z.number().positive().optional(),
|
|
4490
|
+
/** Human label surfaced in the Admin UI "Camera Stream" dropdown. */
|
|
4491
|
+
label: zod.z.string().optional(),
|
|
4492
|
+
/**
|
|
4493
|
+
* Device-level features the publisher advertised (e.g. `battery-operated`).
|
|
4494
|
+
* The broker, snapshot orchestrator, and prebuffer manager all consult
|
|
4495
|
+
* this list to derive policy — relaxed stall watchdog for battery
|
|
4496
|
+
* cams, prebuffer off by default, longer snapshot rate-limit, etc.
|
|
4497
|
+
*
|
|
4498
|
+
* Single source of truth replacing per-stream flags like the
|
|
4499
|
+
* historical `allowStall`: if the publisher knows the camera is
|
|
4500
|
+
* battery-powered, every downstream service derives the right policy
|
|
4501
|
+
* from this list.
|
|
4502
|
+
*/
|
|
4503
|
+
deviceFeatures: zod.z.array(zod.z.string()).optional(),
|
|
4504
|
+
/**
|
|
4505
|
+
* Whether this stream participates in the broker's automatic profile
|
|
4506
|
+
* assignment (`computeInitialAssignment`). Defaults to `true`. Publishers
|
|
4507
|
+
* use `false` when they want a stream to be SELECTABLE in the UI but not
|
|
4508
|
+
* picked by default — e.g. Reolink publishes its native Baichuan streams
|
|
4509
|
+
* as `autoEligible: true` (the recommended path) and its RTSP / RTMP
|
|
4510
|
+
* mirrors as `autoEligible: false` (still pickable per slot, just not
|
|
4511
|
+
* the auto choice). Manual `assignProfile` calls remain valid for
|
|
4512
|
+
* non-eligible streams.
|
|
4513
|
+
*/
|
|
4514
|
+
autoEligible: zod.z.boolean().optional(),
|
|
4515
|
+
/**
|
|
4516
|
+
* The profile slot the PUBLISHER says this stream is: `low` for a stream
|
|
4517
|
+
* whose only sensible role is the low-bandwidth one, `high` for a main
|
|
4518
|
+
* stream. Consulted by the broker's automatic ranking
|
|
4519
|
+
* (`rankInitialAssignment`) BEFORE the pixel-count heuristic, and only there:
|
|
4520
|
+
* an operator's manual assignment still wins, and an absent hint is the
|
|
4521
|
+
* pixel-ranked default every camera had before this field existed.
|
|
4522
|
+
*
|
|
4523
|
+
* Why it exists: a camera with ONE stream ranked to `mid` — the slot no
|
|
4524
|
+
* storage class is written for on its own (`recordings` is high|mid,
|
|
4525
|
+
* `recordingsLow` is low) and the one profile scrub does not read. The robot
|
|
4526
|
+
* camera's single 720p relay is a `low` in every respect except the slot the
|
|
4527
|
+
* heuristic put it in.
|
|
4528
|
+
*/
|
|
4529
|
+
profileHint: CamProfileSchema.optional(),
|
|
4530
|
+
/**
|
|
4531
|
+
* Transport-specific opaque metadata. The broker passes it through to
|
|
4532
|
+
* the source reader without inspecting it. Currently used by
|
|
4533
|
+
* `pull-rfc4571` streams to carry the upstream SDP (so the reader can
|
|
4534
|
+
* route RTP packets to the right depacketizer without an in-band
|
|
4535
|
+
* DESCRIBE phase). Other kinds typically leave it undefined.
|
|
4536
|
+
*/
|
|
4537
|
+
metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
|
|
4538
|
+
});
|
|
4539
|
+
var ProfileSlotStatusSchema = zod.z.enum([
|
|
4540
|
+
"unassigned",
|
|
4541
|
+
"idle",
|
|
4542
|
+
"connecting",
|
|
4543
|
+
"streaming",
|
|
4544
|
+
"error"
|
|
4545
|
+
]);
|
|
4546
|
+
var ProfileSlotSchema = zod.z.object({
|
|
4547
|
+
deviceId: zod.z.number().int().nonnegative(),
|
|
4548
|
+
profile: CamProfileSchema,
|
|
4549
|
+
/** Broker id the rest of the system addresses: `${deviceId}/${profile}`. */
|
|
4550
|
+
brokerId: zod.z.string(),
|
|
4551
|
+
/** `null` when the profile is unassigned. */
|
|
4552
|
+
sourceCamStreamId: zod.z.string().nullable(),
|
|
4553
|
+
status: ProfileSlotStatusSchema,
|
|
4554
|
+
resolution: CamStreamResolutionSchema.optional(),
|
|
4555
|
+
codec: zod.z.string().optional(),
|
|
4556
|
+
preBufferSec: zod.z.number().nonnegative().optional(),
|
|
4557
|
+
errorMessage: zod.z.string().optional()
|
|
4558
|
+
});
|
|
4559
|
+
/** The canonical consumer-facing broker id for a device profile. */
|
|
4560
|
+
function makeProfileBrokerId(deviceId, profile) {
|
|
4561
|
+
return `${deviceId}/${profile}`;
|
|
4562
|
+
}
|
|
4563
|
+
/**
|
|
4564
|
+
* The broker id keying a physical SOURCE stream: `${deviceId}/${camStreamId}`.
|
|
4565
|
+
* This is the broker's internal source key (`brokerIdFor` in the manager) — a
|
|
4566
|
+
* `camStreamId` like `native:main` — as opposed to the public profile alias
|
|
4567
|
+
* {@link makeProfileBrokerId}. Used to resolve a source's restream endpoint
|
|
4568
|
+
* (e.g. routing a transcode's ffmpeg input through the broker so it rides the
|
|
4569
|
+
* single source dial instead of opening a second camera connection).
|
|
4570
|
+
*/
|
|
4571
|
+
function makeSourceBrokerId(deviceId, camStreamId) {
|
|
4572
|
+
return `${deviceId}/${camStreamId}`;
|
|
4573
|
+
}
|
|
4574
|
+
/**
|
|
4575
|
+
* Inverse of {@link makeProfileBrokerId}. Returns `null` when the string is
|
|
4576
|
+
* not a canonical `${deviceId}/${profile}` id — e.g. a broker-internal
|
|
4577
|
+
* cam-stream id (`5/native:main`), a derived/adaptive ref, or a malformed
|
|
4578
|
+
* value. So a caller can safely distinguish "addresses a public profile"
|
|
4579
|
+
* from "addresses something broker-internal".
|
|
4580
|
+
*/
|
|
4581
|
+
function parseProfileBrokerId(brokerId) {
|
|
4582
|
+
const slash = brokerId.indexOf("/");
|
|
4583
|
+
if (slash <= 0) return null;
|
|
4584
|
+
const idPart = brokerId.slice(0, slash);
|
|
4585
|
+
const profilePart = brokerId.slice(slash + 1);
|
|
4586
|
+
if (!/^\d+$/.test(idPart)) return null;
|
|
4587
|
+
const parsed = CamProfileSchema.safeParse(profilePart);
|
|
4588
|
+
if (!parsed.success) return null;
|
|
4589
|
+
return {
|
|
4590
|
+
deviceId: Number(idPart),
|
|
4591
|
+
profile: parsed.data
|
|
4592
|
+
};
|
|
4593
|
+
}
|
|
4594
|
+
/**
|
|
4595
|
+
* The profile slots worth consuming/recording: ASSIGNED only
|
|
4596
|
+
* (`sourceCamStreamId != null`), DEDUPED by physical source so the same
|
|
4597
|
+
* camera encoder is never subscribed/recorded twice, ordered high→mid→low.
|
|
4598
|
+
* Optionally scoped to one `deviceId`. Pure; never mutates the input.
|
|
4599
|
+
*
|
|
4600
|
+
* Recording `main` and `mid` when both point at the same `sourceCamStreamId`
|
|
4601
|
+
* would dial the camera's internal stream twice for no benefit — this is the
|
|
4602
|
+
* dedup that prevents that.
|
|
4603
|
+
*/
|
|
4604
|
+
function selectAssignedProfileSlots(slots, deviceId) {
|
|
4605
|
+
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));
|
|
4606
|
+
const seenSources = /* @__PURE__ */ new Set();
|
|
4607
|
+
const out = [];
|
|
4608
|
+
for (const s of ordered) {
|
|
4609
|
+
const src = s.sourceCamStreamId;
|
|
4610
|
+
if (src === null) continue;
|
|
4611
|
+
if (seenSources.has(src)) continue;
|
|
4612
|
+
seenSources.add(src);
|
|
4613
|
+
out.push(s);
|
|
4614
|
+
}
|
|
4615
|
+
return out;
|
|
4616
|
+
}
|
|
4617
|
+
/**
|
|
4618
|
+
* Zod schema for StreamSourceEntry — the canonical stream descriptor
|
|
4619
|
+
* exposed by ICameraDevice.getStreamSources() and consumed by the broker.
|
|
4620
|
+
*/
|
|
4621
|
+
var StreamSourceEntrySchema$1 = zod.z.object({
|
|
3304
4622
|
id: zod.z.string(),
|
|
3305
4623
|
label: zod.z.string(),
|
|
3306
4624
|
protocol: zod.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 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
|
-
}
|
|
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
|
|
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
|
-
|
|
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`
|
|
@@ -6193,6 +7478,12 @@ Object.defineProperty(exports, "AUDIO_CHUNK_FORMATS", {
|
|
|
6193
7478
|
return AUDIO_CHUNK_FORMATS;
|
|
6194
7479
|
}
|
|
6195
7480
|
});
|
|
7481
|
+
Object.defineProperty(exports, "AdoptionPendingError", {
|
|
7482
|
+
enumerable: true,
|
|
7483
|
+
get: function() {
|
|
7484
|
+
return AdoptionPendingError;
|
|
7485
|
+
}
|
|
7486
|
+
});
|
|
6196
7487
|
Object.defineProperty(exports, "AudioChunkFormatSchema", {
|
|
6197
7488
|
enumerable: true,
|
|
6198
7489
|
get: function() {
|
|
@@ -6217,6 +7508,12 @@ Object.defineProperty(exports, "BaseAddon", {
|
|
|
6217
7508
|
return BaseAddon;
|
|
6218
7509
|
}
|
|
6219
7510
|
});
|
|
7511
|
+
Object.defineProperty(exports, "BatchTooLargeError", {
|
|
7512
|
+
enumerable: true,
|
|
7513
|
+
get: function() {
|
|
7514
|
+
return BatchTooLargeError;
|
|
7515
|
+
}
|
|
7516
|
+
});
|
|
6220
7517
|
Object.defineProperty(exports, "BrokerStatsSchema", {
|
|
6221
7518
|
enumerable: true,
|
|
6222
7519
|
get: function() {
|
|
@@ -6229,6 +7526,12 @@ Object.defineProperty(exports, "BrokerStatusSchema", {
|
|
|
6229
7526
|
return BrokerStatusSchema;
|
|
6230
7527
|
}
|
|
6231
7528
|
});
|
|
7529
|
+
Object.defineProperty(exports, "CALLER_STAMPED_CAPABILITIES", {
|
|
7530
|
+
enumerable: true,
|
|
7531
|
+
get: function() {
|
|
7532
|
+
return CALLER_STAMPED_CAPABILITIES;
|
|
7533
|
+
}
|
|
7534
|
+
});
|
|
6232
7535
|
Object.defineProperty(exports, "CAM_PROFILE_ORDER", {
|
|
6233
7536
|
enumerable: true,
|
|
6234
7537
|
get: function() {
|
|
@@ -6313,6 +7616,12 @@ Object.defineProperty(exports, "DEVICE_STATUS_METHOD", {
|
|
|
6313
7616
|
return DEVICE_STATUS_METHOD;
|
|
6314
7617
|
}
|
|
6315
7618
|
});
|
|
7619
|
+
Object.defineProperty(exports, "DeclarationRefusedError", {
|
|
7620
|
+
enumerable: true,
|
|
7621
|
+
get: function() {
|
|
7622
|
+
return DeclarationRefusedError;
|
|
7623
|
+
}
|
|
7624
|
+
});
|
|
6316
7625
|
Object.defineProperty(exports, "DecodedAudioChunkSchema", {
|
|
6317
7626
|
enumerable: true,
|
|
6318
7627
|
get: function() {
|
|
@@ -6325,6 +7634,12 @@ Object.defineProperty(exports, "DisposerChain", {
|
|
|
6325
7634
|
return DisposerChain;
|
|
6326
7635
|
}
|
|
6327
7636
|
});
|
|
7637
|
+
Object.defineProperty(exports, "EntryDescriptorSchema", {
|
|
7638
|
+
enumerable: true,
|
|
7639
|
+
get: function() {
|
|
7640
|
+
return EntryDescriptorSchema;
|
|
7641
|
+
}
|
|
7642
|
+
});
|
|
6328
7643
|
Object.defineProperty(exports, "ErrorCodeSchema", {
|
|
6329
7644
|
enumerable: true,
|
|
6330
7645
|
get: function() {
|
|
@@ -6337,6 +7652,18 @@ Object.defineProperty(exports, "ErrorI18nPayloadSchema", {
|
|
|
6337
7652
|
return ErrorI18nPayloadSchema;
|
|
6338
7653
|
}
|
|
6339
7654
|
});
|
|
7655
|
+
Object.defineProperty(exports, "FilterRequiredError", {
|
|
7656
|
+
enumerable: true,
|
|
7657
|
+
get: function() {
|
|
7658
|
+
return FilterRequiredError;
|
|
7659
|
+
}
|
|
7660
|
+
});
|
|
7661
|
+
Object.defineProperty(exports, "ForeignSecretMarkerError", {
|
|
7662
|
+
enumerable: true,
|
|
7663
|
+
get: function() {
|
|
7664
|
+
return ForeignSecretMarkerError;
|
|
7665
|
+
}
|
|
7666
|
+
});
|
|
6340
7667
|
Object.defineProperty(exports, "FrameHandleSchema", {
|
|
6341
7668
|
enumerable: true,
|
|
6342
7669
|
get: function() {
|
|
@@ -6367,6 +7694,12 @@ Object.defineProperty(exports, "HISTORY_UNIT_LABELS", {
|
|
|
6367
7694
|
return HISTORY_UNIT_LABELS;
|
|
6368
7695
|
}
|
|
6369
7696
|
});
|
|
7697
|
+
Object.defineProperty(exports, "InvalidRecordError", {
|
|
7698
|
+
enumerable: true,
|
|
7699
|
+
get: function() {
|
|
7700
|
+
return InvalidRecordError;
|
|
7701
|
+
}
|
|
7702
|
+
});
|
|
6370
7703
|
Object.defineProperty(exports, "KeychainWriteRefusedError", {
|
|
6371
7704
|
enumerable: true,
|
|
6372
7705
|
get: function() {
|
|
@@ -6385,6 +7718,12 @@ Object.defineProperty(exports, "MODEL_FORMATS", {
|
|
|
6385
7718
|
return MODEL_FORMATS;
|
|
6386
7719
|
}
|
|
6387
7720
|
});
|
|
7721
|
+
Object.defineProperty(exports, "NoCallerError", {
|
|
7722
|
+
enumerable: true,
|
|
7723
|
+
get: function() {
|
|
7724
|
+
return NoCallerError;
|
|
7725
|
+
}
|
|
7726
|
+
});
|
|
6388
7727
|
Object.defineProperty(exports, "PEER_BYTES_CHUNK_BYTES", {
|
|
6389
7728
|
enumerable: true,
|
|
6390
7729
|
get: function() {
|
|
@@ -6421,6 +7760,12 @@ Object.defineProperty(exports, "PeerBytesTicketSchema", {
|
|
|
6421
7760
|
return PeerBytesTicketSchema;
|
|
6422
7761
|
}
|
|
6423
7762
|
});
|
|
7763
|
+
Object.defineProperty(exports, "PlaintextSecretError", {
|
|
7764
|
+
enumerable: true,
|
|
7765
|
+
get: function() {
|
|
7766
|
+
return PlaintextSecretError;
|
|
7767
|
+
}
|
|
7768
|
+
});
|
|
6424
7769
|
Object.defineProperty(exports, "ProfileRtspEntrySchema", {
|
|
6425
7770
|
enumerable: true,
|
|
6426
7771
|
get: function() {
|
|
@@ -6439,12 +7784,108 @@ Object.defineProperty(exports, "ProfileSlotStatusSchema", {
|
|
|
6439
7784
|
return ProfileSlotStatusSchema;
|
|
6440
7785
|
}
|
|
6441
7786
|
});
|
|
7787
|
+
Object.defineProperty(exports, "RECORDS_ERROR_CODES", {
|
|
7788
|
+
enumerable: true,
|
|
7789
|
+
get: function() {
|
|
7790
|
+
return RECORDS_ERROR_CODES;
|
|
7791
|
+
}
|
|
7792
|
+
});
|
|
7793
|
+
Object.defineProperty(exports, "RECORD_BATCH_MAX", {
|
|
7794
|
+
enumerable: true,
|
|
7795
|
+
get: function() {
|
|
7796
|
+
return RECORD_BATCH_MAX;
|
|
7797
|
+
}
|
|
7798
|
+
});
|
|
7799
|
+
Object.defineProperty(exports, "RECORD_BATCH_MAX_BYTES", {
|
|
7800
|
+
enumerable: true,
|
|
7801
|
+
get: function() {
|
|
7802
|
+
return RECORD_BATCH_MAX_BYTES;
|
|
7803
|
+
}
|
|
7804
|
+
});
|
|
7805
|
+
Object.defineProperty(exports, "RECORD_CLASSES", {
|
|
7806
|
+
enumerable: true,
|
|
7807
|
+
get: function() {
|
|
7808
|
+
return RECORD_CLASSES;
|
|
7809
|
+
}
|
|
7810
|
+
});
|
|
7811
|
+
Object.defineProperty(exports, "RECORD_DATABASES", {
|
|
7812
|
+
enumerable: true,
|
|
7813
|
+
get: function() {
|
|
7814
|
+
return RECORD_DATABASES;
|
|
7815
|
+
}
|
|
7816
|
+
});
|
|
7817
|
+
Object.defineProperty(exports, "RECORD_DEFAULT_MAX_DATA_BYTES", {
|
|
7818
|
+
enumerable: true,
|
|
7819
|
+
get: function() {
|
|
7820
|
+
return RECORD_DEFAULT_MAX_DATA_BYTES;
|
|
7821
|
+
}
|
|
7822
|
+
});
|
|
7823
|
+
Object.defineProperty(exports, "RECORD_DELETE_BATCH", {
|
|
7824
|
+
enumerable: true,
|
|
7825
|
+
get: function() {
|
|
7826
|
+
return RECORD_DELETE_BATCH;
|
|
7827
|
+
}
|
|
7828
|
+
});
|
|
7829
|
+
Object.defineProperty(exports, "RECORD_ID_MAX_LENGTH", {
|
|
7830
|
+
enumerable: true,
|
|
7831
|
+
get: function() {
|
|
7832
|
+
return RECORD_ID_MAX_LENGTH;
|
|
7833
|
+
}
|
|
7834
|
+
});
|
|
7835
|
+
Object.defineProperty(exports, "RECORD_MAX_DATA_BYTES", {
|
|
7836
|
+
enumerable: true,
|
|
7837
|
+
get: function() {
|
|
7838
|
+
return RECORD_MAX_DATA_BYTES;
|
|
7839
|
+
}
|
|
7840
|
+
});
|
|
7841
|
+
Object.defineProperty(exports, "RECORD_MAX_INDEXES", {
|
|
7842
|
+
enumerable: true,
|
|
7843
|
+
get: function() {
|
|
7844
|
+
return RECORD_MAX_INDEXES;
|
|
7845
|
+
}
|
|
7846
|
+
});
|
|
7847
|
+
Object.defineProperty(exports, "RECORD_MAX_INDEX_FIELDS", {
|
|
7848
|
+
enumerable: true,
|
|
7849
|
+
get: function() {
|
|
7850
|
+
return RECORD_MAX_INDEX_FIELDS;
|
|
7851
|
+
}
|
|
7852
|
+
});
|
|
7853
|
+
Object.defineProperty(exports, "RECORD_QUERY_MAX", {
|
|
7854
|
+
enumerable: true,
|
|
7855
|
+
get: function() {
|
|
7856
|
+
return RECORD_QUERY_MAX;
|
|
7857
|
+
}
|
|
7858
|
+
});
|
|
7859
|
+
Object.defineProperty(exports, "RECORD_SECRET_COLLECTION_PREFIX", {
|
|
7860
|
+
enumerable: true,
|
|
7861
|
+
get: function() {
|
|
7862
|
+
return RECORD_SECRET_COLLECTION_PREFIX;
|
|
7863
|
+
}
|
|
7864
|
+
});
|
|
7865
|
+
Object.defineProperty(exports, "RECORD_SETTINGS_MAX_ROWS", {
|
|
7866
|
+
enumerable: true,
|
|
7867
|
+
get: function() {
|
|
7868
|
+
return RECORD_SETTINGS_MAX_ROWS;
|
|
7869
|
+
}
|
|
7870
|
+
});
|
|
7871
|
+
Object.defineProperty(exports, "RECORD_SWEEP_INTERVAL_MS", {
|
|
7872
|
+
enumerable: true,
|
|
7873
|
+
get: function() {
|
|
7874
|
+
return RECORD_SWEEP_INTERVAL_MS;
|
|
7875
|
+
}
|
|
7876
|
+
});
|
|
6442
7877
|
Object.defineProperty(exports, "REDACTED_SECRET", {
|
|
6443
7878
|
enumerable: true,
|
|
6444
7879
|
get: function() {
|
|
6445
7880
|
return REDACTED_SECRET;
|
|
6446
7881
|
}
|
|
6447
7882
|
});
|
|
7883
|
+
Object.defineProperty(exports, "REMOVE_LEAF", {
|
|
7884
|
+
enumerable: true,
|
|
7885
|
+
get: function() {
|
|
7886
|
+
return REMOVE_LEAF;
|
|
7887
|
+
}
|
|
7888
|
+
});
|
|
6448
7889
|
Object.defineProperty(exports, "REVALIDATE_AFTER_MS", {
|
|
6449
7890
|
enumerable: true,
|
|
6450
7891
|
get: function() {
|
|
@@ -6475,6 +7916,72 @@ Object.defineProperty(exports, "ReadinessTimeoutError", {
|
|
|
6475
7916
|
return ReadinessTimeoutError;
|
|
6476
7917
|
}
|
|
6477
7918
|
});
|
|
7919
|
+
Object.defineProperty(exports, "RecordFieldPathSchema", {
|
|
7920
|
+
enumerable: true,
|
|
7921
|
+
get: function() {
|
|
7922
|
+
return RecordFieldPathSchema;
|
|
7923
|
+
}
|
|
7924
|
+
});
|
|
7925
|
+
Object.defineProperty(exports, "RecordIndexSchema", {
|
|
7926
|
+
enumerable: true,
|
|
7927
|
+
get: function() {
|
|
7928
|
+
return RecordIndexSchema;
|
|
7929
|
+
}
|
|
7930
|
+
});
|
|
7931
|
+
Object.defineProperty(exports, "RecordKindDeclarationSchema", {
|
|
7932
|
+
enumerable: true,
|
|
7933
|
+
get: function() {
|
|
7934
|
+
return RecordKindDeclarationSchema;
|
|
7935
|
+
}
|
|
7936
|
+
});
|
|
7937
|
+
Object.defineProperty(exports, "RecordKindNameSchema", {
|
|
7938
|
+
enumerable: true,
|
|
7939
|
+
get: function() {
|
|
7940
|
+
return RecordKindNameSchema;
|
|
7941
|
+
}
|
|
7942
|
+
});
|
|
7943
|
+
Object.defineProperty(exports, "RecordNotFoundError", {
|
|
7944
|
+
enumerable: true,
|
|
7945
|
+
get: function() {
|
|
7946
|
+
return RecordNotFoundError;
|
|
7947
|
+
}
|
|
7948
|
+
});
|
|
7949
|
+
Object.defineProperty(exports, "RecordRetentionSchema", {
|
|
7950
|
+
enumerable: true,
|
|
7951
|
+
get: function() {
|
|
7952
|
+
return RecordRetentionSchema;
|
|
7953
|
+
}
|
|
7954
|
+
});
|
|
7955
|
+
Object.defineProperty(exports, "RecordSecretUnavailableError", {
|
|
7956
|
+
enumerable: true,
|
|
7957
|
+
get: function() {
|
|
7958
|
+
return RecordSecretUnavailableError;
|
|
7959
|
+
}
|
|
7960
|
+
});
|
|
7961
|
+
Object.defineProperty(exports, "RecordTooLargeError", {
|
|
7962
|
+
enumerable: true,
|
|
7963
|
+
get: function() {
|
|
7964
|
+
return RecordTooLargeError;
|
|
7965
|
+
}
|
|
7966
|
+
});
|
|
7967
|
+
Object.defineProperty(exports, "RecordUniqueViolationError", {
|
|
7968
|
+
enumerable: true,
|
|
7969
|
+
get: function() {
|
|
7970
|
+
return RecordUniqueViolationError;
|
|
7971
|
+
}
|
|
7972
|
+
});
|
|
7973
|
+
Object.defineProperty(exports, "RecordsError", {
|
|
7974
|
+
enumerable: true,
|
|
7975
|
+
get: function() {
|
|
7976
|
+
return RecordsError;
|
|
7977
|
+
}
|
|
7978
|
+
});
|
|
7979
|
+
Object.defineProperty(exports, "RevConflictError", {
|
|
7980
|
+
enumerable: true,
|
|
7981
|
+
get: function() {
|
|
7982
|
+
return RevConflictError;
|
|
7983
|
+
}
|
|
7984
|
+
});
|
|
6478
7985
|
Object.defineProperty(exports, "SECRET_CLEAR", {
|
|
6479
7986
|
enumerable: true,
|
|
6480
7987
|
get: function() {
|
|
@@ -6493,6 +8000,18 @@ Object.defineProperty(exports, "SECRET_REF_SCHEME", {
|
|
|
6493
8000
|
return SECRET_REF_SCHEME;
|
|
6494
8001
|
}
|
|
6495
8002
|
});
|
|
8003
|
+
Object.defineProperty(exports, "SETTINGS_ARRAY_ADOPTS_PREFIX", {
|
|
8004
|
+
enumerable: true,
|
|
8005
|
+
get: function() {
|
|
8006
|
+
return SETTINGS_ARRAY_ADOPTS_PREFIX;
|
|
8007
|
+
}
|
|
8008
|
+
});
|
|
8009
|
+
Object.defineProperty(exports, "SETTINGS_BROKERS_ADOPTS_PREFIX", {
|
|
8010
|
+
enumerable: true,
|
|
8011
|
+
get: function() {
|
|
8012
|
+
return SETTINGS_BROKERS_ADOPTS_PREFIX;
|
|
8013
|
+
}
|
|
8014
|
+
});
|
|
6496
8015
|
Object.defineProperty(exports, "SHARE_VIEW_KINDS", {
|
|
6497
8016
|
enumerable: true,
|
|
6498
8017
|
get: function() {
|
|
@@ -6523,6 +8042,18 @@ Object.defineProperty(exports, "SubscribeAudioChunksResultSchema", {
|
|
|
6523
8042
|
return SubscribeAudioChunksResultSchema;
|
|
6524
8043
|
}
|
|
6525
8044
|
});
|
|
8045
|
+
Object.defineProperty(exports, "UnindexedFilterError", {
|
|
8046
|
+
enumerable: true,
|
|
8047
|
+
get: function() {
|
|
8048
|
+
return UnindexedFilterError;
|
|
8049
|
+
}
|
|
8050
|
+
});
|
|
8051
|
+
Object.defineProperty(exports, "UnknownRecordKindError", {
|
|
8052
|
+
enumerable: true,
|
|
8053
|
+
get: function() {
|
|
8054
|
+
return UnknownRecordKindError;
|
|
8055
|
+
}
|
|
8056
|
+
});
|
|
6526
8057
|
Object.defineProperty(exports, "WELL_KNOWN_TABS", {
|
|
6527
8058
|
enumerable: true,
|
|
6528
8059
|
get: function() {
|
|
@@ -6535,6 +8066,12 @@ Object.defineProperty(exports, "WELL_KNOWN_TAB_MAP", {
|
|
|
6535
8066
|
return WELL_KNOWN_TAB_MAP;
|
|
6536
8067
|
}
|
|
6537
8068
|
});
|
|
8069
|
+
Object.defineProperty(exports, "addonSliceHandleApi", {
|
|
8070
|
+
enumerable: true,
|
|
8071
|
+
get: function() {
|
|
8072
|
+
return addonSliceHandleApi;
|
|
8073
|
+
}
|
|
8074
|
+
});
|
|
6538
8075
|
Object.defineProperty(exports, "adminUiCapability", {
|
|
6539
8076
|
enumerable: true,
|
|
6540
8077
|
get: function() {
|
|
@@ -6571,12 +8108,24 @@ Object.defineProperty(exports, "asNumber", {
|
|
|
6571
8108
|
return asNumber;
|
|
6572
8109
|
}
|
|
6573
8110
|
});
|
|
8111
|
+
Object.defineProperty(exports, "asRecordsError", {
|
|
8112
|
+
enumerable: true,
|
|
8113
|
+
get: function() {
|
|
8114
|
+
return asRecordsError;
|
|
8115
|
+
}
|
|
8116
|
+
});
|
|
6574
8117
|
Object.defineProperty(exports, "asString", {
|
|
6575
8118
|
enumerable: true,
|
|
6576
8119
|
get: function() {
|
|
6577
8120
|
return asString;
|
|
6578
8121
|
}
|
|
6579
8122
|
});
|
|
8123
|
+
Object.defineProperty(exports, "assertValidDeclaration", {
|
|
8124
|
+
enumerable: true,
|
|
8125
|
+
get: function() {
|
|
8126
|
+
return assertValidDeclaration;
|
|
8127
|
+
}
|
|
8128
|
+
});
|
|
6580
8129
|
Object.defineProperty(exports, "audioChunkBytesPerSample", {
|
|
6581
8130
|
enumerable: true,
|
|
6582
8131
|
get: function() {
|
|
@@ -6631,6 +8180,12 @@ Object.defineProperty(exports, "collectSecretConfigKeys", {
|
|
|
6631
8180
|
return collectSecretConfigKeys;
|
|
6632
8181
|
}
|
|
6633
8182
|
});
|
|
8183
|
+
Object.defineProperty(exports, "collectSecretLeaves", {
|
|
8184
|
+
enumerable: true,
|
|
8185
|
+
get: function() {
|
|
8186
|
+
return collectSecretLeaves;
|
|
8187
|
+
}
|
|
8188
|
+
});
|
|
6634
8189
|
Object.defineProperty(exports, "collectSecretMarkerRefs", {
|
|
6635
8190
|
enumerable: true,
|
|
6636
8191
|
get: function() {
|
|
@@ -6679,6 +8234,12 @@ Object.defineProperty(exports, "createMirrorSource", {
|
|
|
6679
8234
|
return createMirrorSource;
|
|
6680
8235
|
}
|
|
6681
8236
|
});
|
|
8237
|
+
Object.defineProperty(exports, "createRecordsAccess", {
|
|
8238
|
+
enumerable: true,
|
|
8239
|
+
get: function() {
|
|
8240
|
+
return createRecordsAccess;
|
|
8241
|
+
}
|
|
8242
|
+
});
|
|
6682
8243
|
Object.defineProperty(exports, "createSecretsAccess", {
|
|
6683
8244
|
enumerable: true,
|
|
6684
8245
|
get: function() {
|
|
@@ -6697,12 +8258,42 @@ Object.defineProperty(exports, "customAction", {
|
|
|
6697
8258
|
return customAction;
|
|
6698
8259
|
}
|
|
6699
8260
|
});
|
|
8261
|
+
Object.defineProperty(exports, "declarationsOf", {
|
|
8262
|
+
enumerable: true,
|
|
8263
|
+
get: function() {
|
|
8264
|
+
return declarationsOf;
|
|
8265
|
+
}
|
|
8266
|
+
});
|
|
6700
8267
|
Object.defineProperty(exports, "defineCustomActions", {
|
|
6701
8268
|
enumerable: true,
|
|
6702
8269
|
get: function() {
|
|
6703
8270
|
return defineCustomActions;
|
|
6704
8271
|
}
|
|
6705
8272
|
});
|
|
8273
|
+
Object.defineProperty(exports, "defineEntryKind", {
|
|
8274
|
+
enumerable: true,
|
|
8275
|
+
get: function() {
|
|
8276
|
+
return defineEntryKind;
|
|
8277
|
+
}
|
|
8278
|
+
});
|
|
8279
|
+
Object.defineProperty(exports, "defineRecordKinds", {
|
|
8280
|
+
enumerable: true,
|
|
8281
|
+
get: function() {
|
|
8282
|
+
return defineRecordKinds;
|
|
8283
|
+
}
|
|
8284
|
+
});
|
|
8285
|
+
Object.defineProperty(exports, "dehydrateConfigField", {
|
|
8286
|
+
enumerable: true,
|
|
8287
|
+
get: function() {
|
|
8288
|
+
return dehydrateConfigField;
|
|
8289
|
+
}
|
|
8290
|
+
});
|
|
8291
|
+
Object.defineProperty(exports, "dehydrateSchema", {
|
|
8292
|
+
enumerable: true,
|
|
8293
|
+
get: function() {
|
|
8294
|
+
return dehydrateSchema;
|
|
8295
|
+
}
|
|
8296
|
+
});
|
|
6706
8297
|
Object.defineProperty(exports, "describeCustomActions", {
|
|
6707
8298
|
enumerable: true,
|
|
6708
8299
|
get: function() {
|
|
@@ -6733,6 +8324,12 @@ Object.defineProperty(exports, "emitReadiness", {
|
|
|
6733
8324
|
return emitReadiness;
|
|
6734
8325
|
}
|
|
6735
8326
|
});
|
|
8327
|
+
Object.defineProperty(exports, "entryBody", {
|
|
8328
|
+
enumerable: true,
|
|
8329
|
+
get: function() {
|
|
8330
|
+
return entryBody;
|
|
8331
|
+
}
|
|
8332
|
+
});
|
|
6736
8333
|
Object.defineProperty(exports, "event", {
|
|
6737
8334
|
enumerable: true,
|
|
6738
8335
|
get: function() {
|
|
@@ -6781,6 +8378,12 @@ Object.defineProperty(exports, "hydrateSchema", {
|
|
|
6781
8378
|
return hydrateSchema;
|
|
6782
8379
|
}
|
|
6783
8380
|
});
|
|
8381
|
+
Object.defineProperty(exports, "invokeTrpcLeaf", {
|
|
8382
|
+
enumerable: true,
|
|
8383
|
+
get: function() {
|
|
8384
|
+
return invokeTrpcLeaf;
|
|
8385
|
+
}
|
|
8386
|
+
});
|
|
6784
8387
|
Object.defineProperty(exports, "isAudioChunkFormat", {
|
|
6785
8388
|
enumerable: true,
|
|
6786
8389
|
get: function() {
|
|
@@ -6865,6 +8468,12 @@ Object.defineProperty(exports, "knownSecretCount", {
|
|
|
6865
8468
|
return knownSecretCount;
|
|
6866
8469
|
}
|
|
6867
8470
|
});
|
|
8471
|
+
Object.defineProperty(exports, "makeInMemoryRecords", {
|
|
8472
|
+
enumerable: true,
|
|
8473
|
+
get: function() {
|
|
8474
|
+
return makeInMemoryRecords;
|
|
8475
|
+
}
|
|
8476
|
+
});
|
|
6868
8477
|
Object.defineProperty(exports, "makeProfileBrokerId", {
|
|
6869
8478
|
enumerable: true,
|
|
6870
8479
|
get: function() {
|
|
@@ -6883,6 +8492,12 @@ Object.defineProperty(exports, "makeSourceBrokerId", {
|
|
|
6883
8492
|
return makeSourceBrokerId;
|
|
6884
8493
|
}
|
|
6885
8494
|
});
|
|
8495
|
+
Object.defineProperty(exports, "mapSecretLeaves", {
|
|
8496
|
+
enumerable: true,
|
|
8497
|
+
get: function() {
|
|
8498
|
+
return mapSecretLeaves;
|
|
8499
|
+
}
|
|
8500
|
+
});
|
|
6886
8501
|
Object.defineProperty(exports, "maskUrlCredentials", {
|
|
6887
8502
|
enumerable: true,
|
|
6888
8503
|
get: function() {
|
|
@@ -6955,6 +8570,12 @@ Object.defineProperty(exports, "parseProfileBrokerId", {
|
|
|
6955
8570
|
return parseProfileBrokerId;
|
|
6956
8571
|
}
|
|
6957
8572
|
});
|
|
8573
|
+
Object.defineProperty(exports, "parseSecretPath", {
|
|
8574
|
+
enumerable: true,
|
|
8575
|
+
get: function() {
|
|
8576
|
+
return parseSecretPath;
|
|
8577
|
+
}
|
|
8578
|
+
});
|
|
6958
8579
|
Object.defineProperty(exports, "parseSecretRef", {
|
|
6959
8580
|
enumerable: true,
|
|
6960
8581
|
get: function() {
|
|
@@ -6967,6 +8588,18 @@ Object.defineProperty(exports, "parseSecretStatePath", {
|
|
|
6967
8588
|
return parseSecretStatePath;
|
|
6968
8589
|
}
|
|
6969
8590
|
});
|
|
8591
|
+
Object.defineProperty(exports, "parseSettingsArrayAdoptsFrom", {
|
|
8592
|
+
enumerable: true,
|
|
8593
|
+
get: function() {
|
|
8594
|
+
return parseSettingsArrayAdoptsFrom;
|
|
8595
|
+
}
|
|
8596
|
+
});
|
|
8597
|
+
Object.defineProperty(exports, "parseSettingsBrokersAdoptsFrom", {
|
|
8598
|
+
enumerable: true,
|
|
8599
|
+
get: function() {
|
|
8600
|
+
return parseSettingsBrokersAdoptsFrom;
|
|
8601
|
+
}
|
|
8602
|
+
});
|
|
6970
8603
|
Object.defineProperty(exports, "readErrorI18n", {
|
|
6971
8604
|
enumerable: true,
|
|
6972
8605
|
get: function() {
|
|
@@ -6985,6 +8618,30 @@ Object.defineProperty(exports, "readinessKey", {
|
|
|
6985
8618
|
return readinessKey;
|
|
6986
8619
|
}
|
|
6987
8620
|
});
|
|
8621
|
+
Object.defineProperty(exports, "recordArrayItemPath", {
|
|
8622
|
+
enumerable: true,
|
|
8623
|
+
get: function() {
|
|
8624
|
+
return recordArrayItemPath;
|
|
8625
|
+
}
|
|
8626
|
+
});
|
|
8627
|
+
Object.defineProperty(exports, "recordSecretCollection", {
|
|
8628
|
+
enumerable: true,
|
|
8629
|
+
get: function() {
|
|
8630
|
+
return recordSecretCollection;
|
|
8631
|
+
}
|
|
8632
|
+
});
|
|
8633
|
+
Object.defineProperty(exports, "recordSecretRef", {
|
|
8634
|
+
enumerable: true,
|
|
8635
|
+
get: function() {
|
|
8636
|
+
return recordSecretRef;
|
|
8637
|
+
}
|
|
8638
|
+
});
|
|
8639
|
+
Object.defineProperty(exports, "recordsErrorFromMessage", {
|
|
8640
|
+
enumerable: true,
|
|
8641
|
+
get: function() {
|
|
8642
|
+
return recordsErrorFromMessage;
|
|
8643
|
+
}
|
|
8644
|
+
});
|
|
6988
8645
|
Object.defineProperty(exports, "registerKnownSecret", {
|
|
6989
8646
|
enumerable: true,
|
|
6990
8647
|
get: function() {
|
|
@@ -7033,6 +8690,12 @@ Object.defineProperty(exports, "scrubKnownSecrets", {
|
|
|
7033
8690
|
return scrubKnownSecrets;
|
|
7034
8691
|
}
|
|
7035
8692
|
});
|
|
8693
|
+
Object.defineProperty(exports, "secretArrayPrefixes", {
|
|
8694
|
+
enumerable: true,
|
|
8695
|
+
get: function() {
|
|
8696
|
+
return secretArrayPrefixes;
|
|
8697
|
+
}
|
|
8698
|
+
});
|
|
7036
8699
|
Object.defineProperty(exports, "secretTreeFromPaths", {
|
|
7037
8700
|
enumerable: true,
|
|
7038
8701
|
get: function() {
|
|
@@ -7051,6 +8714,18 @@ Object.defineProperty(exports, "selectAssignedProfileSlots", {
|
|
|
7051
8714
|
return selectAssignedProfileSlots;
|
|
7052
8715
|
}
|
|
7053
8716
|
});
|
|
8717
|
+
Object.defineProperty(exports, "settingsArrayAdoptsFrom", {
|
|
8718
|
+
enumerable: true,
|
|
8719
|
+
get: function() {
|
|
8720
|
+
return settingsArrayAdoptsFrom;
|
|
8721
|
+
}
|
|
8722
|
+
});
|
|
8723
|
+
Object.defineProperty(exports, "settingsBrokersAdoptsFrom", {
|
|
8724
|
+
enumerable: true,
|
|
8725
|
+
get: function() {
|
|
8726
|
+
return settingsBrokersAdoptsFrom;
|
|
8727
|
+
}
|
|
8728
|
+
});
|
|
7054
8729
|
Object.defineProperty(exports, "shortSecretRefHash", {
|
|
7055
8730
|
enumerable: true,
|
|
7056
8731
|
get: function() {
|
|
@@ -7105,3 +8780,9 @@ Object.defineProperty(exports, "viewerUiCapability", {
|
|
|
7105
8780
|
return viewerUiCapability;
|
|
7106
8781
|
}
|
|
7107
8782
|
});
|
|
8783
|
+
Object.defineProperty(exports, "withoutCallerStamp", {
|
|
8784
|
+
enumerable: true,
|
|
8785
|
+
get: function() {
|
|
8786
|
+
return withoutCallerStamp;
|
|
8787
|
+
}
|
|
8788
|
+
});
|