@camstack/types 1.2.331 → 1.2.333
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/base-addon.d.ts +32 -0
- package/dist/addon/secret-aware-context.d.ts +49 -6
- package/dist/addon/secret-settings-view.d.ts +23 -1
- package/dist/addon/secret-write-back.d.ts +40 -0
- package/dist/addon.js +5 -7
- package/dist/addon.mjs +5 -7
- package/dist/auth/app-callback.d.ts +28 -0
- package/dist/auth/sso-state.d.ts +16 -0
- package/dist/capabilities/addon-routes.cap.d.ts +3 -0
- package/dist/capabilities/addons.cap.d.ts +4 -4
- package/dist/capabilities/backup.cap.d.ts +101 -1
- package/dist/capabilities/broker.cap.d.ts +4 -4
- package/dist/capabilities/custom-model-registry.cap.d.ts +520 -0
- package/dist/capabilities/device-manager.cap.d.ts +4 -4
- package/dist/capabilities/hub-address.d.ts +2 -2
- package/dist/capabilities/index.d.ts +12 -6
- package/dist/capabilities/keychain-admin.cap.d.ts +83 -0
- package/dist/capabilities/login-method.cap.d.ts +5 -6
- package/dist/capabilities/notification-output.cap.d.ts +4 -4
- package/dist/capabilities/notification-rules.cap.d.ts +6 -6
- package/dist/capabilities/osd-manager.cap.d.ts +5 -5
- package/dist/capabilities/pipeline-analytics.cap.d.ts +39 -8
- package/dist/capabilities/recording.cap.d.ts +3 -3
- package/dist/capabilities/server-management.cap.d.ts +5 -5
- package/dist/capabilities/snapshot.cap.d.ts +2 -2
- package/dist/capabilities/sso-bridge.cap.d.ts +5 -2
- package/dist/capabilities/training-provider.cap.d.ts +373 -0
- package/dist/capabilities/training.cap.d.ts +1896 -0
- package/dist/capabilities/user-management.cap.d.ts +1 -64
- package/dist/capabilities/videoclips.cap.d.ts +3 -3
- package/dist/client.js +26 -4
- package/dist/client.mjs +26 -4
- package/dist/generated/addon-api.d.ts +842 -173
- package/dist/generated/cap-input-defaults.d.ts +1 -1
- package/dist/generated/capability-router-map.d.ts +10 -4
- package/dist/generated/collection-array-methods.d.ts +1 -1
- 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 +5 -3
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1462 -93
- package/dist/index.mjs +1413 -92
- package/dist/interfaces/addon-routes.d.ts +7 -0
- package/dist/interfaces/addon.d.ts +8 -0
- package/dist/interfaces/auth.d.ts +6 -3
- package/dist/schemas/auth-records.d.ts +1 -2
- package/dist/{sleep-ClNXPpWR.js → sleep-DiQYrfm9.js} +425 -75
- package/dist/{sleep-DujUvOcb.mjs → sleep-r3RWkGVx.mjs} +425 -75
- package/dist/training/index.d.ts +1 -0
- package/dist/training/trainer-contract.d.ts +468 -0
- 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$3(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$3(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$3(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$3(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$3(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$2(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$2(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$2(value) && Object.prototype.hasOwnProperty.call(value, "$secret");
|
|
262
262
|
}
|
|
263
263
|
function isSecretClear(value) {
|
|
264
|
-
return isRecord$
|
|
264
|
+
return isRecord$2(value) && value["$secretClear"] === true;
|
|
265
265
|
}
|
|
266
266
|
function isSecretFieldView(value) {
|
|
267
|
-
return isRecord$
|
|
267
|
+
return isRecord$2(value) && value["set"] === true && isSecretMarkerLike(value);
|
|
268
268
|
}
|
|
269
269
|
/**
|
|
270
270
|
* The UI view of a stored secret field value: a marker becomes "set", inline
|
|
@@ -1018,7 +1018,7 @@ var KeychainWriteRefusedError = class extends Error {
|
|
|
1018
1018
|
}
|
|
1019
1019
|
};
|
|
1020
1020
|
var KEEP = { kind: "keep" };
|
|
1021
|
-
function isRecord(value) {
|
|
1021
|
+
function isRecord$1(value) {
|
|
1022
1022
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1023
1023
|
}
|
|
1024
1024
|
function defaultMintId() {
|
|
@@ -1031,7 +1031,7 @@ function collectSecretMarkerRefs(value, out = []) {
|
|
|
1031
1031
|
return out;
|
|
1032
1032
|
}
|
|
1033
1033
|
if (Array.isArray(value)) for (const item of value) collectSecretMarkerRefs(item, out);
|
|
1034
|
-
else if (isRecord(value)) for (const child of Object.values(value)) collectSecretMarkerRefs(child, out);
|
|
1034
|
+
else if (isRecord$1(value)) for (const child of Object.values(value)) collectSecretMarkerRefs(child, out);
|
|
1035
1035
|
return out;
|
|
1036
1036
|
}
|
|
1037
1037
|
async function storedValueEquals(secrets, marker, candidate) {
|
|
@@ -1086,7 +1086,7 @@ function rowId(row, idKey) {
|
|
|
1086
1086
|
return null;
|
|
1087
1087
|
}
|
|
1088
1088
|
async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
1089
|
-
const storedRows = Array.isArray(stored) ? stored.filter(isRecord) : [];
|
|
1089
|
+
const storedRows = Array.isArray(stored) ? stored.filter(isRecord$1) : [];
|
|
1090
1090
|
if (!Array.isArray(incoming)) {
|
|
1091
1091
|
ctx.deletes.push(...collectSecretMarkerRefs(storedRows));
|
|
1092
1092
|
return {
|
|
@@ -1102,7 +1102,7 @@ async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
|
1102
1102
|
const kept = /* @__PURE__ */ new Set();
|
|
1103
1103
|
const rows = [];
|
|
1104
1104
|
for (const row of incoming) {
|
|
1105
|
-
if (!isRecord(row)) {
|
|
1105
|
+
if (!isRecord$1(row)) {
|
|
1106
1106
|
rows.push(row);
|
|
1107
1107
|
continue;
|
|
1108
1108
|
}
|
|
@@ -1127,7 +1127,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
|
|
|
1127
1127
|
case "leaf": return writeLeaf(ctx, incoming, stored, fieldPath);
|
|
1128
1128
|
case "array": return writeArray(ctx, node, incoming, stored, fieldPath);
|
|
1129
1129
|
case "object": {
|
|
1130
|
-
if (!isRecord(incoming)) {
|
|
1130
|
+
if (!isRecord$1(incoming)) {
|
|
1131
1131
|
if (incoming === void 0) return KEEP;
|
|
1132
1132
|
ctx.deletes.push(...collectSecretMarkerRefs(stored));
|
|
1133
1133
|
return {
|
|
@@ -1135,7 +1135,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
|
|
|
1135
1135
|
value: incoming
|
|
1136
1136
|
};
|
|
1137
1137
|
}
|
|
1138
|
-
const storedObj = isRecord(stored) ? stored : {};
|
|
1138
|
+
const storedObj = isRecord$1(stored) ? stored : {};
|
|
1139
1139
|
return {
|
|
1140
1140
|
kind: "value",
|
|
1141
1141
|
value: await writeMembers(ctx, node.children, incoming, storedObj, (m) => `${fieldPath}.${m}`)
|
|
@@ -1194,12 +1194,19 @@ async function transformSecretWrite(input) {
|
|
|
1194
1194
|
}
|
|
1195
1195
|
};
|
|
1196
1196
|
}
|
|
1197
|
+
/** Is `ref` one of `owner`'s refs? */
|
|
1198
|
+
function isSecretRefOwnedBy(ref, owner) {
|
|
1199
|
+
return parseSecretRef(ref)?.owner === owner;
|
|
1200
|
+
}
|
|
1197
1201
|
/**
|
|
1198
1202
|
* Replace every marker in `value` with its keychain value. Returns the SAME
|
|
1199
1203
|
* reference when there is no marker (no allocation, no keychain call).
|
|
1200
1204
|
*/
|
|
1201
|
-
async function resolveSecretMarkers(value, secrets) {
|
|
1202
|
-
const
|
|
1205
|
+
async function resolveSecretMarkers(value, secrets, options = {}) {
|
|
1206
|
+
const keepMarker = options.unresolved === "keep-marker";
|
|
1207
|
+
const owner = options.ownedBy;
|
|
1208
|
+
const inScope = (ref) => owner === void 0 || isSecretRefOwnedBy(ref, owner);
|
|
1209
|
+
const refs = collectSecretMarkerRefs(value).filter(inScope);
|
|
1203
1210
|
if (refs.length === 0) return {
|
|
1204
1211
|
value,
|
|
1205
1212
|
unresolved: []
|
|
@@ -1223,10 +1230,18 @@ async function resolveSecretMarkers(value, secrets) {
|
|
|
1223
1230
|
}
|
|
1224
1231
|
const substitute = (v) => {
|
|
1225
1232
|
if (isSecretMarker(v)) {
|
|
1233
|
+
if (!inScope(v.$secret)) return {
|
|
1234
|
+
keep: true,
|
|
1235
|
+
value: v
|
|
1236
|
+
};
|
|
1226
1237
|
const answer = answers[v.$secret];
|
|
1227
|
-
|
|
1238
|
+
if (answer?.kind === "value") return {
|
|
1228
1239
|
keep: true,
|
|
1229
1240
|
value: answer.value
|
|
1241
|
+
};
|
|
1242
|
+
return keepMarker ? {
|
|
1243
|
+
keep: true,
|
|
1244
|
+
value: v
|
|
1230
1245
|
} : {
|
|
1231
1246
|
keep: false,
|
|
1232
1247
|
value: void 0
|
|
@@ -1243,7 +1258,7 @@ async function resolveSecretMarkers(value, secrets) {
|
|
|
1243
1258
|
value: items
|
|
1244
1259
|
};
|
|
1245
1260
|
}
|
|
1246
|
-
if (isRecord(v)) {
|
|
1261
|
+
if (isRecord$1(v)) {
|
|
1247
1262
|
const out = {};
|
|
1248
1263
|
for (const [k, child] of Object.entries(v)) {
|
|
1249
1264
|
const s = substitute(child);
|
|
@@ -1265,15 +1280,155 @@ async function resolveSecretMarkers(value, secrets) {
|
|
|
1265
1280
|
};
|
|
1266
1281
|
}
|
|
1267
1282
|
//#endregion
|
|
1268
|
-
//#region src/addon/secret-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1283
|
+
//#region src/addon/secret-write-back.ts
|
|
1284
|
+
/** An addon tried to replace a stored secret it could not read. Nothing was written. */
|
|
1285
|
+
var SecretOverwriteRefusedError = class extends Error {
|
|
1286
|
+
ref;
|
|
1287
|
+
reason;
|
|
1288
|
+
constructor(ref, reason) {
|
|
1289
|
+
super(`secret ${ref} was not replaced: its stored value cannot be read right now (${reason}), and an addon may not overwrite a secret it cannot see. Nothing was written.`);
|
|
1290
|
+
this.ref = ref;
|
|
1291
|
+
this.reason = reason;
|
|
1292
|
+
this.name = "SecretOverwriteRefusedError";
|
|
1293
|
+
}
|
|
1294
|
+
};
|
|
1295
|
+
function isRecord(value) {
|
|
1296
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1297
|
+
}
|
|
1298
|
+
function resolvedValue(pass, marker) {
|
|
1299
|
+
const answer = pass.answers[marker.$secret];
|
|
1300
|
+
return answer?.kind === "value" ? answer.value : null;
|
|
1301
|
+
}
|
|
1302
|
+
async function atMarker(pass, incoming, stored) {
|
|
1303
|
+
if (incoming === null) return stored;
|
|
1304
|
+
if (typeof incoming !== "string") return incoming;
|
|
1305
|
+
if (incoming === resolvedValue(pass, stored)) return stored;
|
|
1306
|
+
const intent = classifySecretWrite(incoming);
|
|
1307
|
+
if (intent.kind !== "set") return stored;
|
|
1308
|
+
const ref = stored.$secret;
|
|
1309
|
+
if (!isSecretRefOwnedBy(ref, pass.secrets.owner)) return incoming;
|
|
1310
|
+
const answer = pass.answers[ref];
|
|
1311
|
+
if ((answer === void 0 || answer.kind === "unavailable" || answer.kind === "forbidden") && !pass.operatorWrite) throw new SecretOverwriteRefusedError(ref, answer === void 0 ? "not-initialized" : answer.kind === "unavailable" ? answer.reason : answer.kind);
|
|
1312
|
+
try {
|
|
1313
|
+
await pass.secrets.put(ref, intent.value);
|
|
1314
|
+
} catch (err) {
|
|
1315
|
+
throw new KeychainWriteRefusedError(ref, err);
|
|
1316
|
+
}
|
|
1317
|
+
pass.changedRefs.push(ref);
|
|
1318
|
+
return stored;
|
|
1319
|
+
}
|
|
1320
|
+
function inArray(pass, incoming, stored) {
|
|
1321
|
+
return incoming.map((item, index) => {
|
|
1322
|
+
const twin = stored[index];
|
|
1323
|
+
if (isSecretMarker(twin)) return typeof item === "string" && item === resolvedValue(pass, twin) ? twin : item;
|
|
1324
|
+
if (isRecord(item) && isRecord(twin)) return inArrayRow(pass, item, twin);
|
|
1325
|
+
if (Array.isArray(item) && Array.isArray(twin)) return inArray(pass, item, twin);
|
|
1326
|
+
return item;
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
function inArrayRow(pass, incoming, stored) {
|
|
1330
|
+
const out = { ...incoming };
|
|
1331
|
+
for (const [key, value] of Object.entries(incoming)) {
|
|
1332
|
+
const twin = stored[key];
|
|
1333
|
+
if (isSecretMarker(twin)) {
|
|
1334
|
+
if (typeof value === "string" && value === resolvedValue(pass, twin)) out[key] = twin;
|
|
1335
|
+
} else if (isRecord(value) && isRecord(twin)) out[key] = inArrayRow(pass, value, twin);
|
|
1336
|
+
else if (Array.isArray(value) && Array.isArray(twin)) out[key] = inArray(pass, value, twin);
|
|
1337
|
+
}
|
|
1338
|
+
return out;
|
|
1339
|
+
}
|
|
1340
|
+
async function walk(pass, incoming, stored) {
|
|
1341
|
+
if (isSecretMarker(stored)) return atMarker(pass, incoming, stored);
|
|
1342
|
+
if (Array.isArray(incoming) && Array.isArray(stored)) return inArray(pass, incoming, stored);
|
|
1343
|
+
if (!isRecord(incoming) || !isRecord(stored)) return incoming;
|
|
1344
|
+
const out = { ...incoming };
|
|
1345
|
+
for (const [key, value] of Object.entries(incoming)) out[key] = await walk(pass, value, stored[key]);
|
|
1346
|
+
return out;
|
|
1347
|
+
}
|
|
1348
|
+
/** Restore markers a write-back carries as values. See the file doc. */
|
|
1349
|
+
async function restoreUnchangedSecrets(input) {
|
|
1350
|
+
const refs = [];
|
|
1351
|
+
for (const key of Object.keys(input.patch)) collectSecretMarkerRefs(input.stored[key], refs);
|
|
1352
|
+
const owned = refs.filter((ref) => isSecretRefOwnedBy(ref, input.secrets.owner));
|
|
1353
|
+
if (owned.length === 0) return {
|
|
1354
|
+
patch: input.patch,
|
|
1355
|
+
changedRefs: []
|
|
1356
|
+
};
|
|
1357
|
+
const pass = {
|
|
1358
|
+
secrets: input.secrets,
|
|
1359
|
+
answers: await input.secrets.resolve([...new Set(owned)]),
|
|
1360
|
+
operatorWrite: input.operatorWrite,
|
|
1361
|
+
changedRefs: []
|
|
1362
|
+
};
|
|
1363
|
+
const out = {};
|
|
1364
|
+
for (const [key, value] of Object.entries(input.patch)) out[key] = await walk(pass, value, input.stored[key]);
|
|
1365
|
+
return {
|
|
1366
|
+
patch: out,
|
|
1367
|
+
changedRefs: pass.changedRefs
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
/** Structural equality over JSON-shaped values (key order does not matter). */
|
|
1371
|
+
function isJsonEqual(a, b) {
|
|
1372
|
+
if (Object.is(a, b)) return true;
|
|
1373
|
+
if (Array.isArray(a)) return Array.isArray(b) && a.length === b.length && a.every((v, i) => isJsonEqual(v, b[i]));
|
|
1374
|
+
if (isRecord(a) && isRecord(b)) {
|
|
1375
|
+
const keys = Object.keys(a);
|
|
1376
|
+
if (keys.length !== Object.keys(b).length) return false;
|
|
1377
|
+
return keys.every((k) => Object.prototype.hasOwnProperty.call(b, k) && isJsonEqual(a[k], b[k]));
|
|
1274
1378
|
}
|
|
1275
1379
|
return false;
|
|
1276
1380
|
}
|
|
1381
|
+
/** The patch without the keys whose value already equals the stored one. */
|
|
1382
|
+
function dropUnchangedKeys(patch, stored) {
|
|
1383
|
+
const out = {};
|
|
1384
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
1385
|
+
if (Object.prototype.hasOwnProperty.call(stored, key) && isJsonEqual(value, stored[key])) continue;
|
|
1386
|
+
out[key] = value;
|
|
1387
|
+
}
|
|
1388
|
+
return out;
|
|
1389
|
+
}
|
|
1390
|
+
/** The top-level keys of a blob that hold at least one of `owner`'s markers. */
|
|
1391
|
+
function markerKeysOf(blob, owner) {
|
|
1392
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1393
|
+
for (const [key, value] of Object.entries(blob)) if (collectSecretMarkerRefs(value).some((ref) => isSecretRefOwnedBy(ref, owner))) keys.add(key);
|
|
1394
|
+
return keys;
|
|
1395
|
+
}
|
|
1396
|
+
function nodeFromStored(value, owner) {
|
|
1397
|
+
if (isSecretMarker(value)) return isSecretRefOwnedBy(value.$secret, owner) ? { kind: "leaf" } : null;
|
|
1398
|
+
if (!isRecord(value)) return null;
|
|
1399
|
+
const children = /* @__PURE__ */ new Map();
|
|
1400
|
+
for (const [key, child] of Object.entries(value)) {
|
|
1401
|
+
const node = nodeFromStored(child, owner);
|
|
1402
|
+
if (node !== null) children.set(key, node);
|
|
1403
|
+
}
|
|
1404
|
+
return children.size > 0 ? {
|
|
1405
|
+
kind: "object",
|
|
1406
|
+
children
|
|
1407
|
+
} : null;
|
|
1408
|
+
}
|
|
1409
|
+
/**
|
|
1410
|
+
* The declared secret tree, widened by every place the STORED blob holds a
|
|
1411
|
+
* marker under one of `keys` — so a marker the schema no longer declares (or
|
|
1412
|
+
* never declared: Wyze before b4906cec6) still gets the save path's
|
|
1413
|
+
* KEEP / SET / CLEAR semantics instead of being overwritten by whatever the
|
|
1414
|
+
* addon writes. Markers inside arrays are not added: a row has no id field to
|
|
1415
|
+
* match by unless the schema declares one. Only `owner`'s markers count: a
|
|
1416
|
+
* builtin that keeps another addon's marker (device-manager) never takes it
|
|
1417
|
+
* over.
|
|
1418
|
+
*/
|
|
1419
|
+
function widenTreeWithStoredMarkers(declared, stored, keys, owner) {
|
|
1420
|
+
const added = /* @__PURE__ */ new Map();
|
|
1421
|
+
for (const key of keys) {
|
|
1422
|
+
const at = key.indexOf("@");
|
|
1423
|
+
const base = at > 0 ? key.slice(0, at) : key;
|
|
1424
|
+
if (declared.has(base) || added.has(base)) continue;
|
|
1425
|
+
const node = nodeFromStored(stored[key], owner);
|
|
1426
|
+
if (node !== null) added.set(base, node);
|
|
1427
|
+
}
|
|
1428
|
+
return added.size === 0 ? declared : new Map([...declared, ...added]);
|
|
1429
|
+
}
|
|
1430
|
+
//#endregion
|
|
1431
|
+
//#region src/addon/secret-aware-context.ts
|
|
1277
1432
|
/** The blob as stored now; a failed read REFUSES the write instead of guessing. */
|
|
1278
1433
|
async function readStoredAddonBlob(raw) {
|
|
1279
1434
|
const threeWay = raw.readAddonStoreResult;
|
|
@@ -1282,7 +1437,41 @@ async function readStoredAddonBlob(raw) {
|
|
|
1282
1437
|
if (result.kind === "failed") throw new Error(`settings write refused: the stored blob could not be read (${result.error})`);
|
|
1283
1438
|
return result.kind === "missing" ? {} : result.value;
|
|
1284
1439
|
}
|
|
1285
|
-
function
|
|
1440
|
+
function touchesTree(tree, patch) {
|
|
1441
|
+
if (tree.size === 0) return false;
|
|
1442
|
+
for (const key of Object.keys(patch)) {
|
|
1443
|
+
const at = key.indexOf("@");
|
|
1444
|
+
if (tree.has(at > 0 ? key.slice(0, at) : key)) return true;
|
|
1445
|
+
}
|
|
1446
|
+
return false;
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* Which top-level keys of each store held markers when last seen. `undefined`
|
|
1450
|
+
* for a store not seen yet: its first write reads it, to be safe.
|
|
1451
|
+
*/
|
|
1452
|
+
var MarkerKeyIndex = class {
|
|
1453
|
+
owner;
|
|
1454
|
+
byStore = /* @__PURE__ */ new Map();
|
|
1455
|
+
constructor(owner) {
|
|
1456
|
+
this.owner = owner;
|
|
1457
|
+
}
|
|
1458
|
+
seen(store, blob) {
|
|
1459
|
+
this.byStore.set(store, markerKeysOf(blob, this.owner));
|
|
1460
|
+
}
|
|
1461
|
+
wrote(store, patch) {
|
|
1462
|
+
const keys = this.byStore.get(store);
|
|
1463
|
+
if (keys === void 0) return;
|
|
1464
|
+
const now = markerKeysOf(patch, this.owner);
|
|
1465
|
+
for (const key of Object.keys(patch)) if (now.has(key)) keys.add(key);
|
|
1466
|
+
else keys.delete(key);
|
|
1467
|
+
}
|
|
1468
|
+
mayHoldMarkers(store, patch) {
|
|
1469
|
+
const keys = this.byStore.get(store);
|
|
1470
|
+
if (keys === void 0) return true;
|
|
1471
|
+
return Object.keys(patch).some((key) => keys.has(key));
|
|
1472
|
+
}
|
|
1473
|
+
};
|
|
1474
|
+
function createHandle(raw, opts) {
|
|
1286
1475
|
const chains = /* @__PURE__ */ new Map();
|
|
1287
1476
|
const serialize = (key, fn) => {
|
|
1288
1477
|
const next = (chains.get(key) ?? Promise.resolve()).then(fn, fn);
|
|
@@ -1293,46 +1482,130 @@ function createSecretAwareSettings(raw, opts) {
|
|
|
1293
1482
|
});
|
|
1294
1483
|
return next;
|
|
1295
1484
|
};
|
|
1296
|
-
const
|
|
1297
|
-
|
|
1298
|
-
|
|
1485
|
+
const index = new MarkerKeyIndex(opts.secrets.owner);
|
|
1486
|
+
const resolveRead = async (store, blob) => {
|
|
1487
|
+
index.seen(store, blob);
|
|
1488
|
+
const { value, unresolved } = await resolveSecretMarkers(blob, opts.secrets, {
|
|
1489
|
+
unresolved: "keep-marker",
|
|
1490
|
+
ownedBy: opts.secrets.owner
|
|
1491
|
+
});
|
|
1492
|
+
if (unresolved.length > 0) opts.onUnresolved?.(unresolved);
|
|
1493
|
+
return value;
|
|
1494
|
+
};
|
|
1495
|
+
const write = async (store, declared, scope, patch, readStored, rawWrite) => {
|
|
1496
|
+
if (!touchesTree(declared, patch) && !index.mayHoldMarkers(store, patch)) {
|
|
1497
|
+
await rawWrite(patch);
|
|
1498
|
+
index.wrote(store, patch);
|
|
1499
|
+
return { changed: true };
|
|
1500
|
+
}
|
|
1501
|
+
return serialize(store, async () => {
|
|
1299
1502
|
const stored = await readStored();
|
|
1503
|
+
index.seen(store, stored);
|
|
1504
|
+
const operatorWrite = opts.isOperatorWrite?.() === true;
|
|
1505
|
+
const restored = await restoreUnchangedSecrets({
|
|
1506
|
+
patch,
|
|
1507
|
+
stored,
|
|
1508
|
+
secrets: opts.secrets,
|
|
1509
|
+
operatorWrite
|
|
1510
|
+
});
|
|
1300
1511
|
const result = await transformSecretWrite({
|
|
1301
|
-
tree,
|
|
1512
|
+
tree: widenTreeWithStoredMarkers(declared, stored, Object.keys(restored.patch), opts.secrets.owner),
|
|
1302
1513
|
secrets: opts.secrets,
|
|
1303
|
-
patch,
|
|
1514
|
+
patch: restored.patch,
|
|
1304
1515
|
stored,
|
|
1305
1516
|
...scope !== void 0 ? { scope } : {},
|
|
1306
|
-
operatorWrite
|
|
1517
|
+
operatorWrite
|
|
1307
1518
|
});
|
|
1308
|
-
|
|
1519
|
+
const effective = dropUnchangedKeys(result.patch, stored);
|
|
1520
|
+
const wroteBlob = Object.keys(effective).length > 0;
|
|
1521
|
+
if (wroteBlob) {
|
|
1522
|
+
await rawWrite(effective);
|
|
1523
|
+
index.wrote(store, effective);
|
|
1524
|
+
}
|
|
1309
1525
|
const { orphaned } = await result.afterWrite();
|
|
1310
1526
|
if (orphaned.length > 0) opts.onOrphaned(orphaned);
|
|
1527
|
+
return { changed: wroteBlob || restored.changedRefs.length > 0 };
|
|
1311
1528
|
});
|
|
1312
1529
|
};
|
|
1313
|
-
const
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1530
|
+
const writeAddon = (patch) => write("addon", opts.addonTree(), void 0, patch, () => readStoredAddonBlob(raw), (p) => raw.writeAddonStore(p));
|
|
1531
|
+
const readAddonStoreResult = raw.readAddonStoreResult;
|
|
1532
|
+
const readAddonStoreKeyResult = raw.readAddonStoreKeyResult;
|
|
1533
|
+
const readDeviceStoreBatch = raw.readDeviceStoreBatch;
|
|
1534
|
+
const overrides = {
|
|
1535
|
+
readAddonStore: async () => resolveRead("addon", await raw.readAddonStore()),
|
|
1536
|
+
...readAddonStoreResult !== void 0 ? { readAddonStoreResult: async () => {
|
|
1537
|
+
const result = await readAddonStoreResult.call(raw);
|
|
1538
|
+
return result.kind === "value" ? {
|
|
1539
|
+
kind: "value",
|
|
1540
|
+
value: await resolveRead("addon", result.value)
|
|
1541
|
+
} : result;
|
|
1542
|
+
} } : {},
|
|
1543
|
+
...readAddonStoreKeyResult !== void 0 ? { readAddonStoreKeyResult: async (key) => {
|
|
1544
|
+
const result = await readAddonStoreKeyResult.call(raw, key);
|
|
1545
|
+
if (result.kind !== "present") return result;
|
|
1546
|
+
const { value, unresolved } = await resolveSecretMarkers({ [key]: result.value }, opts.secrets, {
|
|
1547
|
+
unresolved: "keep-marker",
|
|
1548
|
+
ownedBy: opts.secrets.owner
|
|
1549
|
+
});
|
|
1550
|
+
if (unresolved.length > 0) opts.onUnresolved?.(unresolved);
|
|
1551
|
+
return {
|
|
1552
|
+
kind: "present",
|
|
1553
|
+
value: value[key]
|
|
1554
|
+
};
|
|
1555
|
+
} } : {},
|
|
1556
|
+
readDeviceStore: async (deviceId) => resolveRead(`device:${deviceId}`, await raw.readDeviceStore(deviceId)),
|
|
1557
|
+
...readDeviceStoreBatch !== void 0 ? { readDeviceStoreBatch: async (deviceIds) => {
|
|
1558
|
+
const rows = await readDeviceStoreBatch.call(raw, deviceIds);
|
|
1559
|
+
const out = /* @__PURE__ */ new Map();
|
|
1560
|
+
for (const [deviceId, blob] of rows) out.set(deviceId, await resolveRead(`device:${deviceId}`, blob));
|
|
1561
|
+
return out;
|
|
1562
|
+
} } : {},
|
|
1563
|
+
writeAddonStore: async (patch) => {
|
|
1564
|
+
await writeAddon(patch);
|
|
1565
|
+
},
|
|
1566
|
+
writeDeviceStore: async (deviceId, patch) => {
|
|
1567
|
+
await write(`device:${deviceId}`, opts.deviceTree(), {
|
|
1568
|
+
kind: "device",
|
|
1569
|
+
deviceId
|
|
1570
|
+
}, patch, () => raw.readDeviceStore(deviceId), (p) => raw.writeDeviceStore(deviceId, p));
|
|
1571
|
+
}
|
|
1572
|
+
};
|
|
1573
|
+
return {
|
|
1574
|
+
settings: new Proxy(raw, { get(target, prop, receiver) {
|
|
1575
|
+
if (typeof prop === "string" && Object.prototype.hasOwnProperty.call(overrides, prop)) return Reflect.get(overrides, prop);
|
|
1576
|
+
const value = Reflect.get(target, prop, receiver);
|
|
1577
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
1578
|
+
} }),
|
|
1579
|
+
raw: {
|
|
1580
|
+
readAddonStore: async () => {
|
|
1581
|
+
const blob = await raw.readAddonStore();
|
|
1582
|
+
index.seen("addon", blob);
|
|
1583
|
+
return blob;
|
|
1584
|
+
},
|
|
1585
|
+
readDeviceStore: async (deviceId) => {
|
|
1586
|
+
const blob = await raw.readDeviceStore(deviceId);
|
|
1587
|
+
index.seen(`device:${deviceId}`, blob);
|
|
1588
|
+
return blob;
|
|
1589
|
+
}
|
|
1590
|
+
},
|
|
1591
|
+
writeAddonStore: writeAddon
|
|
1592
|
+
};
|
|
1593
|
+
}
|
|
1594
|
+
/** The context the addon sees, plus the private raw view and write outcome. */
|
|
1595
|
+
function createSecretAwareContext(context, opts) {
|
|
1329
1596
|
const raw = context.settings;
|
|
1330
|
-
if (raw === void 0) return
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1597
|
+
if (raw === void 0) return {
|
|
1598
|
+
context,
|
|
1599
|
+
handle: null
|
|
1600
|
+
};
|
|
1601
|
+
const handle = createHandle(raw, opts);
|
|
1602
|
+
return {
|
|
1603
|
+
context: new Proxy(context, { get(target, prop, receiver) {
|
|
1604
|
+
if (prop === "settings") return handle.settings;
|
|
1605
|
+
return Reflect.get(target, prop, receiver);
|
|
1606
|
+
} }),
|
|
1607
|
+
handle
|
|
1608
|
+
};
|
|
1336
1609
|
}
|
|
1337
1610
|
//#endregion
|
|
1338
1611
|
//#region src/addon/secret-paths.ts
|
|
@@ -1524,6 +1797,14 @@ var BaseAddon = class {
|
|
|
1524
1797
|
_secretChangeUnsub = null;
|
|
1525
1798
|
/** >0 while an OPERATOR's settings write is being applied. */
|
|
1526
1799
|
_operatorWriteDepth = 0;
|
|
1800
|
+
/**
|
|
1801
|
+
* The keychain-aware settings handle (D798). Its `raw` view is the ONLY way
|
|
1802
|
+
* to the marker-bearing blobs and stays private to this class: the form
|
|
1803
|
+
* hydrate and config resolution need markers, addon code never does.
|
|
1804
|
+
*/
|
|
1805
|
+
_secretSettings = null;
|
|
1806
|
+
/** Refs an addon-facing read could not resolve — each is logged once per process. */
|
|
1807
|
+
_loggedUnresolvedReads = /* @__PURE__ */ new Set();
|
|
1527
1808
|
constructor(defaults) {
|
|
1528
1809
|
this.defaults = defaults;
|
|
1529
1810
|
this._config = { ...defaults };
|
|
@@ -1560,13 +1841,21 @@ var BaseAddon = class {
|
|
|
1560
1841
|
}
|
|
1561
1842
|
async initialize(context) {
|
|
1562
1843
|
const secrets = context.secrets;
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1844
|
+
if (secrets !== void 0) {
|
|
1845
|
+
const { context: wrapped, handle } = createSecretAwareContext(context, {
|
|
1846
|
+
secrets,
|
|
1847
|
+
addonTree: () => this.addonSecretTree(),
|
|
1848
|
+
deviceTree: () => this.deviceSecretTree(),
|
|
1849
|
+
onOrphaned: (refs) => context.logger.warn("keychain refs dropped by a settings write could not be deleted", { meta: { refs: [...refs] } }),
|
|
1850
|
+
isOperatorWrite: () => this._operatorWriteDepth > 0,
|
|
1851
|
+
onUnresolved: (unresolved) => this.logUnresolvedRead(unresolved)
|
|
1852
|
+
});
|
|
1853
|
+
this._ctx = wrapped;
|
|
1854
|
+
this._secretSettings = handle;
|
|
1855
|
+
} else {
|
|
1856
|
+
this._ctx = context;
|
|
1857
|
+
this._secretSettings = null;
|
|
1858
|
+
}
|
|
1570
1859
|
await this.resolveConfig();
|
|
1571
1860
|
if (secrets !== void 0) this._secretChangeUnsub = secrets.onChange((ref) => {
|
|
1572
1861
|
if (this._configSecretRefs.has(ref)) this.scheduleSecretReresolve(SECRET_CHANGE_DEBOUNCE_MS);
|
|
@@ -1683,11 +1972,8 @@ var BaseAddon = class {
|
|
|
1683
1972
|
async getGlobalSettings(overlay, cap, nodeId) {
|
|
1684
1973
|
const schema = this.globalSettingsSchema(cap);
|
|
1685
1974
|
if (!schema) return { sections: [] };
|
|
1686
|
-
const projected = await this.
|
|
1687
|
-
return hydrateSchema(schema, overlay ? {
|
|
1688
|
-
...projected,
|
|
1689
|
-
...overlay
|
|
1690
|
-
} : projected, { inlineSecretsAsViews: true });
|
|
1975
|
+
const projected = await this.readRawProjectedStore(nodeId, cap);
|
|
1976
|
+
return hydrateSchema(schema, overlay ? await this.overlayKeepingMarkers(projected, overlay) : projected, { inlineSecretsAsViews: true });
|
|
1691
1977
|
}
|
|
1692
1978
|
/**
|
|
1693
1979
|
* The integration-level view of this addon's settings: exactly the sections
|
|
@@ -1732,7 +2018,7 @@ var BaseAddon = class {
|
|
|
1732
2018
|
});
|
|
1733
2019
|
}
|
|
1734
2020
|
if (sections.length === 0) return null;
|
|
1735
|
-
const projected = await this.
|
|
2021
|
+
const projected = await this.readRawProjectedStore(nodeId);
|
|
1736
2022
|
return hydrateSchema({
|
|
1737
2023
|
...schema,
|
|
1738
2024
|
sections
|
|
@@ -1749,12 +2035,50 @@ var BaseAddon = class {
|
|
|
1749
2035
|
* the store for custom option logic (option narrowing, value snapping) to
|
|
1750
2036
|
* read it per-node — never `ctx.settings.readAddonStore()` directly.
|
|
1751
2037
|
* `nodeId` omitted ⇒ the local node (node-blind injection from ctx).
|
|
2038
|
+
*
|
|
2039
|
+
* Keychain values come back RESOLVED (D798): a secret reads as its value,
|
|
2040
|
+
* never as a `{ $secret }` marker. One the keychain cannot serve right now
|
|
2041
|
+
* stays a marker — "stored, unavailable" (`isSecretMarker()` is true, and it
|
|
2042
|
+
* is listed in {@link unresolvedSecrets}) — never `''` and never absent, so
|
|
2043
|
+
* it cannot be mistaken for "nothing stored, mint a new one". Writing the
|
|
2044
|
+
* resolved blob back is a no-op for every unchanged secret.
|
|
1752
2045
|
*/
|
|
1753
2046
|
async resolveGlobalStore(nodeId, cap) {
|
|
1754
2047
|
const raw = await this._ctx?.settings?.readAddonStore() ?? {};
|
|
2048
|
+
return this.projectForNode(raw, nodeId, cap);
|
|
2049
|
+
}
|
|
2050
|
+
projectForNode(store, nodeId, cap) {
|
|
1755
2051
|
const keys = this.perNodeKeys(cap);
|
|
1756
2052
|
const node = normalizeNodeId(nodeId ?? this._ctx?.kernel?.localNodeId);
|
|
1757
|
-
return keys.size > 0 ? projectStore(
|
|
2053
|
+
return keys.size > 0 ? projectStore(store, keys, node) : store;
|
|
2054
|
+
}
|
|
2055
|
+
/** The PROJECTED store with its markers — the form hydrate only (D798). */
|
|
2056
|
+
async readRawProjectedStore(nodeId, cap) {
|
|
2057
|
+
const raw = await this.rawSettings()?.readAddonStore() ?? {};
|
|
2058
|
+
return this.projectForNode(raw, nodeId, cap);
|
|
2059
|
+
}
|
|
2060
|
+
/**
|
|
2061
|
+
* `{ ...stored, ...overlay }`, except that an overlay member equal to the
|
|
2062
|
+
* RESOLVED stored one keeps the stored (marker-bearing) member — so a form
|
|
2063
|
+
* hydrated from a resolved overlay still shows a secret as "set", never as
|
|
2064
|
+
* its value.
|
|
2065
|
+
*/
|
|
2066
|
+
async overlayKeepingMarkers(stored, overlay) {
|
|
2067
|
+
const secrets = this._ctx?.secrets;
|
|
2068
|
+
const merged = {
|
|
2069
|
+
...stored,
|
|
2070
|
+
...overlay
|
|
2071
|
+
};
|
|
2072
|
+
if (secrets === void 0 || collectSecretMarkerRefs(stored).length === 0) return merged;
|
|
2073
|
+
const { value: resolved } = await resolveSecretMarkers(stored, secrets, {
|
|
2074
|
+
unresolved: "keep-marker",
|
|
2075
|
+
ownedBy: secrets.owner
|
|
2076
|
+
});
|
|
2077
|
+
for (const key of Object.keys(overlay)) {
|
|
2078
|
+
if (collectSecretMarkerRefs(stored[key]).length === 0) continue;
|
|
2079
|
+
if (isJsonEqual(overlay[key], resolved[key])) merged[key] = stored[key];
|
|
2080
|
+
}
|
|
2081
|
+
return merged;
|
|
1758
2082
|
}
|
|
1759
2083
|
/**
|
|
1760
2084
|
* Whether ONE global key of this addon's store was written, read three-way
|
|
@@ -1819,8 +2143,12 @@ var BaseAddon = class {
|
|
|
1819
2143
|
async clearSecrets(keys, nodeId) {
|
|
1820
2144
|
const tree = this.addonSecretTree();
|
|
1821
2145
|
const keychain = this._ctx?.secrets !== void 0;
|
|
2146
|
+
const stored = keychain ? await this.readAddonStoreWithRetry() : {};
|
|
1822
2147
|
const patch = {};
|
|
1823
|
-
for (const key of keys)
|
|
2148
|
+
for (const key of keys) {
|
|
2149
|
+
const keychainStored = tree.has(key) || collectSecretMarkerRefs(stored[key]).length > 0;
|
|
2150
|
+
patch[key] = keychain && keychainStored ? SECRET_CLEAR : "";
|
|
2151
|
+
}
|
|
1824
2152
|
await this.applyGlobalPatch(patch, nodeId);
|
|
1825
2153
|
}
|
|
1826
2154
|
async applyGlobalPatch(barePatch, nodeId) {
|
|
@@ -1828,7 +2156,11 @@ var BaseAddon = class {
|
|
|
1828
2156
|
const localNode = normalizeNodeId(this._ctx?.kernel?.localNodeId);
|
|
1829
2157
|
const target = normalizeNodeId(nodeId ?? this._ctx?.kernel?.localNodeId);
|
|
1830
2158
|
const scoped = keys.size > 0 ? scopePatch(barePatch, keys, target) : barePatch;
|
|
1831
|
-
|
|
2159
|
+
const handle = this._secretSettings;
|
|
2160
|
+
if (handle !== null) {
|
|
2161
|
+
const { changed } = await handle.writeAddonStore(scoped);
|
|
2162
|
+
if (!changed) return;
|
|
2163
|
+
} else await this._ctx?.settings?.writeAddonStore(scoped);
|
|
1832
2164
|
if (target !== localNode) return;
|
|
1833
2165
|
await this.resolveConfig();
|
|
1834
2166
|
await this.onConfigChanged();
|
|
@@ -1881,7 +2213,7 @@ var BaseAddon = class {
|
|
|
1881
2213
|
async getDeviceSettings(deviceId) {
|
|
1882
2214
|
const schema = this.deviceSettingsSchema();
|
|
1883
2215
|
if (!schema) return { sections: [] };
|
|
1884
|
-
return hydrateSchema(schema, await this.
|
|
2216
|
+
return hydrateSchema(schema, await this.rawSettings()?.readDeviceStore(deviceId) ?? {}, { inlineSecretsAsViews: true });
|
|
1885
2217
|
}
|
|
1886
2218
|
async updateDeviceSettings(deviceId, patch) {
|
|
1887
2219
|
await this._ctx?.settings?.writeDeviceStore(deviceId, patch);
|
|
@@ -2053,7 +2385,7 @@ var BaseAddon = class {
|
|
|
2053
2385
|
key,
|
|
2054
2386
|
schema,
|
|
2055
2387
|
fallback,
|
|
2056
|
-
read: async () => this.resolveStoredSecrets(await this.
|
|
2388
|
+
read: async () => this.resolveStoredSecrets(await this.rawSettings()?.readDeviceStore(deviceId) ?? {}, false),
|
|
2057
2389
|
write: async (patch) => {
|
|
2058
2390
|
await this._ctx?.settings?.writeDeviceStore(deviceId, patch);
|
|
2059
2391
|
},
|
|
@@ -2115,6 +2447,23 @@ var BaseAddon = class {
|
|
|
2115
2447
|
}
|
|
2116
2448
|
return value;
|
|
2117
2449
|
}
|
|
2450
|
+
/**
|
|
2451
|
+
* The marker-bearing settings reads (D798) — private on purpose. Without a
|
|
2452
|
+
* keychain the context's own view is already raw.
|
|
2453
|
+
*/
|
|
2454
|
+
rawSettings() {
|
|
2455
|
+
return this._secretSettings?.raw ?? this._ctx?.settings;
|
|
2456
|
+
}
|
|
2457
|
+
/** An addon-facing read met markers it could not resolve: say so once per ref. */
|
|
2458
|
+
logUnresolvedRead(unresolved) {
|
|
2459
|
+
const fresh = unresolved.filter((u) => !this._loggedUnresolvedReads.has(u.ref));
|
|
2460
|
+
if (fresh.length === 0) return;
|
|
2461
|
+
for (const u of fresh) this._loggedUnresolvedReads.add(u.ref);
|
|
2462
|
+
this._ctx?.logger?.warn?.("settings read: a stored secret is unavailable — it reads as its marker, not as a value", { meta: { secrets: fresh.map((u) => ({
|
|
2463
|
+
ref: u.ref,
|
|
2464
|
+
reason: u.reason
|
|
2465
|
+
})) } });
|
|
2466
|
+
}
|
|
2118
2467
|
/** Re-resolve the config (a keychain-only change, or a retry) and apply it. */
|
|
2119
2468
|
scheduleSecretReresolve(delayMs) {
|
|
2120
2469
|
const timerOf = delayMs === SECRET_CHANGE_DEBOUNCE_MS ? "_secretChangeTimer" : "_secretRetryTimer";
|
|
@@ -2141,7 +2490,7 @@ var BaseAddon = class {
|
|
|
2141
2490
|
* `{}` (defaults) — the addon's first successful patch will rehydrate.
|
|
2142
2491
|
*/
|
|
2143
2492
|
async readAddonStoreWithRetry() {
|
|
2144
|
-
const settings = this.
|
|
2493
|
+
const settings = this.rawSettings();
|
|
2145
2494
|
if (!settings) return {};
|
|
2146
2495
|
const delaysMs = [
|
|
2147
2496
|
150,
|
|
@@ -4709,6 +5058,7 @@ function createDeviceProxy(api, binding, opts) {
|
|
|
4709
5058
|
getRetrainExportUrl: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getRetrainExportUrl", "query", input),
|
|
4710
5059
|
setRetrainFrameComplete: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "setRetrainFrameComplete", "mutation", input),
|
|
4711
5060
|
writeRetrainArchive: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "writeRetrainArchive", "mutation", input),
|
|
5061
|
+
offerRetrainArchive: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "offerRetrainArchive", "mutation", input),
|
|
4712
5062
|
previewRetrainDataset: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "previewRetrainDataset", "query", input),
|
|
4713
5063
|
createRetrainDatasetVersion: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "createRetrainDatasetVersion", "mutation", input),
|
|
4714
5064
|
listRetrainDatasetVersions: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRetrainDatasetVersions", "query", input),
|