@camstack/addon-provider-rademacher 0.2.127 → 0.2.129
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.js +1627 -134
- package/dist/addon.mjs +1627 -134
- package/package.json +1 -1
package/dist/addon.mjs
CHANGED
|
@@ -983,7 +983,7 @@ var Rademacher = class {
|
|
|
983
983
|
}
|
|
984
984
|
};
|
|
985
985
|
//#endregion
|
|
986
|
-
//#region ../types/dist/event-category-
|
|
986
|
+
//#region ../types/dist/event-category-DOl51-Ij.mjs
|
|
987
987
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
988
988
|
EventCategory["SystemBoot"] = "system.boot";
|
|
989
989
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -1047,6 +1047,33 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
1047
1047
|
* consumes this category and maps it to the `addon-crash-loop` kind.
|
|
1048
1048
|
*/
|
|
1049
1049
|
EventCategory["AddonRunnerFailed"] = "addon.runner-failed";
|
|
1050
|
+
/**
|
|
1051
|
+
* A runner whose addon refused to start with a typed reason (D877) - parked
|
|
1052
|
+
* in `refused`, never counted by the crash breaker, retried on operator
|
|
1053
|
+
* action. One event per refusal.
|
|
1054
|
+
*/
|
|
1055
|
+
EventCategory["AddonRunnerRefused"] = "addon.runner-refused";
|
|
1056
|
+
/**
|
|
1057
|
+
* A runner settled on a state (D877): `running` (READY), `crashed`, `failed` or
|
|
1058
|
+
* `refused`. In-process telemetry for the boot check (re-evaluate while any
|
|
1059
|
+
* runner is still pending) and the alert centre (close a recovered runner).
|
|
1060
|
+
*/
|
|
1061
|
+
EventCategory["ProcessStateChanged"] = "process.state-changed";
|
|
1062
|
+
/**
|
|
1063
|
+
* The node's one-shot runner boot check (D877): planned runners against the
|
|
1064
|
+
* process service, `degraded` when any is failed, refused or missing. The
|
|
1065
|
+
* alert centre turns it into one critical alert.
|
|
1066
|
+
*/
|
|
1067
|
+
EventCategory["SystemRunnerCheck"] = "system.runner-check";
|
|
1068
|
+
/**
|
|
1069
|
+
* An alert EPISODE opened or closed, emitted by the alert centre for alerts
|
|
1070
|
+
* of severity `critical` or `error` (`AlertEpisodePayload`). The alert
|
|
1071
|
+
* centre sends no notification of its own: Notification Center turns this
|
|
1072
|
+
* into the `alert-critical` / `alert-error` / `alert-critical-resolved`
|
|
1073
|
+
* system-event kinds, and reconciles from the alerts store because a bus
|
|
1074
|
+
* event may be dropped (D8, D11).
|
|
1075
|
+
*/
|
|
1076
|
+
EventCategory["AlertEpisode"] = "alert.episode";
|
|
1050
1077
|
EventCategory["AddonError"] = "addon.error";
|
|
1051
1078
|
EventCategory["AddonPageReady"] = "addon.page-ready";
|
|
1052
1079
|
EventCategory["AddonWidgetReady"] = "addon.widget-ready";
|
|
@@ -6371,7 +6398,7 @@ var ZodIssueCode = {
|
|
|
6371
6398
|
var ZodFirstPartyTypeKind;
|
|
6372
6399
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6373
6400
|
//#endregion
|
|
6374
|
-
//#region ../types/dist/sleep-
|
|
6401
|
+
//#region ../types/dist/sleep-BxjU_fJM.mjs
|
|
6375
6402
|
/**
|
|
6376
6403
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6377
6404
|
* window to float samples (D455).
|
|
@@ -6488,7 +6515,7 @@ function isKeychainStoredField(field) {
|
|
|
6488
6515
|
var SECRET_CLEAR = { $secretClear: true };
|
|
6489
6516
|
/** The `'***'` token D634 redaction writes for non-admins. */
|
|
6490
6517
|
var LEGACY_DEVICE_REDACTION = "***";
|
|
6491
|
-
function isRecord$
|
|
6518
|
+
function isRecord$5(value) {
|
|
6492
6519
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6493
6520
|
}
|
|
6494
6521
|
function makeSecretMarker(ref) {
|
|
@@ -6499,12 +6526,12 @@ function makeSecretMarker(ref) {
|
|
|
6499
6526
|
}
|
|
6500
6527
|
/** A stored marker: an object whose `$secret` is a non-empty string. */
|
|
6501
6528
|
function isSecretMarker(value) {
|
|
6502
|
-
if (!isRecord$
|
|
6529
|
+
if (!isRecord$5(value)) return false;
|
|
6503
6530
|
const ref = value["$secret"];
|
|
6504
6531
|
return typeof ref === "string" && ref.length > 0;
|
|
6505
6532
|
}
|
|
6506
6533
|
function isSecretClear(value) {
|
|
6507
|
-
return isRecord$
|
|
6534
|
+
return isRecord$5(value) && value["$secretClear"] === true;
|
|
6508
6535
|
}
|
|
6509
6536
|
/**
|
|
6510
6537
|
* The UI view of a stored secret field value: a marker becomes "set", inline
|
|
@@ -7114,7 +7141,7 @@ var KeychainWriteRefusedError = class extends Error {
|
|
|
7114
7141
|
}
|
|
7115
7142
|
};
|
|
7116
7143
|
var KEEP = { kind: "keep" };
|
|
7117
|
-
function isRecord$
|
|
7144
|
+
function isRecord$4(value) {
|
|
7118
7145
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7119
7146
|
}
|
|
7120
7147
|
function defaultMintId() {
|
|
@@ -7127,7 +7154,7 @@ function collectSecretMarkerRefs(value, out = []) {
|
|
|
7127
7154
|
return out;
|
|
7128
7155
|
}
|
|
7129
7156
|
if (Array.isArray(value)) for (const item of value) collectSecretMarkerRefs(item, out);
|
|
7130
|
-
else if (isRecord$
|
|
7157
|
+
else if (isRecord$4(value)) for (const child of Object.values(value)) collectSecretMarkerRefs(child, out);
|
|
7131
7158
|
return out;
|
|
7132
7159
|
}
|
|
7133
7160
|
async function storedValueEquals(secrets, marker, candidate) {
|
|
@@ -7182,7 +7209,7 @@ function rowId(row, idKey) {
|
|
|
7182
7209
|
return null;
|
|
7183
7210
|
}
|
|
7184
7211
|
async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
7185
|
-
const storedRows = Array.isArray(stored) ? stored.filter(isRecord$
|
|
7212
|
+
const storedRows = Array.isArray(stored) ? stored.filter(isRecord$4) : [];
|
|
7186
7213
|
if (!Array.isArray(incoming)) {
|
|
7187
7214
|
ctx.deletes.push(...collectSecretMarkerRefs(storedRows));
|
|
7188
7215
|
return {
|
|
@@ -7198,7 +7225,7 @@ async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
|
7198
7225
|
const kept = /* @__PURE__ */ new Set();
|
|
7199
7226
|
const rows = [];
|
|
7200
7227
|
for (const row of incoming) {
|
|
7201
|
-
if (!isRecord$
|
|
7228
|
+
if (!isRecord$4(row)) {
|
|
7202
7229
|
rows.push(row);
|
|
7203
7230
|
continue;
|
|
7204
7231
|
}
|
|
@@ -7223,7 +7250,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
|
|
|
7223
7250
|
case "leaf": return writeLeaf(ctx, incoming, stored, fieldPath);
|
|
7224
7251
|
case "array": return writeArray(ctx, node, incoming, stored, fieldPath);
|
|
7225
7252
|
case "object": {
|
|
7226
|
-
if (!isRecord$
|
|
7253
|
+
if (!isRecord$4(incoming)) {
|
|
7227
7254
|
if (incoming === void 0) return KEEP;
|
|
7228
7255
|
ctx.deletes.push(...collectSecretMarkerRefs(stored));
|
|
7229
7256
|
return {
|
|
@@ -7231,7 +7258,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
|
|
|
7231
7258
|
value: incoming
|
|
7232
7259
|
};
|
|
7233
7260
|
}
|
|
7234
|
-
const storedObj = isRecord$
|
|
7261
|
+
const storedObj = isRecord$4(stored) ? stored : {};
|
|
7235
7262
|
return {
|
|
7236
7263
|
kind: "value",
|
|
7237
7264
|
value: await writeMembers(ctx, node.children, incoming, storedObj, (m) => `${fieldPath}.${m}`)
|
|
@@ -7354,7 +7381,7 @@ async function resolveSecretMarkers(value, secrets, options = {}) {
|
|
|
7354
7381
|
value: items
|
|
7355
7382
|
};
|
|
7356
7383
|
}
|
|
7357
|
-
if (isRecord$
|
|
7384
|
+
if (isRecord$4(v)) {
|
|
7358
7385
|
const out = {};
|
|
7359
7386
|
for (const [k, child] of Object.entries(v)) {
|
|
7360
7387
|
const s = substitute(child);
|
|
@@ -7386,7 +7413,7 @@ var SecretOverwriteRefusedError = class extends Error {
|
|
|
7386
7413
|
this.name = "SecretOverwriteRefusedError";
|
|
7387
7414
|
}
|
|
7388
7415
|
};
|
|
7389
|
-
function isRecord(value) {
|
|
7416
|
+
function isRecord$3(value) {
|
|
7390
7417
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7391
7418
|
}
|
|
7392
7419
|
function resolvedValue(pass, marker) {
|
|
@@ -7415,7 +7442,7 @@ function inArray(pass, incoming, stored) {
|
|
|
7415
7442
|
return incoming.map((item, index) => {
|
|
7416
7443
|
const twin = stored[index];
|
|
7417
7444
|
if (isSecretMarker(twin)) return typeof item === "string" && item === resolvedValue(pass, twin) ? twin : item;
|
|
7418
|
-
if (isRecord(item) && isRecord(twin)) return inArrayRow(pass, item, twin);
|
|
7445
|
+
if (isRecord$3(item) && isRecord$3(twin)) return inArrayRow(pass, item, twin);
|
|
7419
7446
|
if (Array.isArray(item) && Array.isArray(twin)) return inArray(pass, item, twin);
|
|
7420
7447
|
return item;
|
|
7421
7448
|
});
|
|
@@ -7426,7 +7453,7 @@ function inArrayRow(pass, incoming, stored) {
|
|
|
7426
7453
|
const twin = stored[key];
|
|
7427
7454
|
if (isSecretMarker(twin)) {
|
|
7428
7455
|
if (typeof value === "string" && value === resolvedValue(pass, twin)) out[key] = twin;
|
|
7429
|
-
} else if (isRecord(value) && isRecord(twin)) out[key] = inArrayRow(pass, value, twin);
|
|
7456
|
+
} else if (isRecord$3(value) && isRecord$3(twin)) out[key] = inArrayRow(pass, value, twin);
|
|
7430
7457
|
else if (Array.isArray(value) && Array.isArray(twin)) out[key] = inArray(pass, value, twin);
|
|
7431
7458
|
}
|
|
7432
7459
|
return out;
|
|
@@ -7434,7 +7461,7 @@ function inArrayRow(pass, incoming, stored) {
|
|
|
7434
7461
|
async function walk(pass, incoming, stored) {
|
|
7435
7462
|
if (isSecretMarker(stored)) return atMarker(pass, incoming, stored);
|
|
7436
7463
|
if (Array.isArray(incoming) && Array.isArray(stored)) return inArray(pass, incoming, stored);
|
|
7437
|
-
if (!isRecord(incoming) || !isRecord(stored)) return incoming;
|
|
7464
|
+
if (!isRecord$3(incoming) || !isRecord$3(stored)) return incoming;
|
|
7438
7465
|
const out = { ...incoming };
|
|
7439
7466
|
for (const [key, value] of Object.entries(incoming)) out[key] = await walk(pass, value, stored[key]);
|
|
7440
7467
|
return out;
|
|
@@ -7465,7 +7492,7 @@ async function restoreUnchangedSecrets(input) {
|
|
|
7465
7492
|
function isJsonEqual(a, b) {
|
|
7466
7493
|
if (Object.is(a, b)) return true;
|
|
7467
7494
|
if (Array.isArray(a)) return Array.isArray(b) && a.length === b.length && a.every((v, i) => isJsonEqual(v, b[i]));
|
|
7468
|
-
if (isRecord(a) && isRecord(b)) {
|
|
7495
|
+
if (isRecord$3(a) && isRecord$3(b)) {
|
|
7469
7496
|
const keys = Object.keys(a);
|
|
7470
7497
|
if (keys.length !== Object.keys(b).length) return false;
|
|
7471
7498
|
return keys.every((k) => Object.prototype.hasOwnProperty.call(b, k) && isJsonEqual(a[k], b[k]));
|
|
@@ -7489,7 +7516,7 @@ function markerKeysOf(blob, owner) {
|
|
|
7489
7516
|
}
|
|
7490
7517
|
function nodeFromStored(value, owner) {
|
|
7491
7518
|
if (isSecretMarker(value)) return isSecretRefOwnedBy(value.$secret, owner) ? { kind: "leaf" } : null;
|
|
7492
|
-
if (!isRecord(value)) return null;
|
|
7519
|
+
if (!isRecord$3(value)) return null;
|
|
7493
7520
|
const children = /* @__PURE__ */ new Map();
|
|
7494
7521
|
for (const [key, child] of Object.entries(value)) {
|
|
7495
7522
|
const node = nodeFromStored(child, owner);
|
|
@@ -7622,7 +7649,6 @@ function createHandle(raw, opts) {
|
|
|
7622
7649
|
const writeAddon = (patch) => write("addon", opts.addonTree(), void 0, patch, () => readStoredAddonBlob(raw), (p) => raw.writeAddonStore(p));
|
|
7623
7650
|
const readAddonStoreResult = raw.readAddonStoreResult;
|
|
7624
7651
|
const readAddonStoreKeyResult = raw.readAddonStoreKeyResult;
|
|
7625
|
-
const readDeviceStoreBatch = raw.readDeviceStoreBatch;
|
|
7626
7652
|
const overrides = {
|
|
7627
7653
|
readAddonStore: async () => resolveRead("addon", await raw.readAddonStore()),
|
|
7628
7654
|
...readAddonStoreResult !== void 0 ? { readAddonStoreResult: async () => {
|
|
@@ -7646,12 +7672,12 @@ function createHandle(raw, opts) {
|
|
|
7646
7672
|
};
|
|
7647
7673
|
} } : {},
|
|
7648
7674
|
readDeviceStore: async (deviceId) => resolveRead(`device:${deviceId}`, await raw.readDeviceStore(deviceId)),
|
|
7649
|
-
|
|
7650
|
-
const rows = await readDeviceStoreBatch
|
|
7675
|
+
readDeviceStoreBatch: async (deviceIds) => {
|
|
7676
|
+
const rows = await raw.readDeviceStoreBatch(deviceIds);
|
|
7651
7677
|
const out = /* @__PURE__ */ new Map();
|
|
7652
7678
|
for (const [deviceId, blob] of rows) out.set(deviceId, await resolveRead(`device:${deviceId}`, blob));
|
|
7653
7679
|
return out;
|
|
7654
|
-
}
|
|
7680
|
+
},
|
|
7655
7681
|
writeAddonStore: async (patch) => {
|
|
7656
7682
|
await writeAddon(patch);
|
|
7657
7683
|
},
|
|
@@ -8278,7 +8304,7 @@ var BaseAddon = class {
|
|
|
8278
8304
|
if (!ctx) return;
|
|
8279
8305
|
const addonId = ctx.id;
|
|
8280
8306
|
setImmediate(() => {
|
|
8281
|
-
ctx.api.addons
|
|
8307
|
+
ctx.api.addons.restartAddon.mutate({ addonId }).then(() => {
|
|
8282
8308
|
ctx.logger.info("addon auto-restart triggered by restart-required setting change", { meta: { changedFields: patchKeys.filter((k) => restartKeys.has(k)) } });
|
|
8283
8309
|
}).catch((err) => {
|
|
8284
8310
|
ctx.logger.error("addon auto-restart failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
@@ -8478,7 +8504,7 @@ var BaseAddon = class {
|
|
|
8478
8504
|
return this._addonSecretTree;
|
|
8479
8505
|
}
|
|
8480
8506
|
deviceSecretTree() {
|
|
8481
|
-
this._deviceSecretTree ??= secretTreeFromSchema(this.deviceSettingsSchema());
|
|
8507
|
+
this._deviceSecretTree ??= mergeSecretStatePaths(secretTreeFromSchema(this.deviceSettingsSchema()), this.secretStatePaths);
|
|
8482
8508
|
return this._deviceSecretTree;
|
|
8483
8509
|
}
|
|
8484
8510
|
/**
|
|
@@ -8554,42 +8580,135 @@ var BaseAddon = class {
|
|
|
8554
8580
|
this[timerOf] = timer;
|
|
8555
8581
|
}
|
|
8556
8582
|
/**
|
|
8557
|
-
* Wrap `ctx.settings.readAddonStore()` with a
|
|
8558
|
-
*
|
|
8559
|
-
* swap, or any race where the SqliteSettingsBackend is between shutdown and
|
|
8560
|
-
* re-initialize) doesn't propagate up into `initialize()` and leave the
|
|
8583
|
+
* Wrap `ctx.settings.readAddonStore()` with a retry budget so a transient
|
|
8584
|
+
* settings-store outage doesn't propagate up into `initialize()` and leave the
|
|
8561
8585
|
* addon permanently broken.
|
|
8562
8586
|
*
|
|
8563
|
-
*
|
|
8564
|
-
*
|
|
8565
|
-
* `
|
|
8587
|
+
* Two kinds of outage, two budgets:
|
|
8588
|
+
* - the store's own restart fingerprints (`SqliteSettingsBackend not
|
|
8589
|
+
* initialized`, `provider not available`): a short budget, then the addon
|
|
8590
|
+
* falls back to `{}` (defaults) - its first successful patch rehydrates;
|
|
8591
|
+
* - a TRANSPORT failure (the hub is restarting while this runner boots:
|
|
8592
|
+
* `discovery deadline exceeded`, `parent could not route`, a refused or
|
|
8593
|
+
* timed-out connection). Since D870 a runner's settings read THROWS instead
|
|
8594
|
+
* of answering `{}`, so without a budget a hub restart ends in a respawn
|
|
8595
|
+
* loop. A long, bounded budget; only after it the error propagates - the
|
|
8596
|
+
* addon never runs on defaults for a store it could not ask.
|
|
8597
|
+
* Anything else propagates immediately so real bugs surface.
|
|
8566
8598
|
*/
|
|
8567
8599
|
async readAddonStoreWithRetry() {
|
|
8568
8600
|
const settings = this.rawSettings();
|
|
8569
8601
|
if (!settings) return {};
|
|
8570
|
-
const delaysMs = [
|
|
8571
|
-
150,
|
|
8572
|
-
350,
|
|
8573
|
-
600,
|
|
8574
|
-
900
|
|
8575
|
-
];
|
|
8576
8602
|
let lastErr;
|
|
8577
|
-
for (let attempt = 0
|
|
8603
|
+
for (let attempt = 0;; attempt++) try {
|
|
8578
8604
|
const stored = await settings.readAddonStore() ?? {};
|
|
8579
8605
|
this.settingsStoreReady = true;
|
|
8580
8606
|
return stored;
|
|
8581
8607
|
} catch (err) {
|
|
8582
8608
|
lastErr = err;
|
|
8583
|
-
const
|
|
8584
|
-
if (
|
|
8585
|
-
|
|
8586
|
-
|
|
8609
|
+
const kind = classifyStoreError(err);
|
|
8610
|
+
if (kind === "permanent") throw err;
|
|
8611
|
+
const delay = (kind === "transport" ? TRANSPORT_RETRY_DELAYS_MS : RESTART_RETRY_DELAYS_MS)[attempt];
|
|
8612
|
+
if (delay === void 0) {
|
|
8613
|
+
if (kind === "transport") throw err;
|
|
8614
|
+
break;
|
|
8615
|
+
}
|
|
8616
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
8587
8617
|
}
|
|
8588
8618
|
this.settingsStoreReady = false;
|
|
8589
8619
|
this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
|
|
8590
8620
|
return {};
|
|
8591
8621
|
}
|
|
8592
8622
|
};
|
|
8623
|
+
/** The settings store's own restart fingerprints. */
|
|
8624
|
+
var RESTART_RETRY_DELAYS_MS = [
|
|
8625
|
+
150,
|
|
8626
|
+
350,
|
|
8627
|
+
600,
|
|
8628
|
+
900
|
|
8629
|
+
];
|
|
8630
|
+
/** A hub restarting under a booting runner: ~100 s in total. */
|
|
8631
|
+
var TRANSPORT_RETRY_DELAYS_MS = [
|
|
8632
|
+
150,
|
|
8633
|
+
350,
|
|
8634
|
+
600,
|
|
8635
|
+
900,
|
|
8636
|
+
2e3,
|
|
8637
|
+
5e3,
|
|
8638
|
+
1e4,
|
|
8639
|
+
2e4,
|
|
8640
|
+
3e4,
|
|
8641
|
+
3e4
|
|
8642
|
+
];
|
|
8643
|
+
var RESTART_FINGERPRINTS = ["SqliteSettingsBackend not initialized", "provider not available"];
|
|
8644
|
+
/** Node / socket error codes of a connection that did not happen or broke. */
|
|
8645
|
+
var TRANSPORT_CODES = new Set([
|
|
8646
|
+
"ECONNREFUSED",
|
|
8647
|
+
"ECONNRESET",
|
|
8648
|
+
"ETIMEDOUT",
|
|
8649
|
+
"EPIPE",
|
|
8650
|
+
"EHOSTUNREACH",
|
|
8651
|
+
"ENETUNREACH"
|
|
8652
|
+
]);
|
|
8653
|
+
/** tRPC error codes that mean "the other side is not answering now", not "your call is wrong". */
|
|
8654
|
+
var UNAVAILABLE_TRPC_CODES = new Set([
|
|
8655
|
+
"TIMEOUT",
|
|
8656
|
+
"SERVICE_UNAVAILABLE",
|
|
8657
|
+
"BAD_GATEWAY",
|
|
8658
|
+
"GATEWAY_TIMEOUT"
|
|
8659
|
+
]);
|
|
8660
|
+
/** The exact phrases OUR transport raises when it cannot reach the hub. */
|
|
8661
|
+
var TRANSPORT_PHRASES = [
|
|
8662
|
+
"discovery deadline exceeded",
|
|
8663
|
+
"parent could not route child unowned cap call",
|
|
8664
|
+
"UDS request timed out after",
|
|
8665
|
+
"channel closed"
|
|
8666
|
+
];
|
|
8667
|
+
/** Moleculer error `type`s of a call that could not be served right now. */
|
|
8668
|
+
var MOLECULER_TRANSIENT_TYPES = new Set([
|
|
8669
|
+
"REQUEST_TIMEOUT",
|
|
8670
|
+
"SERVICE_NOT_FOUND",
|
|
8671
|
+
"SERVICE_NOT_AVAILABLE",
|
|
8672
|
+
"REQUEST_REJECTED",
|
|
8673
|
+
"BROKER_DISCONNECTED"
|
|
8674
|
+
]);
|
|
8675
|
+
function stringProp(value, key) {
|
|
8676
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
8677
|
+
const found = Reflect.get(value, key);
|
|
8678
|
+
return typeof found === "string" ? found : void 0;
|
|
8679
|
+
}
|
|
8680
|
+
/** The code an error carries: its own, its cause's, or a tRPC `data.code`. */
|
|
8681
|
+
function errorCode(err) {
|
|
8682
|
+
const out = {};
|
|
8683
|
+
const cause = typeof err === "object" && err !== null ? Reflect.get(err, "cause") : void 0;
|
|
8684
|
+
const data = typeof err === "object" && err !== null ? Reflect.get(err, "data") : void 0;
|
|
8685
|
+
const node = stringProp(err, "code") ?? stringProp(cause, "code");
|
|
8686
|
+
if (node !== void 0) out.node = node;
|
|
8687
|
+
const trpc = stringProp(data, "code");
|
|
8688
|
+
if (trpc !== void 0) out.trpc = trpc;
|
|
8689
|
+
return out;
|
|
8690
|
+
}
|
|
8691
|
+
/**
|
|
8692
|
+
* Is a settings read failure worth retrying, and with which budget? Only
|
|
8693
|
+
* EXPLICIT signals count: a socket error code, a tRPC "unavailable" code, or
|
|
8694
|
+
* one of the exact phrases our own transport raises. A message that merely
|
|
8695
|
+
* contains "timed out" or "unreachable" is not evidence of anything, and
|
|
8696
|
+
* `settings store not wired` is a wiring bug that retrying cannot fix.
|
|
8697
|
+
*/
|
|
8698
|
+
function classifyStoreError(err) {
|
|
8699
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8700
|
+
if (RESTART_FINGERPRINTS.some((f) => message.includes(f))) return "restart";
|
|
8701
|
+
const code = errorCode(err);
|
|
8702
|
+
if (code.node !== void 0 && TRANSPORT_CODES.has(code.node)) return "transport";
|
|
8703
|
+
if (code.trpc !== void 0 && UNAVAILABLE_TRPC_CODES.has(code.trpc)) return "transport";
|
|
8704
|
+
if (typeof err === "object" && err !== null) {
|
|
8705
|
+
if (Reflect.get(err, "retryable") === true) return "transport";
|
|
8706
|
+
const type = stringProp(err, "type");
|
|
8707
|
+
if (type !== void 0 && MOLECULER_TRANSIENT_TYPES.has(type)) return "transport";
|
|
8708
|
+
}
|
|
8709
|
+
if (TRANSPORT_PHRASES.some((f) => message.includes(f))) return "transport";
|
|
8710
|
+
return "permanent";
|
|
8711
|
+
}
|
|
8593
8712
|
/**
|
|
8594
8713
|
* Collect the keys of every field marked `perNode: true`, recursing into
|
|
8595
8714
|
* layout containers (`group` fields and `sub-tabs` tabs) the same way
|
|
@@ -8679,6 +8798,156 @@ var PeerBytesTicketSchema = object({
|
|
|
8679
8798
|
*/
|
|
8680
8799
|
declaredBytes: number().int().nonnegative().nullable()
|
|
8681
8800
|
});
|
|
8801
|
+
/** Limits and names of `ctx.records` (D881). One authority; the engine and the facade read it. */
|
|
8802
|
+
/** The files a kind may live in. `history` is device-history's (D850), never records. */
|
|
8803
|
+
var RECORD_DATABASES = ["settings", "events"];
|
|
8804
|
+
/** The classes of a kind: the `@durable` vocabulary, one authority (replaces the annotation). */
|
|
8805
|
+
var RECORD_CLASSES = [
|
|
8806
|
+
"config",
|
|
8807
|
+
"ledger",
|
|
8808
|
+
"audit",
|
|
8809
|
+
"mirror",
|
|
8810
|
+
"ephemeral"
|
|
8811
|
+
];
|
|
8812
|
+
var RECORD_DEFAULT_MAX_DATA_BYTES = 64 * 1024;
|
|
8813
|
+
var RECORD_MAX_DATA_BYTES = 1024 * 1024;
|
|
8814
|
+
var RECORD_BATCH_MAX = 1e3;
|
|
8815
|
+
var RECORD_QUERY_MAX = 1e3;
|
|
8816
|
+
function defOf(schema) {
|
|
8817
|
+
const zodBag = Reflect.get(schema, "_zod");
|
|
8818
|
+
if (typeof zodBag !== "object" || zodBag === null) return {};
|
|
8819
|
+
const def = Reflect.get(zodBag, "def");
|
|
8820
|
+
if (typeof def !== "object" || def === null) return {};
|
|
8821
|
+
return def;
|
|
8822
|
+
}
|
|
8823
|
+
function declaredHere(schema) {
|
|
8824
|
+
return globalRegistry.get(schema)?.secret === true;
|
|
8825
|
+
}
|
|
8826
|
+
/** Wrapper kinds whose `innerType` is the field itself. */
|
|
8827
|
+
var WRAPPERS = new Set([
|
|
8828
|
+
"optional",
|
|
8829
|
+
"nullable",
|
|
8830
|
+
"default",
|
|
8831
|
+
"prefault",
|
|
8832
|
+
"catch",
|
|
8833
|
+
"readonly",
|
|
8834
|
+
"nonoptional"
|
|
8835
|
+
]);
|
|
8836
|
+
/**
|
|
8837
|
+
* The schema layers that make up ONE field: the schema itself and every
|
|
8838
|
+
* wrapper below it (optional / default / nullable / readonly / catch), plus
|
|
8839
|
+
* both sides of a pipe (`z.preprocess` puts the real schema on `out`,
|
|
8840
|
+
* `.transform` on `in`).
|
|
8841
|
+
*/
|
|
8842
|
+
function layersOf(schema) {
|
|
8843
|
+
const out = [];
|
|
8844
|
+
const queue = [schema];
|
|
8845
|
+
while (queue.length > 0) {
|
|
8846
|
+
const s = queue.shift();
|
|
8847
|
+
if (!s || out.includes(s)) continue;
|
|
8848
|
+
out.push(s);
|
|
8849
|
+
const def = defOf(s);
|
|
8850
|
+
if (def.type !== void 0 && WRAPPERS.has(def.type) && def.innerType) queue.push(def.innerType);
|
|
8851
|
+
if (def.type === "pipe") {
|
|
8852
|
+
if (def.in) queue.push(def.in);
|
|
8853
|
+
if (def.out) queue.push(def.out);
|
|
8854
|
+
}
|
|
8855
|
+
}
|
|
8856
|
+
return out;
|
|
8857
|
+
}
|
|
8858
|
+
/** True when any layer of this field declares `.meta({ secret: true })`. */
|
|
8859
|
+
function isZodSecret(schema) {
|
|
8860
|
+
return layersOf(schema).some(declaredHere);
|
|
8861
|
+
}
|
|
8862
|
+
/**
|
|
8863
|
+
* Every declared secret path in a config schema: dotted keys, `[]` for "each
|
|
8864
|
+
* element of this array" (`connection.password`, `rows[].token`). A declared
|
|
8865
|
+
* object or array is reported as one path and not descended into — everything
|
|
8866
|
+
* under it is secret.
|
|
8867
|
+
*/
|
|
8868
|
+
function collectZodSecretPaths(schema, prefix = "") {
|
|
8869
|
+
if (isZodSecret(schema)) return prefix.length > 0 ? [prefix] : [];
|
|
8870
|
+
const paths = [];
|
|
8871
|
+
for (const layer of layersOf(schema)) {
|
|
8872
|
+
const def = defOf(layer);
|
|
8873
|
+
if (def.type === "object" && def.shape) for (const [key, child] of Object.entries(def.shape)) paths.push(...collectZodSecretPaths(child, prefix ? `${prefix}.${key}` : key));
|
|
8874
|
+
else if (def.type === "array" && def.element) paths.push(...collectZodSecretPaths(def.element, `${prefix}[]`));
|
|
8875
|
+
else if (def.type === "union" && def.options) for (const option of def.options) paths.push(...collectZodSecretPaths(option, prefix));
|
|
8876
|
+
else if (def.type === "intersection") {
|
|
8877
|
+
if (def.left) paths.push(...collectZodSecretPaths(def.left, prefix));
|
|
8878
|
+
if (def.right) paths.push(...collectZodSecretPaths(def.right, prefix));
|
|
8879
|
+
}
|
|
8880
|
+
}
|
|
8881
|
+
return [...new Set(paths)];
|
|
8882
|
+
}
|
|
8883
|
+
/**
|
|
8884
|
+
* Record kinds (D881): the declaration an addon makes of one kind of fact, the
|
|
8885
|
+
* Zod row schema that describes it, and the helper that turns the two into the
|
|
8886
|
+
* JSON the engine stores.
|
|
8887
|
+
*
|
|
8888
|
+
* A kind is declared ONCE, next to the code that owns it, and the engine's
|
|
8889
|
+
* reconciler creates its indexes - nothing creates DDL at runtime from a write.
|
|
8890
|
+
* Everything the generic machinery needs (secret fields, the entry descriptor)
|
|
8891
|
+
* is DERIVED from the Zod schema: `.meta({ secret: true })` marks a credential,
|
|
8892
|
+
* never a field name (D879).
|
|
8893
|
+
*/
|
|
8894
|
+
/** A JSON field path: `trackId`, `auth.accessToken`. Charset-restricted: it is rendered into DDL. */
|
|
8895
|
+
var RecordFieldPathSchema = string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,63}(\.[A-Za-z_][A-Za-z0-9_]{0,63}){0,3}$/);
|
|
8896
|
+
var RecordIndexSchema = object({
|
|
8897
|
+
name: string().regex(/^[a-z][a-z0-9_]{0,31}$/),
|
|
8898
|
+
fields: array(RecordFieldPathSchema).min(1).max(4),
|
|
8899
|
+
unique: boolean().optional()
|
|
8900
|
+
}).strict();
|
|
8901
|
+
var RecordRetentionSchema = union([
|
|
8902
|
+
object({
|
|
8903
|
+
ttlMs: number().int().positive(),
|
|
8904
|
+
from: _enum(["at", "write"])
|
|
8905
|
+
}).strict(),
|
|
8906
|
+
object({
|
|
8907
|
+
maxRows: number().int().positive().optional(),
|
|
8908
|
+
maxRowsPerDevice: number().int().positive().optional()
|
|
8909
|
+
}).strict().refine((r) => r.maxRows !== void 0 || r.maxRowsPerDevice !== void 0, { message: "name maxRows, maxRowsPerDevice or both" }),
|
|
8910
|
+
object({
|
|
8911
|
+
owner: string().min(1),
|
|
8912
|
+
reason: string().min(1)
|
|
8913
|
+
}).strict(),
|
|
8914
|
+
object({ none: string().min(1) }).strict()
|
|
8915
|
+
]);
|
|
8916
|
+
/** The descriptor a generic entries UI reads (D881 "generic entries"). */
|
|
8917
|
+
var EntryDescriptorSchema = object({
|
|
8918
|
+
title: string().min(1),
|
|
8919
|
+
/** The record body field shown as the entry's name. */
|
|
8920
|
+
nameField: string().min(1),
|
|
8921
|
+
/** JSON Schema of the entry body; `secret: true` marks a password field. */
|
|
8922
|
+
fields: record(string(), unknown())
|
|
8923
|
+
}).strict();
|
|
8924
|
+
/** What crosses the wire and sits in the engine's catalog: JSON only, no Zod. */
|
|
8925
|
+
var RecordKindDeclarationSchema = object({
|
|
8926
|
+
database: _enum(RECORD_DATABASES).default("settings"),
|
|
8927
|
+
class: _enum(RECORD_CLASSES),
|
|
8928
|
+
writeTrigger: string().min(1),
|
|
8929
|
+
device: _enum([
|
|
8930
|
+
"required",
|
|
8931
|
+
"optional",
|
|
8932
|
+
"none"
|
|
8933
|
+
]).default("none"),
|
|
8934
|
+
at: _enum(["required", "none"]).default("none"),
|
|
8935
|
+
indexes: array(RecordIndexSchema).max(8).default([]),
|
|
8936
|
+
retention: RecordRetentionSchema,
|
|
8937
|
+
deviceRemoval: _enum(["delete", "none"]).default("none"),
|
|
8938
|
+
maxDataBytes: number().int().positive().max(RECORD_MAX_DATA_BYTES).default(RECORD_DEFAULT_MAX_DATA_BYTES),
|
|
8939
|
+
/** Derived from the Zod schema; never written by hand. */
|
|
8940
|
+
secretPaths: array(string().min(1)).default([]),
|
|
8941
|
+
/** The id key of each array that carries a secret (`{ headers: 'name' }`). */
|
|
8942
|
+
secretArrayKeys: record(string(), string()).default({}),
|
|
8943
|
+
/** The legacy table this kind adopts from; the boot guard reads it (D853: no migration code). */
|
|
8944
|
+
adoptsFrom: string().min(1).optional(),
|
|
8945
|
+
/** Kinds that must agree through `transact` sit in one file under one family name. */
|
|
8946
|
+
transactFamily: string().min(1).optional(),
|
|
8947
|
+
entry: EntryDescriptorSchema.optional()
|
|
8948
|
+
}).strict();
|
|
8949
|
+
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
8950
|
+
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
8682
8951
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8683
8952
|
var CamProfileSchema = _enum([
|
|
8684
8953
|
"high",
|
|
@@ -9143,75 +9412,12 @@ method(object({ deviceId: number() }), array(StreamSourceEntrySchema)), method(o
|
|
|
9143
9412
|
kind: "mutation",
|
|
9144
9413
|
auth: "admin"
|
|
9145
9414
|
}), method(object({ deviceId: number() }), unknown().nullable()), method(object({ deviceId: number() }), RawStateResultSchema.nullable(), { auth: "protected" });
|
|
9146
|
-
function defOf(schema) {
|
|
9147
|
-
return schema._zod?.def ?? {};
|
|
9148
|
-
}
|
|
9149
|
-
function declaredHere(schema) {
|
|
9150
|
-
return globalRegistry.get(schema)?.secret === true;
|
|
9151
|
-
}
|
|
9152
|
-
/** Wrapper kinds whose `innerType` is the field itself. */
|
|
9153
|
-
var WRAPPERS = new Set([
|
|
9154
|
-
"optional",
|
|
9155
|
-
"nullable",
|
|
9156
|
-
"default",
|
|
9157
|
-
"prefault",
|
|
9158
|
-
"catch",
|
|
9159
|
-
"readonly",
|
|
9160
|
-
"nonoptional"
|
|
9161
|
-
]);
|
|
9162
|
-
/**
|
|
9163
|
-
* The schema layers that make up ONE field: the schema itself and every
|
|
9164
|
-
* wrapper below it (optional / default / nullable / readonly / catch), plus
|
|
9165
|
-
* both sides of a pipe (`z.preprocess` puts the real schema on `out`,
|
|
9166
|
-
* `.transform` on `in`).
|
|
9167
|
-
*/
|
|
9168
|
-
function layersOf(schema) {
|
|
9169
|
-
const out = [];
|
|
9170
|
-
const queue = [schema];
|
|
9171
|
-
while (queue.length > 0) {
|
|
9172
|
-
const s = queue.shift();
|
|
9173
|
-
if (!s || out.includes(s)) continue;
|
|
9174
|
-
out.push(s);
|
|
9175
|
-
const def = defOf(s);
|
|
9176
|
-
if (def.type !== void 0 && WRAPPERS.has(def.type) && def.innerType) queue.push(def.innerType);
|
|
9177
|
-
if (def.type === "pipe") {
|
|
9178
|
-
if (def.in) queue.push(def.in);
|
|
9179
|
-
if (def.out) queue.push(def.out);
|
|
9180
|
-
}
|
|
9181
|
-
}
|
|
9182
|
-
return out;
|
|
9183
|
-
}
|
|
9184
|
-
/** True when any layer of this field declares `.meta({ secret: true })`. */
|
|
9185
|
-
function isZodSecret(schema) {
|
|
9186
|
-
return layersOf(schema).some(declaredHere);
|
|
9187
|
-
}
|
|
9188
|
-
/**
|
|
9189
|
-
* Every declared secret path in a config schema: dotted keys, `[]` for "each
|
|
9190
|
-
* element of this array" (`connection.password`, `rows[].token`). A declared
|
|
9191
|
-
* object or array is reported as one path and not descended into — everything
|
|
9192
|
-
* under it is secret.
|
|
9193
|
-
*/
|
|
9194
|
-
function collectZodSecretPaths(schema, prefix = "") {
|
|
9195
|
-
if (isZodSecret(schema)) return prefix.length > 0 ? [prefix] : [];
|
|
9196
|
-
const paths = [];
|
|
9197
|
-
for (const layer of layersOf(schema)) {
|
|
9198
|
-
const def = defOf(layer);
|
|
9199
|
-
if (def.type === "object" && def.shape) for (const [key, child] of Object.entries(def.shape)) paths.push(...collectZodSecretPaths(child, prefix ? `${prefix}.${key}` : key));
|
|
9200
|
-
else if (def.type === "array" && def.element) paths.push(...collectZodSecretPaths(def.element, `${prefix}[]`));
|
|
9201
|
-
else if (def.type === "union" && def.options) for (const option of def.options) paths.push(...collectZodSecretPaths(option, prefix));
|
|
9202
|
-
else if (def.type === "intersection") {
|
|
9203
|
-
if (def.left) paths.push(...collectZodSecretPaths(def.left, prefix));
|
|
9204
|
-
if (def.right) paths.push(...collectZodSecretPaths(def.right, prefix));
|
|
9205
|
-
}
|
|
9206
|
-
}
|
|
9207
|
-
return [...new Set(paths)];
|
|
9208
|
-
}
|
|
9209
9415
|
object({
|
|
9210
9416
|
code: string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/),
|
|
9211
9417
|
params: record(string(), union([string(), number()])).optional()
|
|
9212
9418
|
});
|
|
9213
9419
|
//#endregion
|
|
9214
|
-
//#region ../types/dist/err-msg-
|
|
9420
|
+
//#region ../types/dist/err-msg-BXKzRBwg.mjs
|
|
9215
9421
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
9216
9422
|
DeviceType["Camera"] = "camera";
|
|
9217
9423
|
DeviceType["Hub"] = "hub";
|
|
@@ -9303,6 +9509,10 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
9303
9509
|
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
9304
9510
|
* integrations sharing the same food/desiccant/hopper surface. */
|
|
9305
9511
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
9512
|
+
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
9513
|
+
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
9514
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations. */
|
|
9515
|
+
DeviceType["Dishwasher"] = "dishwasher";
|
|
9306
9516
|
return DeviceType;
|
|
9307
9517
|
}({});
|
|
9308
9518
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -9480,6 +9690,9 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
9480
9690
|
/** Virtual HA toggle (input_boolean.*) — distinguishable from a
|
|
9481
9691
|
* real Switch device for UI rendering / export adapters. */
|
|
9482
9692
|
DeviceRole["BinaryHelper"] = "binary-helper";
|
|
9693
|
+
/** A smart plug: a `switch` whose source says it is an outlet (HA
|
|
9694
|
+
* `device_class: outlet`). The Alexa export shows it as a SMARTPLUG. */
|
|
9695
|
+
DeviceRole["Outlet"] = "outlet";
|
|
9483
9696
|
/** Generic motion / occupancy / moving event source. Distinct from
|
|
9484
9697
|
* the camera accessory PirSensor role: that one is a camera child;
|
|
9485
9698
|
* this is a standalone HA / 3rd-party motion sensor. */
|
|
@@ -9557,7 +9770,7 @@ function errMsg(err) {
|
|
|
9557
9770
|
return String(err);
|
|
9558
9771
|
}
|
|
9559
9772
|
//#endregion
|
|
9560
|
-
//#region ../types/dist/composition-
|
|
9773
|
+
//#region ../types/dist/composition-CB6PMT9p.mjs
|
|
9561
9774
|
/**
|
|
9562
9775
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
9563
9776
|
*
|
|
@@ -12761,11 +12974,10 @@ var ClipModelMetaSchema = object({
|
|
|
12761
12974
|
/**
|
|
12762
12975
|
* The `vector-store` index this model's vectors live in. ONE feature space
|
|
12763
12976
|
* per index: two models share an index only when their vectors are ranked
|
|
12764
|
-
* against each other, which for CLIP means never across families.
|
|
12765
|
-
*
|
|
12766
|
-
* `modelId`); any other model gets its own.
|
|
12977
|
+
* against each other, which for CLIP means never across families. Every
|
|
12978
|
+
* model gets its own.
|
|
12767
12979
|
*/
|
|
12768
|
-
vectorIndex: string().regex(/^object-clip
|
|
12980
|
+
vectorIndex: string().regex(/^object-clip-[a-z0-9][a-z0-9-]*$/),
|
|
12769
12981
|
/**
|
|
12770
12982
|
* The text encoder's tokenizer, a declared SIBLING file of its onnx. The name
|
|
12771
12983
|
* must be unique per tokenizer: every model's siblings land in ONE flat
|
|
@@ -13944,8 +14156,20 @@ var AlertSeveritySchema = _enum([
|
|
|
13944
14156
|
"info",
|
|
13945
14157
|
"success",
|
|
13946
14158
|
"warning",
|
|
13947
|
-
"error"
|
|
14159
|
+
"error",
|
|
14160
|
+
"critical"
|
|
13948
14161
|
]);
|
|
14162
|
+
var AlertActionSchema = object({
|
|
14163
|
+
label: string(),
|
|
14164
|
+
href: string().optional(),
|
|
14165
|
+
/**
|
|
14166
|
+
* How `href` is followed. Absent / `app`: an admin-ui route (client-side).
|
|
14167
|
+
* `server`: a route the HUB serves (an addon HTTP route such as an OAuth
|
|
14168
|
+
* start) — the browser must leave the SPA with a full navigation, because
|
|
14169
|
+
* the SPA has no such route and would bounce to the home page.
|
|
14170
|
+
*/
|
|
14171
|
+
navigation: _enum(["app", "server"]).optional()
|
|
14172
|
+
});
|
|
13949
14173
|
var AlertStatusSchema = _enum([
|
|
13950
14174
|
"active",
|
|
13951
14175
|
"in-progress",
|
|
@@ -13963,6 +14187,7 @@ var AlertSchema = object({
|
|
|
13963
14187
|
severity: AlertSeveritySchema,
|
|
13964
14188
|
title: string(),
|
|
13965
14189
|
message: string(),
|
|
14190
|
+
action: AlertActionSchema.optional(),
|
|
13966
14191
|
status: AlertStatusSchema,
|
|
13967
14192
|
progress: number().optional(),
|
|
13968
14193
|
read: boolean(),
|
|
@@ -16498,6 +16723,41 @@ var ComposableCapabilitiesSchema = object({ caps: array(object({
|
|
|
16498
16723
|
keyField: string()
|
|
16499
16724
|
}).optional()
|
|
16500
16725
|
})) });
|
|
16726
|
+
/**
|
|
16727
|
+
* The report of a one-shot "move this owner's plaintext secrets into the
|
|
16728
|
+
* keychain" run (D878). COUNTS only - never a value, never a ref.
|
|
16729
|
+
*
|
|
16730
|
+
* The owner runs it on its own rows, through its own write path; an operator
|
|
16731
|
+
* script (`scripts/hub/migrate-raw-secrets.ts`) calls the owner's cap method.
|
|
16732
|
+
* Dry run (`apply: false`) reports what WOULD move and changes nothing.
|
|
16733
|
+
*/
|
|
16734
|
+
var RawSecretMigrationInputSchema = object({
|
|
16735
|
+
/** `false` (the default of the script) = report only. */
|
|
16736
|
+
apply: boolean() });
|
|
16737
|
+
var RawSecretMigrationReportSchema = object({
|
|
16738
|
+
apply: boolean(),
|
|
16739
|
+
/** Rows that can carry a secret (a profile, an enrolment). */
|
|
16740
|
+
rows: number().int(),
|
|
16741
|
+
/** Rows whose secret was plaintext when the run started. */
|
|
16742
|
+
raw: number().int(),
|
|
16743
|
+
/** Rows that already held a keychain marker when the run started. */
|
|
16744
|
+
markers: number().int(),
|
|
16745
|
+
/** Plaintext rows moved by THIS run (always 0 on a dry run). */
|
|
16746
|
+
migrated: number().int(),
|
|
16747
|
+
/** Plaintext rows left in place because the move or its read-back failed. */
|
|
16748
|
+
failed: number().int(),
|
|
16749
|
+
/** After the run: rows still holding plaintext. */
|
|
16750
|
+
remainingRaw: number().int(),
|
|
16751
|
+
/** After the run: markers the keychain could not resolve right now. */
|
|
16752
|
+
unresolvedMarkers: number().int(),
|
|
16753
|
+
/**
|
|
16754
|
+
* A second, redundant copy of the secrets' rows that the run found (and, on
|
|
16755
|
+
* `apply`, deleted after verifying the first). Owners with a single copy omit it.
|
|
16756
|
+
*/
|
|
16757
|
+
redundantCopies: number().int().optional(),
|
|
16758
|
+
/** True when nothing is raw and every marker resolves. */
|
|
16759
|
+
verified: boolean()
|
|
16760
|
+
});
|
|
16501
16761
|
/** Where a block runs. The operator chooses — a block driving a device on an
|
|
16502
16762
|
* agent is the reason placement is not fixed to the hub. */
|
|
16503
16763
|
var CoreBlockPlacementSchema = union([literal("hub"), string().min(1)]);
|
|
@@ -16724,6 +16984,9 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
|
|
|
16724
16984
|
}), SettingsUpdateResultSchema, {
|
|
16725
16985
|
kind: "mutation",
|
|
16726
16986
|
auth: "admin"
|
|
16987
|
+
}), method(RawSecretMigrationInputSchema, RawSecretMigrationReportSchema, {
|
|
16988
|
+
kind: "mutation",
|
|
16989
|
+
auth: "admin"
|
|
16727
16990
|
}), method(object({}), object({ libs: array(object({
|
|
16728
16991
|
filePath: string(),
|
|
16729
16992
|
content: string()
|
|
@@ -16987,6 +17250,347 @@ id: union([string(), number()]) }), {
|
|
|
16987
17250
|
auth: "admin"
|
|
16988
17251
|
});
|
|
16989
17252
|
/**
|
|
17253
|
+
* records - an addon's own facts and documents (D881): ledgers, audit rows,
|
|
17254
|
+
* config documents, mirrors. The third storage API next to `ctx.settings`
|
|
17255
|
+
* (operator intent, D870) and device-history (numbers over time, D850).
|
|
17256
|
+
*
|
|
17257
|
+
* Who the OWNER is: `callerAddonId`, stamped by the transport on a call that
|
|
17258
|
+
* crossed a process and stated by a hub in-process caller (`ctx.records` does
|
|
17259
|
+
* that with the addon id closed over). It is deliberately NOT in any input
|
|
17260
|
+
* schema, so a session can never supply it, and a call with no stamp is refused
|
|
17261
|
+
* `records/no-caller`. A kind is readable and writable only by its owner; other
|
|
17262
|
+
* addons go through the owner's capability.
|
|
17263
|
+
*
|
|
17264
|
+
* Every read is three-way: a row, `null`, or the call THROWS. A failed read is
|
|
17265
|
+
* never `[]`. Secret fields are never on the wire: a read shows the
|
|
17266
|
+
* redaction token, `secretRefs` hands the owner's `ctx.secrets` the refs it
|
|
17267
|
+
* resolves itself, and a write may carry only a keychain marker bound to the
|
|
17268
|
+
* row's own ref.
|
|
17269
|
+
*
|
|
17270
|
+
* Internal: addons reach it through `ctx.records`, never directly.
|
|
17271
|
+
*/
|
|
17272
|
+
var RecordIdSchema = string().min(1).max(256);
|
|
17273
|
+
/** A JSON object body. Size is the engine's check (`maxDataBytes`), not a schema's. */
|
|
17274
|
+
var RecordBodySchema = record(string(), unknown());
|
|
17275
|
+
var RecordInputSchema = object({
|
|
17276
|
+
id: RecordIdSchema,
|
|
17277
|
+
/** The device this row belongs to (D865 removal, per-device reads). */
|
|
17278
|
+
deviceId: number().int().optional(),
|
|
17279
|
+
/** The domain clock, ms: observed / created / opened. */
|
|
17280
|
+
at: number().int().optional(),
|
|
17281
|
+
/** Producer-set expiry, ms. Refused on a kind whose retention is an engine TTL. */
|
|
17282
|
+
expiresAt: number().int().optional(),
|
|
17283
|
+
data: RecordBodySchema
|
|
17284
|
+
});
|
|
17285
|
+
var RecordViewSchema = object({
|
|
17286
|
+
id: string(),
|
|
17287
|
+
deviceId: number().int().nullable(),
|
|
17288
|
+
at: number().nullable(),
|
|
17289
|
+
expiresAt: number().nullable(),
|
|
17290
|
+
rev: number().int(),
|
|
17291
|
+
updatedAt: number(),
|
|
17292
|
+
data: RecordBodySchema
|
|
17293
|
+
});
|
|
17294
|
+
/** Declared index fields only. Anything else does not compile, by design. */
|
|
17295
|
+
var RecordWhereSchema = record(RecordFieldPathSchema, union([
|
|
17296
|
+
string(),
|
|
17297
|
+
number(),
|
|
17298
|
+
boolean(),
|
|
17299
|
+
object({ in: array(union([
|
|
17300
|
+
string(),
|
|
17301
|
+
number(),
|
|
17302
|
+
boolean()
|
|
17303
|
+
])).min(1).max(RECORD_BATCH_MAX) }),
|
|
17304
|
+
object({
|
|
17305
|
+
gt: union([string(), number()]).optional(),
|
|
17306
|
+
gte: union([string(), number()]).optional(),
|
|
17307
|
+
lt: union([string(), number()]).optional(),
|
|
17308
|
+
lte: union([string(), number()]).optional()
|
|
17309
|
+
}).refine((r) => Object.keys(r).length > 0, { message: "name at least one bound" })
|
|
17310
|
+
]));
|
|
17311
|
+
var KindShape = { kind: RecordKindNameSchema };
|
|
17312
|
+
var TimeWindowShape = {
|
|
17313
|
+
deviceId: number().int().optional(),
|
|
17314
|
+
atFrom: number().optional(),
|
|
17315
|
+
atTo: number().optional()
|
|
17316
|
+
};
|
|
17317
|
+
var RecordQueryInputSchema = object({
|
|
17318
|
+
...KindShape,
|
|
17319
|
+
...TimeWindowShape,
|
|
17320
|
+
where: RecordWhereSchema.optional(),
|
|
17321
|
+
/** Without `where`: `at` (default for a kind with a clock) or `id`. With `where` the order is the index's. */
|
|
17322
|
+
order: _enum(["at", "id"]).optional(),
|
|
17323
|
+
desc: boolean().optional(),
|
|
17324
|
+
limit: number().int().min(1).max(RECORD_QUERY_MAX).default(100),
|
|
17325
|
+
/** Opaque keyset cursor from a previous answer. There is no offset. */
|
|
17326
|
+
cursor: string().min(1).optional()
|
|
17327
|
+
});
|
|
17328
|
+
var RecordQueryResultSchema = object({
|
|
17329
|
+
records: array(RecordViewSchema),
|
|
17330
|
+
nextCursor: string().nullable()
|
|
17331
|
+
});
|
|
17332
|
+
var RecordKindStateSchema = _enum([
|
|
17333
|
+
"created",
|
|
17334
|
+
"unchanged",
|
|
17335
|
+
"updated"
|
|
17336
|
+
]);
|
|
17337
|
+
var DeclareKindResultSchema = object({
|
|
17338
|
+
kindId: number().int(),
|
|
17339
|
+
state: RecordKindStateSchema,
|
|
17340
|
+
createdIndexes: array(string()),
|
|
17341
|
+
/** The boot guard: the kind is empty while its legacy table still holds rows. */
|
|
17342
|
+
adoptionPending: object({
|
|
17343
|
+
legacyTable: string(),
|
|
17344
|
+
legacyRows: number().int()
|
|
17345
|
+
}).nullable()
|
|
17346
|
+
});
|
|
17347
|
+
/** Keychain refs a write released (the old marker is gone from the row): the owner deletes the values. */
|
|
17348
|
+
var SecretRefsList = array(string());
|
|
17349
|
+
var RecordSecretRefsSchema = record(string(), record(string(), string()));
|
|
17350
|
+
method(object({ kinds: record(RecordKindNameSchema, RecordKindDeclarationSchema) }), object({ kinds: record(string(), DeclareKindResultSchema) }), {
|
|
17351
|
+
kind: "mutation",
|
|
17352
|
+
auth: "admin"
|
|
17353
|
+
}), method(object({
|
|
17354
|
+
...KindShape,
|
|
17355
|
+
id: RecordIdSchema
|
|
17356
|
+
}), RecordViewSchema.nullable(), { auth: "admin" }), method(object({
|
|
17357
|
+
...KindShape,
|
|
17358
|
+
ids: array(RecordIdSchema).min(1).max(RECORD_BATCH_MAX)
|
|
17359
|
+
}), array(RecordViewSchema), { auth: "admin" }), method(object({
|
|
17360
|
+
...KindShape,
|
|
17361
|
+
ids: array(RecordIdSchema).min(1).max(RECORD_BATCH_MAX)
|
|
17362
|
+
}), RecordSecretRefsSchema, { auth: "admin" }), method(object({
|
|
17363
|
+
...KindShape,
|
|
17364
|
+
record: RecordInputSchema,
|
|
17365
|
+
/** Compare-and-set. `0` means "the row must not exist". */
|
|
17366
|
+
ifRev: number().int().min(0).optional()
|
|
17367
|
+
}), object({
|
|
17368
|
+
rev: number().int(),
|
|
17369
|
+
releasedRefs: SecretRefsList
|
|
17370
|
+
}), {
|
|
17371
|
+
kind: "mutation",
|
|
17372
|
+
auth: "admin"
|
|
17373
|
+
}), method(object({
|
|
17374
|
+
...KindShape,
|
|
17375
|
+
records: array(RecordInputSchema).min(1).max(RECORD_BATCH_MAX)
|
|
17376
|
+
}), object({
|
|
17377
|
+
count: number().int(),
|
|
17378
|
+
releasedRefs: SecretRefsList
|
|
17379
|
+
}), {
|
|
17380
|
+
kind: "mutation",
|
|
17381
|
+
auth: "admin"
|
|
17382
|
+
}), method(object({
|
|
17383
|
+
...KindShape,
|
|
17384
|
+
id: RecordIdSchema,
|
|
17385
|
+
data: RecordBodySchema,
|
|
17386
|
+
at: number().int().nullable().optional(),
|
|
17387
|
+
expiresAt: number().int().nullable().optional(),
|
|
17388
|
+
ifRev: number().int().min(1).optional()
|
|
17389
|
+
}), object({
|
|
17390
|
+
rev: number().int(),
|
|
17391
|
+
releasedRefs: SecretRefsList
|
|
17392
|
+
}), {
|
|
17393
|
+
kind: "mutation",
|
|
17394
|
+
auth: "admin"
|
|
17395
|
+
}), method(object({
|
|
17396
|
+
...KindShape,
|
|
17397
|
+
id: RecordIdSchema
|
|
17398
|
+
}), object({
|
|
17399
|
+
deleted: boolean(),
|
|
17400
|
+
secretRefs: SecretRefsList
|
|
17401
|
+
}), {
|
|
17402
|
+
kind: "mutation",
|
|
17403
|
+
auth: "admin"
|
|
17404
|
+
}), method(object({
|
|
17405
|
+
...KindShape,
|
|
17406
|
+
ids: array(RecordIdSchema).min(1).max(RECORD_BATCH_MAX)
|
|
17407
|
+
}), object({
|
|
17408
|
+
deleted: number().int(),
|
|
17409
|
+
secretRefs: SecretRefsList
|
|
17410
|
+
}), {
|
|
17411
|
+
kind: "mutation",
|
|
17412
|
+
auth: "admin"
|
|
17413
|
+
}), method(RecordQueryInputSchema, RecordQueryResultSchema, { auth: "admin" }), method(object({
|
|
17414
|
+
...KindShape,
|
|
17415
|
+
...TimeWindowShape,
|
|
17416
|
+
where: RecordWhereSchema.optional()
|
|
17417
|
+
}), object({ count: number().int() }), { auth: "admin" }), method(object({
|
|
17418
|
+
...KindShape,
|
|
17419
|
+
deviceId: number().int().optional(),
|
|
17420
|
+
from: number(),
|
|
17421
|
+
to: number(),
|
|
17422
|
+
bucketMs: number().int().positive()
|
|
17423
|
+
}), object({ buckets: array(object({
|
|
17424
|
+
bucketStart: number(),
|
|
17425
|
+
count: number().int()
|
|
17426
|
+
})) }), { auth: "admin" }), method(object({
|
|
17427
|
+
...KindShape,
|
|
17428
|
+
op: _enum([
|
|
17429
|
+
"sum",
|
|
17430
|
+
"min",
|
|
17431
|
+
"max",
|
|
17432
|
+
"count"
|
|
17433
|
+
]),
|
|
17434
|
+
field: RecordFieldPathSchema.optional(),
|
|
17435
|
+
groupBy: RecordFieldPathSchema.optional(),
|
|
17436
|
+
where: RecordWhereSchema.optional()
|
|
17437
|
+
}), object({ rows: array(object({
|
|
17438
|
+
group: union([
|
|
17439
|
+
string(),
|
|
17440
|
+
number(),
|
|
17441
|
+
_null()
|
|
17442
|
+
]),
|
|
17443
|
+
value: number().nullable()
|
|
17444
|
+
})) }), { auth: "admin" }), method(object({
|
|
17445
|
+
...KindShape,
|
|
17446
|
+
deviceId: number().int().optional(),
|
|
17447
|
+
atBefore: number().optional(),
|
|
17448
|
+
where: RecordWhereSchema.optional()
|
|
17449
|
+
}), object({
|
|
17450
|
+
deleted: number().int(),
|
|
17451
|
+
secretRefs: SecretRefsList
|
|
17452
|
+
}), {
|
|
17453
|
+
kind: "mutation",
|
|
17454
|
+
auth: "admin"
|
|
17455
|
+
}), method(object({
|
|
17456
|
+
deviceId: number().int(),
|
|
17457
|
+
kinds: array(RecordKindNameSchema).optional()
|
|
17458
|
+
}), object({
|
|
17459
|
+
deleted: record(string(), number().int()),
|
|
17460
|
+
secretRefs: SecretRefsList
|
|
17461
|
+
}), {
|
|
17462
|
+
kind: "mutation",
|
|
17463
|
+
auth: "admin"
|
|
17464
|
+
}), method(object(KindShape), object({ id: number().int() }), {
|
|
17465
|
+
kind: "mutation",
|
|
17466
|
+
auth: "admin"
|
|
17467
|
+
});
|
|
17468
|
+
/** One table of the settings database. */
|
|
17469
|
+
var StorageTableSchema = object({
|
|
17470
|
+
/** The table's full name, e.g. `recorder:addon-settings` or `addon-device-settings`. */
|
|
17471
|
+
name: string(),
|
|
17472
|
+
/** The owner prefix of a scoped name (`recorder` for `recorder:addon-settings`), else null. */
|
|
17473
|
+
owner: string().nullable(),
|
|
17474
|
+
rows: number().int().nonnegative(),
|
|
17475
|
+
/** Bytes the table's pages occupy (`dbstat`); null when the engine cannot measure. */
|
|
17476
|
+
bytes: number().int().nonnegative().nullable(),
|
|
17477
|
+
/** Declared by an addon since this engine process started (a running addon claims it). */
|
|
17478
|
+
declaredThisBoot: boolean()
|
|
17479
|
+
});
|
|
17480
|
+
/** One declared record kind (D881) as System -> Data shows it. */
|
|
17481
|
+
var StorageKindSchema = object({
|
|
17482
|
+
owner: string(),
|
|
17483
|
+
kind: string(),
|
|
17484
|
+
database: _enum(["settings", "events"]),
|
|
17485
|
+
class: string(),
|
|
17486
|
+
state: _enum([
|
|
17487
|
+
"declared",
|
|
17488
|
+
"orphaned",
|
|
17489
|
+
"dropped"
|
|
17490
|
+
]),
|
|
17491
|
+
/** `null` when the caller asked for no counts (`counts: false`). */
|
|
17492
|
+
rows: number().int().nonnegative().nullable(),
|
|
17493
|
+
/** Rows x the average size of a sample; null for an empty kind. */
|
|
17494
|
+
bytesEstimate: number().int().nonnegative().nullable(),
|
|
17495
|
+
writeTrigger: string(),
|
|
17496
|
+
retention: RecordRetentionSchema,
|
|
17497
|
+
/** `true` when the kind is an entry kind (the generic entries UI lists it). */
|
|
17498
|
+
entry: boolean(),
|
|
17499
|
+
/** The whole declaration, secret paths and entry descriptor included (the entries service builds its handle from it). */
|
|
17500
|
+
declaration: RecordKindDeclarationSchema
|
|
17501
|
+
});
|
|
17502
|
+
method(object({ ownerPrefix: string().min(1).optional() }), object({ tables: array(StorageTableSchema) }), { auth: "admin" }), method(object({
|
|
17503
|
+
collection: string().min(1),
|
|
17504
|
+
expectRows: number().int().nonnegative()
|
|
17505
|
+
}), object({
|
|
17506
|
+
dropped: literal(true),
|
|
17507
|
+
rows: number().int().nonnegative()
|
|
17508
|
+
}), {
|
|
17509
|
+
kind: "mutation",
|
|
17510
|
+
auth: "admin"
|
|
17511
|
+
}), method(object({
|
|
17512
|
+
owner: string().min(1).optional(),
|
|
17513
|
+
/** `false` skips the per-kind row count (a catalog read only). Default true. */
|
|
17514
|
+
counts: boolean().optional()
|
|
17515
|
+
}), object({ kinds: array(StorageKindSchema) }), { auth: "admin" }), method(RecordQueryInputSchema.extend({
|
|
17516
|
+
owner: string().min(1),
|
|
17517
|
+
kind: RecordKindNameSchema
|
|
17518
|
+
}), RecordQueryResultSchema, { auth: "admin" }), method(object({
|
|
17519
|
+
owner: string().min(1),
|
|
17520
|
+
kind: RecordKindNameSchema,
|
|
17521
|
+
records: array(RecordInputSchema).max(RECORD_BATCH_MAX),
|
|
17522
|
+
/** The LAST batch: the copy is complete, the boot guard stops asking. */
|
|
17523
|
+
complete: boolean().optional()
|
|
17524
|
+
}).refine((input) => input.records.length > 0 || input.complete === true, { message: "records must be non-empty unless complete is true" }), object({ adopted: number().int() }), {
|
|
17525
|
+
kind: "mutation",
|
|
17526
|
+
auth: "admin"
|
|
17527
|
+
}), method(object({
|
|
17528
|
+
collection: string().min(1),
|
|
17529
|
+
cursor: string().optional(),
|
|
17530
|
+
limit: number().int().min(1).max(1e3).optional()
|
|
17531
|
+
}), object({
|
|
17532
|
+
rows: array(object({
|
|
17533
|
+
id: string(),
|
|
17534
|
+
data: record(string(), unknown())
|
|
17535
|
+
})),
|
|
17536
|
+
nextCursor: string().nullable()
|
|
17537
|
+
}), { auth: "admin" }), method(object({ collection: string().min(1) }), object({ adopted: boolean() }), { auth: "admin" });
|
|
17538
|
+
/**
|
|
17539
|
+
* record-entries - the ONE admin surface for every list of user-created entries
|
|
17540
|
+
* (D881): notification targets, brokers, LLM profiles, anything an addon
|
|
17541
|
+
* declares as an ENTRY kind (`entry: { title }` in `defineRecordKinds`).
|
|
17542
|
+
*
|
|
17543
|
+
* The UI is generic. `listEntryKinds` hands it, per kind, the JSON Schema of
|
|
17544
|
+
* the entry body with `secret: true` on every credential field, so a password
|
|
17545
|
+
* field is derived from the schema and never from a name. `putEntry` takes the
|
|
17546
|
+
* redaction token for an untouched secret (the stored value is kept), a string
|
|
17547
|
+
* for a new one, and the clear instruction to remove one. A read never carries
|
|
17548
|
+
* a secret value, and a locked keychain refuses the write with
|
|
17549
|
+
* `records/secret-unavailable` instead of storing plaintext.
|
|
17550
|
+
*
|
|
17551
|
+
* Hub-only, served in-process (it acts for each entry's owner on the keychain).
|
|
17552
|
+
*/
|
|
17553
|
+
var EntryKindInfoSchema = object({
|
|
17554
|
+
owner: string(),
|
|
17555
|
+
kind: RecordKindNameSchema,
|
|
17556
|
+
title: string(),
|
|
17557
|
+
nameField: string(),
|
|
17558
|
+
/** JSON Schema of the body; `secret: true` marks a password field. */
|
|
17559
|
+
fields: record(string(), unknown()),
|
|
17560
|
+
secretPaths: array(string()),
|
|
17561
|
+
rows: number().int().nonnegative()
|
|
17562
|
+
});
|
|
17563
|
+
var EntryViewSchema = object({
|
|
17564
|
+
id: RecordIdSchema,
|
|
17565
|
+
name: string(),
|
|
17566
|
+
rev: number().int(),
|
|
17567
|
+
updatedAt: number(),
|
|
17568
|
+
/** Secret fields hold the redaction token. */
|
|
17569
|
+
data: RecordBodySchema
|
|
17570
|
+
});
|
|
17571
|
+
var EntryAddress = {
|
|
17572
|
+
owner: string().min(1),
|
|
17573
|
+
kind: RecordKindNameSchema
|
|
17574
|
+
};
|
|
17575
|
+
method(object({}), object({ kinds: array(EntryKindInfoSchema) }), { auth: "admin" }), method(object({ ...EntryAddress }), object({ entries: array(EntryViewSchema) }), { auth: "admin" }), method(object({
|
|
17576
|
+
...EntryAddress,
|
|
17577
|
+
id: RecordIdSchema.optional(),
|
|
17578
|
+
data: RecordBodySchema,
|
|
17579
|
+
ifRev: number().int().min(1).optional()
|
|
17580
|
+
}), object({
|
|
17581
|
+
id: string(),
|
|
17582
|
+
rev: number().int()
|
|
17583
|
+
}), {
|
|
17584
|
+
kind: "mutation",
|
|
17585
|
+
auth: "admin"
|
|
17586
|
+
}), method(object({
|
|
17587
|
+
...EntryAddress,
|
|
17588
|
+
id: RecordIdSchema
|
|
17589
|
+
}), object({ deleted: boolean() }), {
|
|
17590
|
+
kind: "mutation",
|
|
17591
|
+
auth: "admin"
|
|
17592
|
+
});
|
|
17593
|
+
/**
|
|
16990
17594
|
* `keychain` — the hub's encrypted store of secret values (D787).
|
|
16991
17595
|
*
|
|
16992
17596
|
* Settings blobs never hold a secret: they hold a marker
|
|
@@ -17527,6 +18131,16 @@ method(object({}), KeychainStatusSchema, { auth: "admin" }), method(object({}),
|
|
|
17527
18131
|
kind: "mutation",
|
|
17528
18132
|
auth: "admin",
|
|
17529
18133
|
caller: "required"
|
|
18134
|
+
}), method(object({
|
|
18135
|
+
ref: string().min(1),
|
|
18136
|
+
value: string().min(1)
|
|
18137
|
+
}), object({
|
|
18138
|
+
ref: string(),
|
|
18139
|
+
version: number().int()
|
|
18140
|
+
}), {
|
|
18141
|
+
kind: "mutation",
|
|
18142
|
+
auth: "admin",
|
|
18143
|
+
caller: "required"
|
|
17530
18144
|
}), method(object({ refs: array(string().min(1)).max(1e3) }), object({
|
|
17531
18145
|
deleted: array(string()).readonly(),
|
|
17532
18146
|
kept: array(object({
|
|
@@ -18048,7 +18662,11 @@ var deviceDiscoveryCapability = {
|
|
|
18048
18662
|
};
|
|
18049
18663
|
/**
|
|
18050
18664
|
* `device-adoption` — generic discovery + adoption surface,
|
|
18051
|
-
* system-scoped
|
|
18665
|
+
* system-scoped collection (one provider per integration addon), routed
|
|
18666
|
+
* by explicit `{ addonId }` on direct `deviceAdoption.*` calls — the same
|
|
18667
|
+
* pin model as `connection-test`. The admin UI keeps using
|
|
18668
|
+
* `deviceManager.adoption*` (which already threads `addonId`). The de-HA-ified
|
|
18669
|
+
* successor to `ha-discovery`:
|
|
18052
18670
|
* keyed by `integrationId` (the addon resolves integrationId → broker
|
|
18053
18671
|
* internally) rather than a connection-specific `brokerId`, and it
|
|
18054
18672
|
* REUSES the shared `DiscoveredChildDevice` candidate type from
|
|
@@ -40301,6 +40919,9 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, {
|
|
|
40301
40919
|
}), _void(), { kind: "mutation" }), method(object({}), array(LlmProfileKindDescriptorSchema)), method(object({}), array(LlmProfileSchema)), method(object({ profile: LlmProfileSchema }), LlmProfileSchema, {
|
|
40302
40920
|
kind: "mutation",
|
|
40303
40921
|
auth: "admin"
|
|
40922
|
+
}), method(RawSecretMigrationInputSchema, RawSecretMigrationReportSchema, {
|
|
40923
|
+
kind: "mutation",
|
|
40924
|
+
auth: "admin"
|
|
40304
40925
|
}), method(ProfileRefInputSchema, _void(), {
|
|
40305
40926
|
kind: "mutation",
|
|
40306
40927
|
auth: "admin"
|
|
@@ -42376,6 +42997,9 @@ var NcSystemEventKindSchema = _enum([
|
|
|
42376
42997
|
"server-updated",
|
|
42377
42998
|
"export-completed",
|
|
42378
42999
|
"backup-completed",
|
|
43000
|
+
"alert-critical",
|
|
43001
|
+
"alert-error",
|
|
43002
|
+
"alert-critical-resolved",
|
|
42379
43003
|
"camera-online",
|
|
42380
43004
|
"camera-offline",
|
|
42381
43005
|
"camera-disabled",
|
|
@@ -50810,6 +51434,41 @@ var ServerRollbackInfoSchema = object({
|
|
|
50810
51434
|
atMs: number(),
|
|
50811
51435
|
reason: string()
|
|
50812
51436
|
});
|
|
51437
|
+
/**
|
|
51438
|
+
* The runner boot check (D877): the runners this node PLANNED (hub: one per
|
|
51439
|
+
* `resolveRunnerId` over its forked addons; agent: the runners its process
|
|
51440
|
+
* service holds, because only the hub plans) against the states the process
|
|
51441
|
+
* service reports. Kept in memory, recomputed by the same one-shot check after
|
|
51442
|
+
* every boot, served on `getServerPackageStatus`.
|
|
51443
|
+
*
|
|
51444
|
+
* `failed` is the D6 breaker's terminal state, `refused` a deterministic Init
|
|
51445
|
+
* refusal (an addon that said "I will not start, and here is why"), `missing` a
|
|
51446
|
+
* planned runner the process service has no entry for.
|
|
51447
|
+
*/
|
|
51448
|
+
var RunnerRefusalSchema = object({
|
|
51449
|
+
runnerId: string(),
|
|
51450
|
+
addonIds: array(string()),
|
|
51451
|
+
reason: string()
|
|
51452
|
+
});
|
|
51453
|
+
var RunnerBootCheckSchema = object({
|
|
51454
|
+
checkedAtMs: number(),
|
|
51455
|
+
/** Runners planned for this node. */
|
|
51456
|
+
expected: number(),
|
|
51457
|
+
/** Planned runners whose process is `running`. */
|
|
51458
|
+
running: number(),
|
|
51459
|
+
failed: array(string()),
|
|
51460
|
+
refused: array(RunnerRefusalSchema),
|
|
51461
|
+
missing: array(string()),
|
|
51462
|
+
/**
|
|
51463
|
+
* Runners still on their way: `starting`, or `crashed` waiting on a backoff
|
|
51464
|
+
* respawn. The check is FINAL only when this is empty; until then nothing is
|
|
51465
|
+
* pushed and the verdict is re-evaluated on the next runner state change.
|
|
51466
|
+
* Optional for version skew (absent = settled).
|
|
51467
|
+
*/
|
|
51468
|
+
pending: array(string()).optional(),
|
|
51469
|
+
/** True when the plan is the hub's (`missing` is then meaningful); false on an agent. */
|
|
51470
|
+
planKnown: boolean()
|
|
51471
|
+
});
|
|
50813
51472
|
var ServerPackageStatusSchema = object({
|
|
50814
51473
|
/** Root package name (`@camstack/server` on the hub). */
|
|
50815
51474
|
packageName: string(),
|
|
@@ -50872,7 +51531,14 @@ var ServerPackageStatusSchema = object({
|
|
|
50872
51531
|
* for version skew: an older provider's payload simply omits it, and an
|
|
50873
51532
|
* absent wrapper is unknown — never `native`.
|
|
50874
51533
|
*/
|
|
50875
|
-
wrapper: WrapperIdentitySchema.optional()
|
|
51534
|
+
wrapper: WrapperIdentitySchema.optional(),
|
|
51535
|
+
/**
|
|
51536
|
+
* What this node PLANNED to run against what its process service reports
|
|
51537
|
+
* (D877). Absent until the one-shot boot check has run (~60 s after boot) and
|
|
51538
|
+
* on a provider that predates it. Absent is "not checked yet", never "all
|
|
51539
|
+
* well": a consumer that needs the answer treats it as pending.
|
|
51540
|
+
*/
|
|
51541
|
+
runners: RunnerBootCheckSchema.optional()
|
|
50876
51542
|
});
|
|
50877
51543
|
var ServerUpdateCheckResultSchema = object({
|
|
50878
51544
|
packageName: string(),
|
|
@@ -50923,6 +51589,13 @@ var ServerUpdateOutcomeSchema = _enum([
|
|
|
50923
51589
|
"refused",
|
|
50924
51590
|
"failed"
|
|
50925
51591
|
]);
|
|
51592
|
+
/** One addon the pre-flight found the target version would refuse (D877). */
|
|
51593
|
+
var UpdateBlockerSchema = object({
|
|
51594
|
+
addonId: string(),
|
|
51595
|
+
reason: string(),
|
|
51596
|
+
/** What the operator does about it. */
|
|
51597
|
+
remedy: string()
|
|
51598
|
+
});
|
|
50926
51599
|
var ServerUpdateActionResultSchema = object({
|
|
50927
51600
|
accepted: boolean(),
|
|
50928
51601
|
targetVersion: string().nullable(),
|
|
@@ -50940,14 +51613,27 @@ var ServerUpdateActionResultSchema = object({
|
|
|
50940
51613
|
* The failure itself, verbatim enough to act on (the npm output for a
|
|
50941
51614
|
* staging install). Non-null only for `failed`.
|
|
50942
51615
|
*/
|
|
50943
|
-
error: string().nullable().optional()
|
|
51616
|
+
error: string().nullable().optional(),
|
|
51617
|
+
/**
|
|
51618
|
+
* The addons the target version would refuse to start on this node's live
|
|
51619
|
+
* store (D877), present when the pre-flight refused the update
|
|
51620
|
+
* (`reason: 'addon-would-refuse'`). Optional for version skew.
|
|
51621
|
+
*/
|
|
51622
|
+
blockers: array(UpdateBlockerSchema).optional()
|
|
50944
51623
|
});
|
|
50945
51624
|
method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
|
|
50946
51625
|
kind: "mutation",
|
|
50947
51626
|
auth: "admin"
|
|
50948
|
-
}), method(object({
|
|
50949
|
-
/** Explicit target version; omitted = latest from the registry. */
|
|
50950
|
-
version: string().optional()
|
|
51627
|
+
}), method(object({
|
|
51628
|
+
/** Explicit target version; omitted = latest from the registry. */
|
|
51629
|
+
version: string().optional(),
|
|
51630
|
+
/**
|
|
51631
|
+
* Apply even though the pre-flight (D877) found addons the target would
|
|
51632
|
+
* refuse to start. Off by default: those addons stay down until the
|
|
51633
|
+
* remedy is run, which is the incident this gate exists to prevent.
|
|
51634
|
+
*/
|
|
51635
|
+
acknowledgeRefusals: boolean().optional()
|
|
51636
|
+
}), ServerUpdateActionResultSchema, {
|
|
50951
51637
|
kind: "mutation",
|
|
50952
51638
|
auth: "admin",
|
|
50953
51639
|
timeoutMs: 16 * 6e4
|
|
@@ -51390,7 +52076,10 @@ method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin"
|
|
|
51390
52076
|
}), method(object({ jobId: string().optional() }), StorageMigrationJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
51391
52077
|
kind: "mutation",
|
|
51392
52078
|
auth: "admin"
|
|
51393
|
-
}), method(object({}), array(StorageMigrationMoverSchema).readonly(), { auth: "admin" }), method(object({
|
|
52079
|
+
}), method(object({}), array(StorageMigrationMoverSchema).readonly(), { auth: "admin" }), method(object({ locationIds: array(string()).readonly() }), object({
|
|
52080
|
+
clear: boolean(),
|
|
52081
|
+
repointLocationId: string().optional()
|
|
52082
|
+
}), { auth: "admin" }), method(object({}), array(StorageMigrationResidueSchema).readonly(), { auth: "admin" }), method(StorageMigrationDrainInputSchema, object({ jobId: string() }), {
|
|
51394
52083
|
kind: "mutation",
|
|
51395
52084
|
auth: "admin"
|
|
51396
52085
|
}), method(StorageCleanupInputSchema, object({ jobId: string() }), {
|
|
@@ -53393,7 +54082,9 @@ var ManifestShapeSchema = object({
|
|
|
53393
54082
|
var AddonProcessSchema = object({
|
|
53394
54083
|
pid: number().optional(),
|
|
53395
54084
|
mode: string(),
|
|
53396
|
-
state: string()
|
|
54085
|
+
state: string(),
|
|
54086
|
+
/** Why the runner is `refused` (an addon's own words), when it is (D877). */
|
|
54087
|
+
reason: string().optional()
|
|
53397
54088
|
});
|
|
53398
54089
|
/**
|
|
53399
54090
|
* Per-addon health snapshot from the kernel's AddonHealthMonitor.
|
|
@@ -54161,7 +54852,8 @@ var batteryCapability = {
|
|
|
54161
54852
|
DeviceType.Button,
|
|
54162
54853
|
DeviceType.Switch,
|
|
54163
54854
|
DeviceType.PetFeeder,
|
|
54164
|
-
DeviceType.Container
|
|
54855
|
+
DeviceType.Container,
|
|
54856
|
+
DeviceType.Thermostat
|
|
54165
54857
|
],
|
|
54166
54858
|
methods: {
|
|
54167
54859
|
/**
|
|
@@ -54782,6 +55474,12 @@ var ClimateControlStatusSchema = object({
|
|
|
54782
55474
|
/** Horizontal louver swing on/off. Null when the device has no
|
|
54783
55475
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
54784
55476
|
swingHorizontal: boolean().nullable(),
|
|
55477
|
+
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
55478
|
+
minTemp: number().nullable().optional(),
|
|
55479
|
+
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
55480
|
+
maxTemp: number().nullable().optional(),
|
|
55481
|
+
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
55482
|
+
tempStep: number().positive().nullable().optional(),
|
|
54785
55483
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
54786
55484
|
lastFetchedAt: number()
|
|
54787
55485
|
});
|
|
@@ -55628,6 +56326,294 @@ onStatusChanged: { data: object({
|
|
|
55628
56326
|
* whether persisting is worth a SQLite commit. */
|
|
55629
56327
|
volatileStateFields: ["lastChangedAt"]
|
|
55630
56328
|
};
|
|
56329
|
+
/**
|
|
56330
|
+
* Smart-dishwasher cap — program lifecycle, door / remote-start gates,
|
|
56331
|
+
* consumable levels (salt, rinse aid) and common program options.
|
|
56332
|
+
*
|
|
56333
|
+
* Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
|
|
56334
|
+
* by any integration that exposes the same program / option surface.
|
|
56335
|
+
*
|
|
56336
|
+
* `kind: 'poll'` — cloud REST APIs typically have no push channel; the
|
|
56337
|
+
* provider refreshes the slice on an interval and eagerly after commands.
|
|
56338
|
+
*
|
|
56339
|
+
* UNKNOWN IS NOT OFF. Every field the appliance reports separately is
|
|
56340
|
+
* nullable: `null` means "not known right now" (the appliance has not said,
|
|
56341
|
+
* the link is down, or the description does not carry it) and is never
|
|
56342
|
+
* rendered or exported as `false` / `0`. `availability` says why.
|
|
56343
|
+
*/
|
|
56344
|
+
var DishwasherStateSchema = _enum([
|
|
56345
|
+
"idle",
|
|
56346
|
+
"running",
|
|
56347
|
+
"paused",
|
|
56348
|
+
"finished",
|
|
56349
|
+
"error",
|
|
56350
|
+
"unavailable"
|
|
56351
|
+
]);
|
|
56352
|
+
/**
|
|
56353
|
+
* The appliance's own operation state, uncollapsed. `state` above is the coarse
|
|
56354
|
+
* view for compact surfaces; this is what the appliance said.
|
|
56355
|
+
*/
|
|
56356
|
+
var DishwasherOperationStateSchema = _enum([
|
|
56357
|
+
"Inactive",
|
|
56358
|
+
"Ready",
|
|
56359
|
+
"DelayedStart",
|
|
56360
|
+
"Run",
|
|
56361
|
+
"Pause",
|
|
56362
|
+
"ActionRequired",
|
|
56363
|
+
"Finished",
|
|
56364
|
+
"Error",
|
|
56365
|
+
"Aborting"
|
|
56366
|
+
]);
|
|
56367
|
+
/**
|
|
56368
|
+
* Why fields may be `null`:
|
|
56369
|
+
* - `available` — the link is up and the description is loaded;
|
|
56370
|
+
* - `offline` — the local link is down (values are unknown, not last-known);
|
|
56371
|
+
* - `description-missing` — the link is up but the appliance's description could not
|
|
56372
|
+
* be loaded, so its values cannot be decoded.
|
|
56373
|
+
*/
|
|
56374
|
+
var DishwasherAvailabilitySchema = _enum([
|
|
56375
|
+
"available",
|
|
56376
|
+
"offline",
|
|
56377
|
+
"description-missing"
|
|
56378
|
+
]);
|
|
56379
|
+
var DishwasherConsumableLevelSchema = _enum([
|
|
56380
|
+
"ok",
|
|
56381
|
+
"low",
|
|
56382
|
+
"empty"
|
|
56383
|
+
]);
|
|
56384
|
+
var DishwasherStatusSchema = object({
|
|
56385
|
+
availability: DishwasherAvailabilitySchema,
|
|
56386
|
+
/** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
|
|
56387
|
+
state: DishwasherStateSchema,
|
|
56388
|
+
/** The appliance's operation state as reported; null when not known. */
|
|
56389
|
+
operationState: DishwasherOperationStateSchema.nullable(),
|
|
56390
|
+
/** Feature key of the ACTIVE (running) program, or null when none runs / not known. */
|
|
56391
|
+
program: string().nullable(),
|
|
56392
|
+
/** Feature key of the SELECTED program (what Start would run), or null when none / not known. */
|
|
56393
|
+
selectedProgram: string().nullable(),
|
|
56394
|
+
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
56395
|
+
availablePrograms: array(string()),
|
|
56396
|
+
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
56397
|
+
remainingSeconds: number().int().nonnegative().nullable(),
|
|
56398
|
+
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
56399
|
+
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
56400
|
+
/** Cycle completion 0..100, or null when not applicable. */
|
|
56401
|
+
progressPercent: number().min(0).max(100).nullable(),
|
|
56402
|
+
/** True when the door is reported open; null when the door state is not known. */
|
|
56403
|
+
doorOpen: boolean().nullable(),
|
|
56404
|
+
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
56405
|
+
doorLocked: boolean().nullable(),
|
|
56406
|
+
/** True when remote start is allowed (door closed, power on, etc.); null when not known. */
|
|
56407
|
+
remoteStartAllowed: boolean().nullable(),
|
|
56408
|
+
/** True when the appliance accepts remote control now; null when not known. */
|
|
56409
|
+
remoteControlActive: boolean().nullable(),
|
|
56410
|
+
/** True while somebody operates the appliance at its panel; null when not reported. */
|
|
56411
|
+
localControlActive: boolean().nullable(),
|
|
56412
|
+
/** Main power / switched-on state; null when not known. */
|
|
56413
|
+
powerOn: boolean().nullable(),
|
|
56414
|
+
/** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
|
|
56415
|
+
powerState: string().nullable(),
|
|
56416
|
+
saltLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
56417
|
+
rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
56418
|
+
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
56419
|
+
halfLoad: boolean().nullable(),
|
|
56420
|
+
hygienePlus: boolean().nullable(),
|
|
56421
|
+
/** Extra dry option when the appliance exposes it. */
|
|
56422
|
+
extraDry: boolean().nullable(),
|
|
56423
|
+
/** Intensive zone (lower basket) when the appliance exposes it. */
|
|
56424
|
+
intensiveZone: boolean().nullable(),
|
|
56425
|
+
/** VarioSpeed / VarioSpeed+ when the appliance exposes it. */
|
|
56426
|
+
varioSpeedPlus: boolean().nullable(),
|
|
56427
|
+
/** Child lock (controls disabled on the appliance); null when not known. */
|
|
56428
|
+
childLock: boolean().nullable(),
|
|
56429
|
+
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
56430
|
+
activeEvents: array(string()),
|
|
56431
|
+
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
56432
|
+
errorCode: number().nullable(),
|
|
56433
|
+
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
56434
|
+
errorLabel: string().nullable(),
|
|
56435
|
+
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
56436
|
+
lastFetchedAt: number()
|
|
56437
|
+
});
|
|
56438
|
+
var DeviceIdSchema = number().int().nonnegative();
|
|
56439
|
+
/** A value a program option or setting can take. */
|
|
56440
|
+
var DishwasherValueSchema = union([
|
|
56441
|
+
boolean(),
|
|
56442
|
+
string(),
|
|
56443
|
+
number()
|
|
56444
|
+
]);
|
|
56445
|
+
var DishwasherAccessSchema = _enum([
|
|
56446
|
+
"none",
|
|
56447
|
+
"read",
|
|
56448
|
+
"readWrite",
|
|
56449
|
+
"writeOnly",
|
|
56450
|
+
"readStatic"
|
|
56451
|
+
]);
|
|
56452
|
+
/**
|
|
56453
|
+
* One option or setting the appliance declares, with the constraints its description
|
|
56454
|
+
* gives. A `readWrite` descriptor that is `available` is what `setOption` accepts.
|
|
56455
|
+
*/
|
|
56456
|
+
var DishwasherOptionDescriptorSchema = object({
|
|
56457
|
+
/** Feature key (`Dishcare.Dishwasher.Option.ExtraDry`). */
|
|
56458
|
+
key: string(),
|
|
56459
|
+
/** Last segment of the key, for display. */
|
|
56460
|
+
name: string(),
|
|
56461
|
+
type: _enum([
|
|
56462
|
+
"boolean",
|
|
56463
|
+
"number",
|
|
56464
|
+
"enum",
|
|
56465
|
+
"string"
|
|
56466
|
+
]),
|
|
56467
|
+
access: DishwasherAccessSchema,
|
|
56468
|
+
/** The appliance reports this entity as currently available. */
|
|
56469
|
+
available: boolean(),
|
|
56470
|
+
/** Unit the description declares for a number; null when it declares none. */
|
|
56471
|
+
unit: string().nullable(),
|
|
56472
|
+
min: number().nullable(),
|
|
56473
|
+
max: number().nullable(),
|
|
56474
|
+
step: number().nullable(),
|
|
56475
|
+
/** Allowed members of an enum; null for other types. */
|
|
56476
|
+
enumValues: array(string()).nullable(),
|
|
56477
|
+
defaultValue: DishwasherValueSchema.nullable()
|
|
56478
|
+
});
|
|
56479
|
+
var DishwasherProgramSchema = object({
|
|
56480
|
+
/** Feature key (`Dishcare.Dishwasher.Program.Eco50`) — what `setProgram` / `start` take. */
|
|
56481
|
+
key: string(),
|
|
56482
|
+
name: string(),
|
|
56483
|
+
/** The appliance currently offers this program. */
|
|
56484
|
+
available: boolean(),
|
|
56485
|
+
/** The options this program lists, with the program-level access / availability / default. */
|
|
56486
|
+
options: array(DishwasherOptionDescriptorSchema)
|
|
56487
|
+
});
|
|
56488
|
+
var DishwasherOptionsSchema = object({
|
|
56489
|
+
availability: DishwasherAvailabilitySchema,
|
|
56490
|
+
/** What the appliance can be told to do, from the commands its description declares. */
|
|
56491
|
+
supportsStart: boolean(),
|
|
56492
|
+
supportsPause: boolean(),
|
|
56493
|
+
supportsResume: boolean(),
|
|
56494
|
+
supportsStop: boolean(),
|
|
56495
|
+
supportsPower: boolean(),
|
|
56496
|
+
/** Every program the description lists, with its options. */
|
|
56497
|
+
programs: array(DishwasherProgramSchema),
|
|
56498
|
+
/** Every option and setting entity the description lists (programs reference these by key). */
|
|
56499
|
+
options: array(DishwasherOptionDescriptorSchema)
|
|
56500
|
+
});
|
|
56501
|
+
var dishwasherCapability = {
|
|
56502
|
+
name: "dishwasher",
|
|
56503
|
+
scope: "device",
|
|
56504
|
+
deviceNative: true,
|
|
56505
|
+
mode: "singleton",
|
|
56506
|
+
deviceTypes: [DeviceType.Dishwasher],
|
|
56507
|
+
methods: {
|
|
56508
|
+
/**
|
|
56509
|
+
* Start a program. Without `program` the selected one starts. `options` are
|
|
56510
|
+
* option feature keys; each is checked against the program's constraints.
|
|
56511
|
+
*/
|
|
56512
|
+
start: method(object({
|
|
56513
|
+
deviceId: DeviceIdSchema,
|
|
56514
|
+
program: string().min(1).optional(),
|
|
56515
|
+
options: record(string(), DishwasherValueSchema).optional()
|
|
56516
|
+
}), _void(), {
|
|
56517
|
+
kind: "mutation",
|
|
56518
|
+
auth: "protected"
|
|
56519
|
+
}),
|
|
56520
|
+
pause: method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
56521
|
+
kind: "mutation",
|
|
56522
|
+
auth: "protected"
|
|
56523
|
+
}),
|
|
56524
|
+
resume: method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
56525
|
+
kind: "mutation",
|
|
56526
|
+
auth: "protected"
|
|
56527
|
+
}),
|
|
56528
|
+
stop: method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
56529
|
+
kind: "mutation",
|
|
56530
|
+
auth: "protected"
|
|
56531
|
+
}),
|
|
56532
|
+
/** Select (not start) a program; refused when the appliance does not offer it. */
|
|
56533
|
+
setProgram: method(object({
|
|
56534
|
+
deviceId: DeviceIdSchema,
|
|
56535
|
+
program: string().min(1)
|
|
56536
|
+
}), _void(), {
|
|
56537
|
+
kind: "mutation",
|
|
56538
|
+
auth: "protected"
|
|
56539
|
+
}),
|
|
56540
|
+
setPower: method(object({
|
|
56541
|
+
deviceId: DeviceIdSchema,
|
|
56542
|
+
on: boolean()
|
|
56543
|
+
}), _void(), {
|
|
56544
|
+
kind: "mutation",
|
|
56545
|
+
auth: "protected"
|
|
56546
|
+
}),
|
|
56547
|
+
setHalfLoad: method(object({
|
|
56548
|
+
deviceId: DeviceIdSchema,
|
|
56549
|
+
on: boolean()
|
|
56550
|
+
}), _void(), {
|
|
56551
|
+
kind: "mutation",
|
|
56552
|
+
auth: "protected"
|
|
56553
|
+
}),
|
|
56554
|
+
setHygienePlus: method(object({
|
|
56555
|
+
deviceId: DeviceIdSchema,
|
|
56556
|
+
on: boolean()
|
|
56557
|
+
}), _void(), {
|
|
56558
|
+
kind: "mutation",
|
|
56559
|
+
auth: "protected"
|
|
56560
|
+
}),
|
|
56561
|
+
setExtraDry: method(object({
|
|
56562
|
+
deviceId: DeviceIdSchema,
|
|
56563
|
+
on: boolean()
|
|
56564
|
+
}), _void(), {
|
|
56565
|
+
kind: "mutation",
|
|
56566
|
+
auth: "protected"
|
|
56567
|
+
}),
|
|
56568
|
+
setIntensiveZone: method(object({
|
|
56569
|
+
deviceId: DeviceIdSchema,
|
|
56570
|
+
on: boolean()
|
|
56571
|
+
}), _void(), {
|
|
56572
|
+
kind: "mutation",
|
|
56573
|
+
auth: "protected"
|
|
56574
|
+
}),
|
|
56575
|
+
setVarioSpeedPlus: method(object({
|
|
56576
|
+
deviceId: DeviceIdSchema,
|
|
56577
|
+
on: boolean()
|
|
56578
|
+
}), _void(), {
|
|
56579
|
+
kind: "mutation",
|
|
56580
|
+
auth: "protected"
|
|
56581
|
+
}),
|
|
56582
|
+
setChildLock: method(object({
|
|
56583
|
+
deviceId: DeviceIdSchema,
|
|
56584
|
+
on: boolean()
|
|
56585
|
+
}), _void(), {
|
|
56586
|
+
kind: "mutation",
|
|
56587
|
+
auth: "protected"
|
|
56588
|
+
}),
|
|
56589
|
+
/**
|
|
56590
|
+
* Write any option or setting by feature key. Refused when the description does
|
|
56591
|
+
* not list it, it is not writable or not available now, or the value is outside
|
|
56592
|
+
* its declared range / members.
|
|
56593
|
+
*/
|
|
56594
|
+
setOption: method(object({
|
|
56595
|
+
deviceId: DeviceIdSchema,
|
|
56596
|
+
key: string().min(1),
|
|
56597
|
+
value: DishwasherValueSchema
|
|
56598
|
+
}), _void(), {
|
|
56599
|
+
kind: "mutation",
|
|
56600
|
+
auth: "protected"
|
|
56601
|
+
}),
|
|
56602
|
+
/** What this appliance can do, from its own description — the UI is derived from it. */
|
|
56603
|
+
getOptions: method(object({ deviceId: DeviceIdSchema }), DishwasherOptionsSchema, { auth: "protected" })
|
|
56604
|
+
},
|
|
56605
|
+
status: {
|
|
56606
|
+
schema: DishwasherStatusSchema,
|
|
56607
|
+
kind: "poll"
|
|
56608
|
+
},
|
|
56609
|
+
runtimeState: DishwasherStatusSchema,
|
|
56610
|
+
durability: "session",
|
|
56611
|
+
history: { fields: { progressPercent: {
|
|
56612
|
+
kind: "gauge",
|
|
56613
|
+
unit: "%",
|
|
56614
|
+
deadband: 2
|
|
56615
|
+
} } }
|
|
56616
|
+
};
|
|
55631
56617
|
var DoorbellStatusSchema = object({
|
|
55632
56618
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
55633
56619
|
lastPressedAt: number().nullable(),
|
|
@@ -56430,6 +57416,32 @@ var gasCapability = {
|
|
|
56430
57416
|
* whether persisting is worth a SQLite commit. */
|
|
56431
57417
|
volatileStateFields: ["lastChangedAt"]
|
|
56432
57418
|
};
|
|
57419
|
+
var HeatingValveStatusSchema = object({
|
|
57420
|
+
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
57421
|
+
position: number().min(0).max(100).nullable(),
|
|
57422
|
+
/** Ms epoch when the slice was last updated (push or poll). */
|
|
57423
|
+
lastFetchedAt: number()
|
|
57424
|
+
});
|
|
57425
|
+
var heatingValveCapability = {
|
|
57426
|
+
name: "heating-valve",
|
|
57427
|
+
scope: "device",
|
|
57428
|
+
deviceNative: true,
|
|
57429
|
+
mode: "singleton",
|
|
57430
|
+
deviceTypes: [DeviceType.Thermostat],
|
|
57431
|
+
methods: {},
|
|
57432
|
+
status: {
|
|
57433
|
+
schema: HeatingValveStatusSchema,
|
|
57434
|
+
kind: "push"
|
|
57435
|
+
},
|
|
57436
|
+
runtimeState: HeatingValveStatusSchema,
|
|
57437
|
+
durability: "session",
|
|
57438
|
+
history: { fields: { position: {
|
|
57439
|
+
kind: "gauge",
|
|
57440
|
+
unit: "%",
|
|
57441
|
+
deadband: 1
|
|
57442
|
+
} } },
|
|
57443
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
57444
|
+
};
|
|
56433
57445
|
/**
|
|
56434
57446
|
* Humidifier / dehumidifier cap. Models HA `humidifier.*` entities —
|
|
56435
57447
|
* an on/off actuator with an optional target-humidity setpoint and an
|
|
@@ -57562,7 +58574,19 @@ var TlsStatusSchema = object({
|
|
|
57562
58574
|
sans: array(string()),
|
|
57563
58575
|
caCertPem: string().nullable(),
|
|
57564
58576
|
reissueError: string().nullable(),
|
|
57565
|
-
restartRequired: boolean()
|
|
58577
|
+
restartRequired: boolean(),
|
|
58578
|
+
/** An uploaded certificate is served but no CA is kept for it and it is not publicly signed (D873). */
|
|
58579
|
+
caMissing: boolean(),
|
|
58580
|
+
/** Does the hub's own generated CA carry a critical name constraint? `null` while it has none. */
|
|
58581
|
+
localCaConstrained: boolean().nullable(),
|
|
58582
|
+
/** ISO time the generated CA was replaced by a constrained one; devices must re-download it. */
|
|
58583
|
+
caReplacedAt: string().nullable(),
|
|
58584
|
+
/** The uploaded certificate kept on disk, selectable again after "Revert to generated". */
|
|
58585
|
+
storedUpload: object({
|
|
58586
|
+
leafFingerprintSha256: string(),
|
|
58587
|
+
validTo: string(),
|
|
58588
|
+
hasCa: boolean()
|
|
58589
|
+
}).nullable()
|
|
57566
58590
|
});
|
|
57567
58591
|
method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
|
|
57568
58592
|
/**
|
|
@@ -57618,6 +58642,9 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
|
|
|
57618
58642
|
}), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
|
|
57619
58643
|
kind: "mutation",
|
|
57620
58644
|
auth: "admin"
|
|
58645
|
+
}), method(_void(), TlsStatusSchema, {
|
|
58646
|
+
kind: "mutation",
|
|
58647
|
+
auth: "admin"
|
|
57621
58648
|
});
|
|
57622
58649
|
var LockControlStatusSchema = object({
|
|
57623
58650
|
/** Lifecycle state of the lock. `jammed` means the motor reported
|
|
@@ -64111,7 +65138,11 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
|
|
|
64111
65138
|
kind: "mutation",
|
|
64112
65139
|
auth: "admin",
|
|
64113
65140
|
access: "delete"
|
|
64114
|
-
}), method(object({ userId: string() }), TotpStatusSchema, { auth: "admin" }), method(
|
|
65141
|
+
}), method(object({ userId: string() }), TotpStatusSchema, { auth: "admin" }), method(RawSecretMigrationInputSchema, RawSecretMigrationReportSchema, {
|
|
65142
|
+
kind: "mutation",
|
|
65143
|
+
auth: "admin",
|
|
65144
|
+
access: "create"
|
|
65145
|
+
}), method(object({
|
|
64115
65146
|
userId: string(),
|
|
64116
65147
|
code: string()
|
|
64117
65148
|
}), object({ valid: boolean() }), {
|
|
@@ -65831,6 +66862,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
65831
66862
|
dayNight: dayNightCapability,
|
|
65832
66863
|
deviceDiscovery: deviceDiscoveryCapability,
|
|
65833
66864
|
deviceStatus: deviceStatusCapability,
|
|
66865
|
+
dishwasher: dishwasherCapability,
|
|
65834
66866
|
doorbell: doorbellCapability,
|
|
65835
66867
|
enumSensor: enumSensorCapability,
|
|
65836
66868
|
eventEmitter: eventEmitterCapability,
|
|
@@ -65838,6 +66870,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
65838
66870
|
featureProbe: featureProbeCapability,
|
|
65839
66871
|
flood: floodCapability,
|
|
65840
66872
|
gas: gasCapability,
|
|
66873
|
+
heatingValve: heatingValveCapability,
|
|
65841
66874
|
humidifier: humidifierCapability,
|
|
65842
66875
|
humiditySensor: humiditySensorCapability,
|
|
65843
66876
|
image: imageCapability,
|
|
@@ -65923,13 +66956,14 @@ var BaseDevice = class {
|
|
|
65923
66956
|
get state() {
|
|
65924
66957
|
if (!this._stateProxyCache) {
|
|
65925
66958
|
const cache = {};
|
|
65926
|
-
const handler = { get: (
|
|
66959
|
+
const handler = { get: (target, key) => {
|
|
65927
66960
|
const k = key;
|
|
65928
|
-
|
|
66961
|
+
const existing = Reflect.get(target, k);
|
|
66962
|
+
if (existing !== void 0) return existing;
|
|
65929
66963
|
const cap = DEVICE_LOCAL_STATE_CAPS[k];
|
|
65930
66964
|
if (!cap) return void 0;
|
|
65931
66965
|
const proxy = this.sliceProxy(cap);
|
|
65932
|
-
|
|
66966
|
+
Reflect.set(target, k, proxy);
|
|
65933
66967
|
return proxy;
|
|
65934
66968
|
} };
|
|
65935
66969
|
this._stateProxyCache = new Proxy(cache, handler);
|
|
@@ -66128,7 +67162,7 @@ var BaseDevice = class {
|
|
|
66128
67162
|
async updateSourceInfo(patch) {
|
|
66129
67163
|
const next = mergeSourceInfo(this.sourceInfo, patch);
|
|
66130
67164
|
this._sourceInfoCache = Object.freeze({ ...next });
|
|
66131
|
-
const action = this.ctx.api
|
|
67165
|
+
const action = this.ctx.api.deviceManager?.setMetadata;
|
|
66132
67166
|
if (action) try {
|
|
66133
67167
|
await action.mutate({
|
|
66134
67168
|
deviceId: this.id,
|
|
@@ -66163,7 +67197,7 @@ var BaseDevice = class {
|
|
|
66163
67197
|
* device boot on a meta refresh.
|
|
66164
67198
|
*/
|
|
66165
67199
|
async refreshFeatures() {
|
|
66166
|
-
const action = this.ctx.api
|
|
67200
|
+
const action = this.ctx.api.deviceManager?.registerDevice;
|
|
66167
67201
|
if (!action) return;
|
|
66168
67202
|
try {
|
|
66169
67203
|
await action.mutate({
|
|
@@ -66562,6 +67596,12 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
66562
67596
|
provider: this
|
|
66563
67597
|
}];
|
|
66564
67598
|
}
|
|
67599
|
+
/** Flatten `super.onInitialize()` whether it returned an array or an envelope. */
|
|
67600
|
+
providerRegistrationsFromSuper(result) {
|
|
67601
|
+
if (Array.isArray(result)) return result;
|
|
67602
|
+
if (result !== void 0 && result.providers !== void 0) return [...result.providers];
|
|
67603
|
+
return [];
|
|
67604
|
+
}
|
|
66565
67605
|
async onShutdown() {
|
|
66566
67606
|
this._restoreShuttingDown = true;
|
|
66567
67607
|
this.cancelRestoreRetries();
|
|
@@ -67088,7 +68128,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
67088
68128
|
return toDeviceSummary(device, this.addonId);
|
|
67089
68129
|
}
|
|
67090
68130
|
};
|
|
67091
|
-
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
|
|
68131
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
67092
68132
|
new Set(Object.values(DeviceType));
|
|
67093
68133
|
Object.freeze({
|
|
67094
68134
|
"accessories.getStatus": {
|
|
@@ -68237,6 +69277,12 @@ Object.freeze({
|
|
|
68237
69277
|
addonId: null,
|
|
68238
69278
|
access: "view"
|
|
68239
69279
|
},
|
|
69280
|
+
"coreBlocks.migrateRawSecrets": {
|
|
69281
|
+
capName: "core-blocks",
|
|
69282
|
+
capScope: "system",
|
|
69283
|
+
addonId: null,
|
|
69284
|
+
access: "create"
|
|
69285
|
+
},
|
|
68240
69286
|
"coreBlocks.restart": {
|
|
68241
69287
|
capName: "core-blocks",
|
|
68242
69288
|
capScope: "system",
|
|
@@ -69503,6 +70549,96 @@ Object.freeze({
|
|
|
69503
70549
|
addonId: null,
|
|
69504
70550
|
access: "view"
|
|
69505
70551
|
},
|
|
70552
|
+
"dishwasher.getOptions": {
|
|
70553
|
+
capName: "dishwasher",
|
|
70554
|
+
capScope: "device",
|
|
70555
|
+
addonId: null,
|
|
70556
|
+
access: "view"
|
|
70557
|
+
},
|
|
70558
|
+
"dishwasher.getStatus": {
|
|
70559
|
+
capName: "dishwasher",
|
|
70560
|
+
capScope: "device",
|
|
70561
|
+
addonId: null,
|
|
70562
|
+
access: "view"
|
|
70563
|
+
},
|
|
70564
|
+
"dishwasher.pause": {
|
|
70565
|
+
capName: "dishwasher",
|
|
70566
|
+
capScope: "device",
|
|
70567
|
+
addonId: null,
|
|
70568
|
+
access: "create"
|
|
70569
|
+
},
|
|
70570
|
+
"dishwasher.resume": {
|
|
70571
|
+
capName: "dishwasher",
|
|
70572
|
+
capScope: "device",
|
|
70573
|
+
addonId: null,
|
|
70574
|
+
access: "create"
|
|
70575
|
+
},
|
|
70576
|
+
"dishwasher.setChildLock": {
|
|
70577
|
+
capName: "dishwasher",
|
|
70578
|
+
capScope: "device",
|
|
70579
|
+
addonId: null,
|
|
70580
|
+
access: "create"
|
|
70581
|
+
},
|
|
70582
|
+
"dishwasher.setExtraDry": {
|
|
70583
|
+
capName: "dishwasher",
|
|
70584
|
+
capScope: "device",
|
|
70585
|
+
addonId: null,
|
|
70586
|
+
access: "create"
|
|
70587
|
+
},
|
|
70588
|
+
"dishwasher.setHalfLoad": {
|
|
70589
|
+
capName: "dishwasher",
|
|
70590
|
+
capScope: "device",
|
|
70591
|
+
addonId: null,
|
|
70592
|
+
access: "create"
|
|
70593
|
+
},
|
|
70594
|
+
"dishwasher.setHygienePlus": {
|
|
70595
|
+
capName: "dishwasher",
|
|
70596
|
+
capScope: "device",
|
|
70597
|
+
addonId: null,
|
|
70598
|
+
access: "create"
|
|
70599
|
+
},
|
|
70600
|
+
"dishwasher.setIntensiveZone": {
|
|
70601
|
+
capName: "dishwasher",
|
|
70602
|
+
capScope: "device",
|
|
70603
|
+
addonId: null,
|
|
70604
|
+
access: "create"
|
|
70605
|
+
},
|
|
70606
|
+
"dishwasher.setOption": {
|
|
70607
|
+
capName: "dishwasher",
|
|
70608
|
+
capScope: "device",
|
|
70609
|
+
addonId: null,
|
|
70610
|
+
access: "create"
|
|
70611
|
+
},
|
|
70612
|
+
"dishwasher.setPower": {
|
|
70613
|
+
capName: "dishwasher",
|
|
70614
|
+
capScope: "device",
|
|
70615
|
+
addonId: null,
|
|
70616
|
+
access: "create"
|
|
70617
|
+
},
|
|
70618
|
+
"dishwasher.setProgram": {
|
|
70619
|
+
capName: "dishwasher",
|
|
70620
|
+
capScope: "device",
|
|
70621
|
+
addonId: null,
|
|
70622
|
+
access: "create"
|
|
70623
|
+
},
|
|
70624
|
+
"dishwasher.setVarioSpeedPlus": {
|
|
70625
|
+
capName: "dishwasher",
|
|
70626
|
+
capScope: "device",
|
|
70627
|
+
addonId: null,
|
|
70628
|
+
access: "create"
|
|
70629
|
+
},
|
|
70630
|
+
"dishwasher.start": {
|
|
70631
|
+
capName: "dishwasher",
|
|
70632
|
+
capScope: "device",
|
|
70633
|
+
addonId: null,
|
|
70634
|
+
access: "create"
|
|
70635
|
+
},
|
|
70636
|
+
"dishwasher.stop": {
|
|
70637
|
+
capName: "dishwasher",
|
|
70638
|
+
capScope: "device",
|
|
70639
|
+
addonId: null,
|
|
70640
|
+
access: "create"
|
|
70641
|
+
},
|
|
69506
70642
|
"doorbell.getStatus": {
|
|
69507
70643
|
capName: "doorbell",
|
|
69508
70644
|
capScope: "device",
|
|
@@ -69713,6 +70849,12 @@ Object.freeze({
|
|
|
69713
70849
|
addonId: null,
|
|
69714
70850
|
access: "view"
|
|
69715
70851
|
},
|
|
70852
|
+
"heatingValve.getStatus": {
|
|
70853
|
+
capName: "heating-valve",
|
|
70854
|
+
capScope: "device",
|
|
70855
|
+
addonId: null,
|
|
70856
|
+
access: "view"
|
|
70857
|
+
},
|
|
69716
70858
|
"humidifier.getStatus": {
|
|
69717
70859
|
capName: "humidifier",
|
|
69718
70860
|
capScope: "device",
|
|
@@ -69923,6 +71065,12 @@ Object.freeze({
|
|
|
69923
71065
|
addonId: null,
|
|
69924
71066
|
access: "create"
|
|
69925
71067
|
},
|
|
71068
|
+
"keychainAdmin.importSecret": {
|
|
71069
|
+
capName: "keychain-admin",
|
|
71070
|
+
capScope: "system",
|
|
71071
|
+
addonId: null,
|
|
71072
|
+
access: "create"
|
|
71073
|
+
},
|
|
69926
71074
|
"keychainAdmin.listAudit": {
|
|
69927
71075
|
capName: "keychain-admin",
|
|
69928
71076
|
capScope: "system",
|
|
@@ -70091,6 +71239,12 @@ Object.freeze({
|
|
|
70091
71239
|
addonId: null,
|
|
70092
71240
|
access: "view"
|
|
70093
71241
|
},
|
|
71242
|
+
"llm.migrateRawSecrets": {
|
|
71243
|
+
capName: "llm",
|
|
71244
|
+
capScope: "system",
|
|
71245
|
+
addonId: null,
|
|
71246
|
+
access: "create"
|
|
71247
|
+
},
|
|
70094
71248
|
"llm.resolveModelRef": {
|
|
70095
71249
|
capName: "llm",
|
|
70096
71250
|
capScope: "system",
|
|
@@ -70319,6 +71473,12 @@ Object.freeze({
|
|
|
70319
71473
|
addonId: null,
|
|
70320
71474
|
access: "create"
|
|
70321
71475
|
},
|
|
71476
|
+
"localNetwork.useStoredUploadedCertificate": {
|
|
71477
|
+
capName: "local-network",
|
|
71478
|
+
capScope: "system",
|
|
71479
|
+
addonId: null,
|
|
71480
|
+
access: "create"
|
|
71481
|
+
},
|
|
70322
71482
|
"lockControl.getStatus": {
|
|
70323
71483
|
capName: "lock-control",
|
|
70324
71484
|
capScope: "device",
|
|
@@ -72971,6 +74131,30 @@ Object.freeze({
|
|
|
72971
74131
|
addonId: null,
|
|
72972
74132
|
access: "create"
|
|
72973
74133
|
},
|
|
74134
|
+
"recordEntries.deleteEntry": {
|
|
74135
|
+
capName: "record-entries",
|
|
74136
|
+
capScope: "system",
|
|
74137
|
+
addonId: null,
|
|
74138
|
+
access: "delete"
|
|
74139
|
+
},
|
|
74140
|
+
"recordEntries.listEntries": {
|
|
74141
|
+
capName: "record-entries",
|
|
74142
|
+
capScope: "system",
|
|
74143
|
+
addonId: null,
|
|
74144
|
+
access: "view"
|
|
74145
|
+
},
|
|
74146
|
+
"recordEntries.listEntryKinds": {
|
|
74147
|
+
capName: "record-entries",
|
|
74148
|
+
capScope: "system",
|
|
74149
|
+
addonId: null,
|
|
74150
|
+
access: "view"
|
|
74151
|
+
},
|
|
74152
|
+
"recordEntries.putEntry": {
|
|
74153
|
+
capName: "record-entries",
|
|
74154
|
+
capScope: "system",
|
|
74155
|
+
addonId: null,
|
|
74156
|
+
access: "create"
|
|
74157
|
+
},
|
|
72974
74158
|
"recording.getAvailability": {
|
|
72975
74159
|
capName: "recording",
|
|
72976
74160
|
capScope: "device",
|
|
@@ -73271,6 +74455,102 @@ Object.freeze({
|
|
|
73271
74455
|
addonId: null,
|
|
73272
74456
|
access: "view"
|
|
73273
74457
|
},
|
|
74458
|
+
"records.aggregate": {
|
|
74459
|
+
capName: "records",
|
|
74460
|
+
capScope: "system",
|
|
74461
|
+
addonId: null,
|
|
74462
|
+
access: "view"
|
|
74463
|
+
},
|
|
74464
|
+
"records.allocateId": {
|
|
74465
|
+
capName: "records",
|
|
74466
|
+
capScope: "system",
|
|
74467
|
+
addonId: null,
|
|
74468
|
+
access: "create"
|
|
74469
|
+
},
|
|
74470
|
+
"records.count": {
|
|
74471
|
+
capName: "records",
|
|
74472
|
+
capScope: "system",
|
|
74473
|
+
addonId: null,
|
|
74474
|
+
access: "view"
|
|
74475
|
+
},
|
|
74476
|
+
"records.declareKinds": {
|
|
74477
|
+
capName: "records",
|
|
74478
|
+
capScope: "system",
|
|
74479
|
+
addonId: null,
|
|
74480
|
+
access: "create"
|
|
74481
|
+
},
|
|
74482
|
+
"records.delete": {
|
|
74483
|
+
capName: "records",
|
|
74484
|
+
capScope: "system",
|
|
74485
|
+
addonId: null,
|
|
74486
|
+
access: "delete"
|
|
74487
|
+
},
|
|
74488
|
+
"records.deleteDevice": {
|
|
74489
|
+
capName: "records",
|
|
74490
|
+
capScope: "system",
|
|
74491
|
+
addonId: null,
|
|
74492
|
+
access: "delete"
|
|
74493
|
+
},
|
|
74494
|
+
"records.deleteMany": {
|
|
74495
|
+
capName: "records",
|
|
74496
|
+
capScope: "system",
|
|
74497
|
+
addonId: null,
|
|
74498
|
+
access: "delete"
|
|
74499
|
+
},
|
|
74500
|
+
"records.deleteWhere": {
|
|
74501
|
+
capName: "records",
|
|
74502
|
+
capScope: "system",
|
|
74503
|
+
addonId: null,
|
|
74504
|
+
access: "delete"
|
|
74505
|
+
},
|
|
74506
|
+
"records.get": {
|
|
74507
|
+
capName: "records",
|
|
74508
|
+
capScope: "system",
|
|
74509
|
+
addonId: null,
|
|
74510
|
+
access: "view"
|
|
74511
|
+
},
|
|
74512
|
+
"records.getMany": {
|
|
74513
|
+
capName: "records",
|
|
74514
|
+
capScope: "system",
|
|
74515
|
+
addonId: null,
|
|
74516
|
+
access: "view"
|
|
74517
|
+
},
|
|
74518
|
+
"records.histogram": {
|
|
74519
|
+
capName: "records",
|
|
74520
|
+
capScope: "system",
|
|
74521
|
+
addonId: null,
|
|
74522
|
+
access: "view"
|
|
74523
|
+
},
|
|
74524
|
+
"records.patch": {
|
|
74525
|
+
capName: "records",
|
|
74526
|
+
capScope: "system",
|
|
74527
|
+
addonId: null,
|
|
74528
|
+
access: "create"
|
|
74529
|
+
},
|
|
74530
|
+
"records.put": {
|
|
74531
|
+
capName: "records",
|
|
74532
|
+
capScope: "system",
|
|
74533
|
+
addonId: null,
|
|
74534
|
+
access: "create"
|
|
74535
|
+
},
|
|
74536
|
+
"records.putMany": {
|
|
74537
|
+
capName: "records",
|
|
74538
|
+
capScope: "system",
|
|
74539
|
+
addonId: null,
|
|
74540
|
+
access: "create"
|
|
74541
|
+
},
|
|
74542
|
+
"records.query": {
|
|
74543
|
+
capName: "records",
|
|
74544
|
+
capScope: "system",
|
|
74545
|
+
addonId: null,
|
|
74546
|
+
access: "view"
|
|
74547
|
+
},
|
|
74548
|
+
"records.secretRefs": {
|
|
74549
|
+
capName: "records",
|
|
74550
|
+
capScope: "system",
|
|
74551
|
+
addonId: null,
|
|
74552
|
+
access: "view"
|
|
74553
|
+
},
|
|
73274
74554
|
"sceneMonitor.captureReference": {
|
|
73275
74555
|
capName: "scene-monitor",
|
|
73276
74556
|
capScope: "device",
|
|
@@ -73703,6 +74983,48 @@ Object.freeze({
|
|
|
73703
74983
|
addonId: null,
|
|
73704
74984
|
access: "create"
|
|
73705
74985
|
},
|
|
74986
|
+
"storageAdmin.adoptRecords": {
|
|
74987
|
+
capName: "storage-admin",
|
|
74988
|
+
capScope: "system",
|
|
74989
|
+
addonId: null,
|
|
74990
|
+
access: "create"
|
|
74991
|
+
},
|
|
74992
|
+
"storageAdmin.dropCollection": {
|
|
74993
|
+
capName: "storage-admin",
|
|
74994
|
+
capScope: "system",
|
|
74995
|
+
addonId: null,
|
|
74996
|
+
access: "delete"
|
|
74997
|
+
},
|
|
74998
|
+
"storageAdmin.isAdoptedLegacyTable": {
|
|
74999
|
+
capName: "storage-admin",
|
|
75000
|
+
capScope: "system",
|
|
75001
|
+
addonId: null,
|
|
75002
|
+
access: "view"
|
|
75003
|
+
},
|
|
75004
|
+
"storageAdmin.listKinds": {
|
|
75005
|
+
capName: "storage-admin",
|
|
75006
|
+
capScope: "system",
|
|
75007
|
+
addonId: null,
|
|
75008
|
+
access: "view"
|
|
75009
|
+
},
|
|
75010
|
+
"storageAdmin.listTables": {
|
|
75011
|
+
capName: "storage-admin",
|
|
75012
|
+
capScope: "system",
|
|
75013
|
+
addonId: null,
|
|
75014
|
+
access: "view"
|
|
75015
|
+
},
|
|
75016
|
+
"storageAdmin.readLegacyCollection": {
|
|
75017
|
+
capName: "storage-admin",
|
|
75018
|
+
capScope: "system",
|
|
75019
|
+
addonId: null,
|
|
75020
|
+
access: "view"
|
|
75021
|
+
},
|
|
75022
|
+
"storageAdmin.readRecords": {
|
|
75023
|
+
capName: "storage-admin",
|
|
75024
|
+
capScope: "system",
|
|
75025
|
+
addonId: null,
|
|
75026
|
+
access: "view"
|
|
75027
|
+
},
|
|
73706
75028
|
"storageEvictable.evict": {
|
|
73707
75029
|
capName: "storage-evictable",
|
|
73708
75030
|
capScope: "system",
|
|
@@ -73751,6 +75073,12 @@ Object.freeze({
|
|
|
73751
75073
|
addonId: null,
|
|
73752
75074
|
access: "view"
|
|
73753
75075
|
},
|
|
75076
|
+
"storageMigration.moverClearance": {
|
|
75077
|
+
capName: "storage-migration",
|
|
75078
|
+
capScope: "system",
|
|
75079
|
+
addonId: null,
|
|
75080
|
+
access: "view"
|
|
75081
|
+
},
|
|
73754
75082
|
"storageMigration.movers": {
|
|
73755
75083
|
capName: "storage-migration",
|
|
73756
75084
|
capScope: "system",
|
|
@@ -74615,6 +75943,12 @@ Object.freeze({
|
|
|
74615
75943
|
addonId: null,
|
|
74616
75944
|
access: "view"
|
|
74617
75945
|
},
|
|
75946
|
+
"userManagement.migrateRawSecrets": {
|
|
75947
|
+
capName: "user-management",
|
|
75948
|
+
capScope: "system",
|
|
75949
|
+
addonId: null,
|
|
75950
|
+
access: "create"
|
|
75951
|
+
},
|
|
74618
75952
|
"userManagement.oauthExchangeCode": {
|
|
74619
75953
|
capName: "user-management",
|
|
74620
75954
|
capScope: "system",
|
|
@@ -75114,7 +76448,7 @@ Object.freeze({
|
|
|
75114
76448
|
access: "create"
|
|
75115
76449
|
}
|
|
75116
76450
|
});
|
|
75117
|
-
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
|
|
76451
|
+
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
75118
76452
|
DeviceFeature.BatteryOperated;
|
|
75119
76453
|
Object.freeze({
|
|
75120
76454
|
"accessories.getStatus": [{
|
|
@@ -75938,6 +77272,81 @@ Object.freeze({
|
|
|
75938
77272
|
form: "single",
|
|
75939
77273
|
optional: false
|
|
75940
77274
|
}],
|
|
77275
|
+
"dishwasher.getOptions": [{
|
|
77276
|
+
name: "deviceId",
|
|
77277
|
+
form: "single",
|
|
77278
|
+
optional: false
|
|
77279
|
+
}],
|
|
77280
|
+
"dishwasher.getStatus": [{
|
|
77281
|
+
name: "deviceId",
|
|
77282
|
+
form: "single",
|
|
77283
|
+
optional: false
|
|
77284
|
+
}],
|
|
77285
|
+
"dishwasher.pause": [{
|
|
77286
|
+
name: "deviceId",
|
|
77287
|
+
form: "single",
|
|
77288
|
+
optional: false
|
|
77289
|
+
}],
|
|
77290
|
+
"dishwasher.resume": [{
|
|
77291
|
+
name: "deviceId",
|
|
77292
|
+
form: "single",
|
|
77293
|
+
optional: false
|
|
77294
|
+
}],
|
|
77295
|
+
"dishwasher.setChildLock": [{
|
|
77296
|
+
name: "deviceId",
|
|
77297
|
+
form: "single",
|
|
77298
|
+
optional: false
|
|
77299
|
+
}],
|
|
77300
|
+
"dishwasher.setExtraDry": [{
|
|
77301
|
+
name: "deviceId",
|
|
77302
|
+
form: "single",
|
|
77303
|
+
optional: false
|
|
77304
|
+
}],
|
|
77305
|
+
"dishwasher.setHalfLoad": [{
|
|
77306
|
+
name: "deviceId",
|
|
77307
|
+
form: "single",
|
|
77308
|
+
optional: false
|
|
77309
|
+
}],
|
|
77310
|
+
"dishwasher.setHygienePlus": [{
|
|
77311
|
+
name: "deviceId",
|
|
77312
|
+
form: "single",
|
|
77313
|
+
optional: false
|
|
77314
|
+
}],
|
|
77315
|
+
"dishwasher.setIntensiveZone": [{
|
|
77316
|
+
name: "deviceId",
|
|
77317
|
+
form: "single",
|
|
77318
|
+
optional: false
|
|
77319
|
+
}],
|
|
77320
|
+
"dishwasher.setOption": [{
|
|
77321
|
+
name: "deviceId",
|
|
77322
|
+
form: "single",
|
|
77323
|
+
optional: false
|
|
77324
|
+
}],
|
|
77325
|
+
"dishwasher.setPower": [{
|
|
77326
|
+
name: "deviceId",
|
|
77327
|
+
form: "single",
|
|
77328
|
+
optional: false
|
|
77329
|
+
}],
|
|
77330
|
+
"dishwasher.setProgram": [{
|
|
77331
|
+
name: "deviceId",
|
|
77332
|
+
form: "single",
|
|
77333
|
+
optional: false
|
|
77334
|
+
}],
|
|
77335
|
+
"dishwasher.setVarioSpeedPlus": [{
|
|
77336
|
+
name: "deviceId",
|
|
77337
|
+
form: "single",
|
|
77338
|
+
optional: false
|
|
77339
|
+
}],
|
|
77340
|
+
"dishwasher.start": [{
|
|
77341
|
+
name: "deviceId",
|
|
77342
|
+
form: "single",
|
|
77343
|
+
optional: false
|
|
77344
|
+
}],
|
|
77345
|
+
"dishwasher.stop": [{
|
|
77346
|
+
name: "deviceId",
|
|
77347
|
+
form: "single",
|
|
77348
|
+
optional: false
|
|
77349
|
+
}],
|
|
75941
77350
|
"doorbell.getStatus": [{
|
|
75942
77351
|
name: "deviceId",
|
|
75943
77352
|
form: "single",
|
|
@@ -76007,6 +77416,11 @@ Object.freeze({
|
|
|
76007
77416
|
form: "single",
|
|
76008
77417
|
optional: false
|
|
76009
77418
|
}],
|
|
77419
|
+
"heatingValve.getStatus": [{
|
|
77420
|
+
name: "deviceId",
|
|
77421
|
+
form: "single",
|
|
77422
|
+
optional: false
|
|
77423
|
+
}],
|
|
76010
77424
|
"humidifier.getStatus": [{
|
|
76011
77425
|
name: "deviceId",
|
|
76012
77426
|
form: "single",
|
|
@@ -77291,6 +78705,37 @@ Object.freeze({
|
|
|
77291
78705
|
form: "single",
|
|
77292
78706
|
optional: false
|
|
77293
78707
|
}],
|
|
78708
|
+
"records.count": [{
|
|
78709
|
+
name: "deviceId",
|
|
78710
|
+
form: "single",
|
|
78711
|
+
optional: true
|
|
78712
|
+
}],
|
|
78713
|
+
"records.deleteDevice": [{
|
|
78714
|
+
name: "deviceId",
|
|
78715
|
+
form: "single",
|
|
78716
|
+
optional: false
|
|
78717
|
+
}],
|
|
78718
|
+
"records.deleteWhere": [{
|
|
78719
|
+
name: "deviceId",
|
|
78720
|
+
form: "single",
|
|
78721
|
+
optional: true
|
|
78722
|
+
}],
|
|
78723
|
+
"records.histogram": [{
|
|
78724
|
+
name: "deviceId",
|
|
78725
|
+
form: "single",
|
|
78726
|
+
optional: true
|
|
78727
|
+
}],
|
|
78728
|
+
"records.putMany": [{
|
|
78729
|
+
name: "records",
|
|
78730
|
+
form: "object-array",
|
|
78731
|
+
optional: false,
|
|
78732
|
+
itemField: "deviceId"
|
|
78733
|
+
}],
|
|
78734
|
+
"records.query": [{
|
|
78735
|
+
name: "deviceId",
|
|
78736
|
+
form: "single",
|
|
78737
|
+
optional: true
|
|
78738
|
+
}],
|
|
77294
78739
|
"sceneMonitor.captureReference": [{
|
|
77295
78740
|
name: "deviceId",
|
|
77296
78741
|
form: "single",
|
|
@@ -77407,6 +78852,17 @@ Object.freeze({
|
|
|
77407
78852
|
form: "single",
|
|
77408
78853
|
optional: false
|
|
77409
78854
|
}],
|
|
78855
|
+
"storageAdmin.adoptRecords": [{
|
|
78856
|
+
name: "records",
|
|
78857
|
+
form: "object-array",
|
|
78858
|
+
optional: false,
|
|
78859
|
+
itemField: "deviceId"
|
|
78860
|
+
}],
|
|
78861
|
+
"storageAdmin.readRecords": [{
|
|
78862
|
+
name: "deviceId",
|
|
78863
|
+
form: "single",
|
|
78864
|
+
optional: true
|
|
78865
|
+
}],
|
|
77410
78866
|
"streamBroker.acquireEgressTranscode": [{
|
|
77411
78867
|
name: "deviceId",
|
|
77412
78868
|
form: "single",
|
|
@@ -77922,6 +79378,9 @@ new Map(Object.entries({
|
|
|
77922
79378
|
"wrapper-update-available": "system",
|
|
77923
79379
|
"backup-completed": "system",
|
|
77924
79380
|
"export-completed": "system",
|
|
79381
|
+
"alert-critical": "system",
|
|
79382
|
+
"alert-error": "system",
|
|
79383
|
+
"alert-critical-resolved": "system",
|
|
77925
79384
|
"storage-location-low": "system",
|
|
77926
79385
|
"storage-location-critical": "system",
|
|
77927
79386
|
"storage-location-ok": "system",
|
|
@@ -78046,6 +79505,16 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
78046
79505
|
"storage-location-ok"
|
|
78047
79506
|
]
|
|
78048
79507
|
},
|
|
79508
|
+
{
|
|
79509
|
+
id: "alerts",
|
|
79510
|
+
family: "system",
|
|
79511
|
+
label: "Alerts",
|
|
79512
|
+
kinds: [
|
|
79513
|
+
"alert-critical",
|
|
79514
|
+
"alert-error",
|
|
79515
|
+
"alert-critical-resolved"
|
|
79516
|
+
]
|
|
79517
|
+
},
|
|
78049
79518
|
{
|
|
78050
79519
|
id: "alarm",
|
|
78051
79520
|
family: "alarm",
|
|
@@ -78090,6 +79559,21 @@ var NC_SENSOR_RAISED_FIELD_BY_KIND = Object.freeze(Object.fromEntries(Object.ent
|
|
|
78090
79559
|
return [[descriptor.kind, field]];
|
|
78091
79560
|
})));
|
|
78092
79561
|
Object.freeze(Object.keys(NC_SENSOR_RAISED_FIELD_BY_KIND));
|
|
79562
|
+
object({
|
|
79563
|
+
phase: _enum(["raised", "resolved"]),
|
|
79564
|
+
episodeId: string().min(1),
|
|
79565
|
+
alertId: string().min(1),
|
|
79566
|
+
severity: AlertSeveritySchema,
|
|
79567
|
+
category: string(),
|
|
79568
|
+
title: string(),
|
|
79569
|
+
message: string(),
|
|
79570
|
+
sourceType: string().optional(),
|
|
79571
|
+
sourceId: string().optional(),
|
|
79572
|
+
nodeId: string().optional(),
|
|
79573
|
+
/** The alert's own action link (where the operator acts on it), when it has one. */
|
|
79574
|
+
actionUrl: string().optional(),
|
|
79575
|
+
at: number()
|
|
79576
|
+
});
|
|
78093
79577
|
var RULE_BODY_ONLY = ["body"];
|
|
78094
79578
|
var RULE_TEXT = ["title", "body"];
|
|
78095
79579
|
var BATTERY = ["device-battery-low", "device-battery-normal"];
|
|
@@ -78099,6 +79583,11 @@ var TANK = [
|
|
|
78099
79583
|
"device-tank-full",
|
|
78100
79584
|
"device-tank-normal"
|
|
78101
79585
|
];
|
|
79586
|
+
var ALERT_EPISODE = [
|
|
79587
|
+
"alert-critical",
|
|
79588
|
+
"alert-error",
|
|
79589
|
+
"alert-critical-resolved"
|
|
79590
|
+
];
|
|
78102
79591
|
var UPDATES = [
|
|
78103
79592
|
"addon-update-available",
|
|
78104
79593
|
"server-update-available",
|
|
@@ -78291,14 +79780,14 @@ var STATE_SUMMARY_VARS = [
|
|
|
78291
79780
|
([...RULE_TEXT], [...CONSUMABLE]),
|
|
78292
79781
|
([...RULE_TEXT], [...TANK]),
|
|
78293
79782
|
[...RULE_TEXT],
|
|
78294
|
-
([...RULE_TEXT], [...UPDATES]),
|
|
78295
|
-
([...RULE_TEXT], [...UPDATES]),
|
|
78296
|
-
[...RULE_TEXT],
|
|
79783
|
+
([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
|
|
79784
|
+
([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
|
|
78297
79785
|
[...RULE_TEXT],
|
|
78298
79786
|
[...RULE_TEXT],
|
|
78299
79787
|
[...RULE_TEXT],
|
|
78300
79788
|
[...RULE_TEXT],
|
|
78301
79789
|
[...RULE_TEXT],
|
|
79790
|
+
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
78302
79791
|
[...RULE_TEXT],
|
|
78303
79792
|
[...RULE_TEXT],
|
|
78304
79793
|
[...RULE_TEXT],
|
|
@@ -78316,7 +79805,11 @@ var STATE_SUMMARY_VARS = [
|
|
|
78316
79805
|
[...RULE_TEXT],
|
|
78317
79806
|
[...RULE_TEXT],
|
|
78318
79807
|
[...RULE_TEXT],
|
|
78319
|
-
[...RULE_TEXT],
|
|
79808
|
+
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79809
|
+
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79810
|
+
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79811
|
+
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79812
|
+
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
78320
79813
|
[...RULE_TEXT],
|
|
78321
79814
|
[...RULE_TEXT],
|
|
78322
79815
|
[...RULE_TEXT],
|