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