@camstack/addon-provider-tuya 0.2.125 → 0.2.126
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 +1318 -129
- package/dist/addon.mjs +1318 -129
- package/package.json +1 -1
package/dist/addon.mjs
CHANGED
|
@@ -818,7 +818,7 @@ async function discoverDevices(options = {}, binder = createDgramBinder()) {
|
|
|
818
818
|
return [...byId.values()];
|
|
819
819
|
}
|
|
820
820
|
//#endregion
|
|
821
|
-
//#region ../types/dist/event-category-
|
|
821
|
+
//#region ../types/dist/event-category-BvOFi6PY.mjs
|
|
822
822
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
823
823
|
EventCategory["SystemBoot"] = "system.boot";
|
|
824
824
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -882,6 +882,24 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
882
882
|
* consumes this category and maps it to the `addon-crash-loop` kind.
|
|
883
883
|
*/
|
|
884
884
|
EventCategory["AddonRunnerFailed"] = "addon.runner-failed";
|
|
885
|
+
/**
|
|
886
|
+
* A runner whose addon refused to start with a typed reason (D877) - parked
|
|
887
|
+
* in `refused`, never counted by the crash breaker, retried on operator
|
|
888
|
+
* action. One event per refusal.
|
|
889
|
+
*/
|
|
890
|
+
EventCategory["AddonRunnerRefused"] = "addon.runner-refused";
|
|
891
|
+
/**
|
|
892
|
+
* A runner settled on a state (D877): `running` (READY), `crashed`, `failed` or
|
|
893
|
+
* `refused`. In-process telemetry for the boot check (re-evaluate while any
|
|
894
|
+
* runner is still pending) and the alert centre (close a recovered runner).
|
|
895
|
+
*/
|
|
896
|
+
EventCategory["ProcessStateChanged"] = "process.state-changed";
|
|
897
|
+
/**
|
|
898
|
+
* The node's one-shot runner boot check (D877): planned runners against the
|
|
899
|
+
* process service, `degraded` when any is failed, refused or missing. The
|
|
900
|
+
* alert centre turns it into one alert and a direct critical push.
|
|
901
|
+
*/
|
|
902
|
+
EventCategory["SystemRunnerCheck"] = "system.runner-check";
|
|
885
903
|
EventCategory["AddonError"] = "addon.error";
|
|
886
904
|
EventCategory["AddonPageReady"] = "addon.page-ready";
|
|
887
905
|
EventCategory["AddonWidgetReady"] = "addon.widget-ready";
|
|
@@ -6206,7 +6224,7 @@ var ZodIssueCode = {
|
|
|
6206
6224
|
var ZodFirstPartyTypeKind;
|
|
6207
6225
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6208
6226
|
//#endregion
|
|
6209
|
-
//#region ../types/dist/sleep-
|
|
6227
|
+
//#region ../types/dist/sleep-BOjuyoPC.mjs
|
|
6210
6228
|
/**
|
|
6211
6229
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6212
6230
|
* window to float samples (D455).
|
|
@@ -6323,7 +6341,7 @@ function isKeychainStoredField(field) {
|
|
|
6323
6341
|
var SECRET_CLEAR = { $secretClear: true };
|
|
6324
6342
|
/** The `'***'` token D634 redaction writes for non-admins. */
|
|
6325
6343
|
var LEGACY_DEVICE_REDACTION = "***";
|
|
6326
|
-
function isRecord$
|
|
6344
|
+
function isRecord$5(value) {
|
|
6327
6345
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6328
6346
|
}
|
|
6329
6347
|
function makeSecretMarker(ref) {
|
|
@@ -6334,12 +6352,12 @@ function makeSecretMarker(ref) {
|
|
|
6334
6352
|
}
|
|
6335
6353
|
/** A stored marker: an object whose `$secret` is a non-empty string. */
|
|
6336
6354
|
function isSecretMarker(value) {
|
|
6337
|
-
if (!isRecord$
|
|
6355
|
+
if (!isRecord$5(value)) return false;
|
|
6338
6356
|
const ref = value["$secret"];
|
|
6339
6357
|
return typeof ref === "string" && ref.length > 0;
|
|
6340
6358
|
}
|
|
6341
6359
|
function isSecretClear(value) {
|
|
6342
|
-
return isRecord$
|
|
6360
|
+
return isRecord$5(value) && value["$secretClear"] === true;
|
|
6343
6361
|
}
|
|
6344
6362
|
/**
|
|
6345
6363
|
* The UI view of a stored secret field value: a marker becomes "set", inline
|
|
@@ -6949,7 +6967,7 @@ var KeychainWriteRefusedError = class extends Error {
|
|
|
6949
6967
|
}
|
|
6950
6968
|
};
|
|
6951
6969
|
var KEEP = { kind: "keep" };
|
|
6952
|
-
function isRecord$
|
|
6970
|
+
function isRecord$4(value) {
|
|
6953
6971
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6954
6972
|
}
|
|
6955
6973
|
function defaultMintId() {
|
|
@@ -6962,7 +6980,7 @@ function collectSecretMarkerRefs(value, out = []) {
|
|
|
6962
6980
|
return out;
|
|
6963
6981
|
}
|
|
6964
6982
|
if (Array.isArray(value)) for (const item of value) collectSecretMarkerRefs(item, out);
|
|
6965
|
-
else if (isRecord$
|
|
6983
|
+
else if (isRecord$4(value)) for (const child of Object.values(value)) collectSecretMarkerRefs(child, out);
|
|
6966
6984
|
return out;
|
|
6967
6985
|
}
|
|
6968
6986
|
async function storedValueEquals(secrets, marker, candidate) {
|
|
@@ -7017,7 +7035,7 @@ function rowId(row, idKey) {
|
|
|
7017
7035
|
return null;
|
|
7018
7036
|
}
|
|
7019
7037
|
async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
7020
|
-
const storedRows = Array.isArray(stored) ? stored.filter(isRecord$
|
|
7038
|
+
const storedRows = Array.isArray(stored) ? stored.filter(isRecord$4) : [];
|
|
7021
7039
|
if (!Array.isArray(incoming)) {
|
|
7022
7040
|
ctx.deletes.push(...collectSecretMarkerRefs(storedRows));
|
|
7023
7041
|
return {
|
|
@@ -7033,7 +7051,7 @@ async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
|
7033
7051
|
const kept = /* @__PURE__ */ new Set();
|
|
7034
7052
|
const rows = [];
|
|
7035
7053
|
for (const row of incoming) {
|
|
7036
|
-
if (!isRecord$
|
|
7054
|
+
if (!isRecord$4(row)) {
|
|
7037
7055
|
rows.push(row);
|
|
7038
7056
|
continue;
|
|
7039
7057
|
}
|
|
@@ -7058,7 +7076,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
|
|
|
7058
7076
|
case "leaf": return writeLeaf(ctx, incoming, stored, fieldPath);
|
|
7059
7077
|
case "array": return writeArray(ctx, node, incoming, stored, fieldPath);
|
|
7060
7078
|
case "object": {
|
|
7061
|
-
if (!isRecord$
|
|
7079
|
+
if (!isRecord$4(incoming)) {
|
|
7062
7080
|
if (incoming === void 0) return KEEP;
|
|
7063
7081
|
ctx.deletes.push(...collectSecretMarkerRefs(stored));
|
|
7064
7082
|
return {
|
|
@@ -7066,7 +7084,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
|
|
|
7066
7084
|
value: incoming
|
|
7067
7085
|
};
|
|
7068
7086
|
}
|
|
7069
|
-
const storedObj = isRecord$
|
|
7087
|
+
const storedObj = isRecord$4(stored) ? stored : {};
|
|
7070
7088
|
return {
|
|
7071
7089
|
kind: "value",
|
|
7072
7090
|
value: await writeMembers(ctx, node.children, incoming, storedObj, (m) => `${fieldPath}.${m}`)
|
|
@@ -7189,7 +7207,7 @@ async function resolveSecretMarkers(value, secrets, options = {}) {
|
|
|
7189
7207
|
value: items
|
|
7190
7208
|
};
|
|
7191
7209
|
}
|
|
7192
|
-
if (isRecord$
|
|
7210
|
+
if (isRecord$4(v)) {
|
|
7193
7211
|
const out = {};
|
|
7194
7212
|
for (const [k, child] of Object.entries(v)) {
|
|
7195
7213
|
const s = substitute(child);
|
|
@@ -7221,7 +7239,7 @@ var SecretOverwriteRefusedError = class extends Error {
|
|
|
7221
7239
|
this.name = "SecretOverwriteRefusedError";
|
|
7222
7240
|
}
|
|
7223
7241
|
};
|
|
7224
|
-
function isRecord(value) {
|
|
7242
|
+
function isRecord$3(value) {
|
|
7225
7243
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7226
7244
|
}
|
|
7227
7245
|
function resolvedValue(pass, marker) {
|
|
@@ -7250,7 +7268,7 @@ function inArray(pass, incoming, stored) {
|
|
|
7250
7268
|
return incoming.map((item, index) => {
|
|
7251
7269
|
const twin = stored[index];
|
|
7252
7270
|
if (isSecretMarker(twin)) return typeof item === "string" && item === resolvedValue(pass, twin) ? twin : item;
|
|
7253
|
-
if (isRecord(item) && isRecord(twin)) return inArrayRow(pass, item, twin);
|
|
7271
|
+
if (isRecord$3(item) && isRecord$3(twin)) return inArrayRow(pass, item, twin);
|
|
7254
7272
|
if (Array.isArray(item) && Array.isArray(twin)) return inArray(pass, item, twin);
|
|
7255
7273
|
return item;
|
|
7256
7274
|
});
|
|
@@ -7261,7 +7279,7 @@ function inArrayRow(pass, incoming, stored) {
|
|
|
7261
7279
|
const twin = stored[key];
|
|
7262
7280
|
if (isSecretMarker(twin)) {
|
|
7263
7281
|
if (typeof value === "string" && value === resolvedValue(pass, twin)) out[key] = twin;
|
|
7264
|
-
} else if (isRecord(value) && isRecord(twin)) out[key] = inArrayRow(pass, value, twin);
|
|
7282
|
+
} else if (isRecord$3(value) && isRecord$3(twin)) out[key] = inArrayRow(pass, value, twin);
|
|
7265
7283
|
else if (Array.isArray(value) && Array.isArray(twin)) out[key] = inArray(pass, value, twin);
|
|
7266
7284
|
}
|
|
7267
7285
|
return out;
|
|
@@ -7269,7 +7287,7 @@ function inArrayRow(pass, incoming, stored) {
|
|
|
7269
7287
|
async function walk(pass, incoming, stored) {
|
|
7270
7288
|
if (isSecretMarker(stored)) return atMarker(pass, incoming, stored);
|
|
7271
7289
|
if (Array.isArray(incoming) && Array.isArray(stored)) return inArray(pass, incoming, stored);
|
|
7272
|
-
if (!isRecord(incoming) || !isRecord(stored)) return incoming;
|
|
7290
|
+
if (!isRecord$3(incoming) || !isRecord$3(stored)) return incoming;
|
|
7273
7291
|
const out = { ...incoming };
|
|
7274
7292
|
for (const [key, value] of Object.entries(incoming)) out[key] = await walk(pass, value, stored[key]);
|
|
7275
7293
|
return out;
|
|
@@ -7300,7 +7318,7 @@ async function restoreUnchangedSecrets(input) {
|
|
|
7300
7318
|
function isJsonEqual(a, b) {
|
|
7301
7319
|
if (Object.is(a, b)) return true;
|
|
7302
7320
|
if (Array.isArray(a)) return Array.isArray(b) && a.length === b.length && a.every((v, i) => isJsonEqual(v, b[i]));
|
|
7303
|
-
if (isRecord(a) && isRecord(b)) {
|
|
7321
|
+
if (isRecord$3(a) && isRecord$3(b)) {
|
|
7304
7322
|
const keys = Object.keys(a);
|
|
7305
7323
|
if (keys.length !== Object.keys(b).length) return false;
|
|
7306
7324
|
return keys.every((k) => Object.prototype.hasOwnProperty.call(b, k) && isJsonEqual(a[k], b[k]));
|
|
@@ -7324,7 +7342,7 @@ function markerKeysOf(blob, owner) {
|
|
|
7324
7342
|
}
|
|
7325
7343
|
function nodeFromStored(value, owner) {
|
|
7326
7344
|
if (isSecretMarker(value)) return isSecretRefOwnedBy(value.$secret, owner) ? { kind: "leaf" } : null;
|
|
7327
|
-
if (!isRecord(value)) return null;
|
|
7345
|
+
if (!isRecord$3(value)) return null;
|
|
7328
7346
|
const children = /* @__PURE__ */ new Map();
|
|
7329
7347
|
for (const [key, child] of Object.entries(value)) {
|
|
7330
7348
|
const node = nodeFromStored(child, owner);
|
|
@@ -7457,7 +7475,6 @@ function createHandle(raw, opts) {
|
|
|
7457
7475
|
const writeAddon = (patch) => write("addon", opts.addonTree(), void 0, patch, () => readStoredAddonBlob(raw), (p) => raw.writeAddonStore(p));
|
|
7458
7476
|
const readAddonStoreResult = raw.readAddonStoreResult;
|
|
7459
7477
|
const readAddonStoreKeyResult = raw.readAddonStoreKeyResult;
|
|
7460
|
-
const readDeviceStoreBatch = raw.readDeviceStoreBatch;
|
|
7461
7478
|
const overrides = {
|
|
7462
7479
|
readAddonStore: async () => resolveRead("addon", await raw.readAddonStore()),
|
|
7463
7480
|
...readAddonStoreResult !== void 0 ? { readAddonStoreResult: async () => {
|
|
@@ -7481,12 +7498,12 @@ function createHandle(raw, opts) {
|
|
|
7481
7498
|
};
|
|
7482
7499
|
} } : {},
|
|
7483
7500
|
readDeviceStore: async (deviceId) => resolveRead(`device:${deviceId}`, await raw.readDeviceStore(deviceId)),
|
|
7484
|
-
|
|
7485
|
-
const rows = await readDeviceStoreBatch
|
|
7501
|
+
readDeviceStoreBatch: async (deviceIds) => {
|
|
7502
|
+
const rows = await raw.readDeviceStoreBatch(deviceIds);
|
|
7486
7503
|
const out = /* @__PURE__ */ new Map();
|
|
7487
7504
|
for (const [deviceId, blob] of rows) out.set(deviceId, await resolveRead(`device:${deviceId}`, blob));
|
|
7488
7505
|
return out;
|
|
7489
|
-
}
|
|
7506
|
+
},
|
|
7490
7507
|
writeAddonStore: async (patch) => {
|
|
7491
7508
|
await writeAddon(patch);
|
|
7492
7509
|
},
|
|
@@ -8113,7 +8130,7 @@ var BaseAddon = class {
|
|
|
8113
8130
|
if (!ctx) return;
|
|
8114
8131
|
const addonId = ctx.id;
|
|
8115
8132
|
setImmediate(() => {
|
|
8116
|
-
ctx.api.addons
|
|
8133
|
+
ctx.api.addons.restartAddon.mutate({ addonId }).then(() => {
|
|
8117
8134
|
ctx.logger.info("addon auto-restart triggered by restart-required setting change", { meta: { changedFields: patchKeys.filter((k) => restartKeys.has(k)) } });
|
|
8118
8135
|
}).catch((err) => {
|
|
8119
8136
|
ctx.logger.error("addon auto-restart failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
@@ -8313,7 +8330,7 @@ var BaseAddon = class {
|
|
|
8313
8330
|
return this._addonSecretTree;
|
|
8314
8331
|
}
|
|
8315
8332
|
deviceSecretTree() {
|
|
8316
|
-
this._deviceSecretTree ??= secretTreeFromSchema(this.deviceSettingsSchema());
|
|
8333
|
+
this._deviceSecretTree ??= mergeSecretStatePaths(secretTreeFromSchema(this.deviceSettingsSchema()), this.secretStatePaths);
|
|
8317
8334
|
return this._deviceSecretTree;
|
|
8318
8335
|
}
|
|
8319
8336
|
/**
|
|
@@ -8389,42 +8406,135 @@ var BaseAddon = class {
|
|
|
8389
8406
|
this[timerOf] = timer;
|
|
8390
8407
|
}
|
|
8391
8408
|
/**
|
|
8392
|
-
* Wrap `ctx.settings.readAddonStore()` with a
|
|
8393
|
-
*
|
|
8394
|
-
* swap, or any race where the SqliteSettingsBackend is between shutdown and
|
|
8395
|
-
* re-initialize) doesn't propagate up into `initialize()` and leave the
|
|
8409
|
+
* Wrap `ctx.settings.readAddonStore()` with a retry budget so a transient
|
|
8410
|
+
* settings-store outage doesn't propagate up into `initialize()` and leave the
|
|
8396
8411
|
* addon permanently broken.
|
|
8397
8412
|
*
|
|
8398
|
-
*
|
|
8399
|
-
*
|
|
8400
|
-
* `
|
|
8413
|
+
* Two kinds of outage, two budgets:
|
|
8414
|
+
* - the store's own restart fingerprints (`SqliteSettingsBackend not
|
|
8415
|
+
* initialized`, `provider not available`): a short budget, then the addon
|
|
8416
|
+
* falls back to `{}` (defaults) - its first successful patch rehydrates;
|
|
8417
|
+
* - a TRANSPORT failure (the hub is restarting while this runner boots:
|
|
8418
|
+
* `discovery deadline exceeded`, `parent could not route`, a refused or
|
|
8419
|
+
* timed-out connection). Since D870 a runner's settings read THROWS instead
|
|
8420
|
+
* of answering `{}`, so without a budget a hub restart ends in a respawn
|
|
8421
|
+
* loop. A long, bounded budget; only after it the error propagates - the
|
|
8422
|
+
* addon never runs on defaults for a store it could not ask.
|
|
8423
|
+
* Anything else propagates immediately so real bugs surface.
|
|
8401
8424
|
*/
|
|
8402
8425
|
async readAddonStoreWithRetry() {
|
|
8403
8426
|
const settings = this.rawSettings();
|
|
8404
8427
|
if (!settings) return {};
|
|
8405
|
-
const delaysMs = [
|
|
8406
|
-
150,
|
|
8407
|
-
350,
|
|
8408
|
-
600,
|
|
8409
|
-
900
|
|
8410
|
-
];
|
|
8411
8428
|
let lastErr;
|
|
8412
|
-
for (let attempt = 0
|
|
8429
|
+
for (let attempt = 0;; attempt++) try {
|
|
8413
8430
|
const stored = await settings.readAddonStore() ?? {};
|
|
8414
8431
|
this.settingsStoreReady = true;
|
|
8415
8432
|
return stored;
|
|
8416
8433
|
} catch (err) {
|
|
8417
8434
|
lastErr = err;
|
|
8418
|
-
const
|
|
8419
|
-
if (
|
|
8420
|
-
|
|
8421
|
-
|
|
8435
|
+
const kind = classifyStoreError(err);
|
|
8436
|
+
if (kind === "permanent") throw err;
|
|
8437
|
+
const delay = (kind === "transport" ? TRANSPORT_RETRY_DELAYS_MS : RESTART_RETRY_DELAYS_MS)[attempt];
|
|
8438
|
+
if (delay === void 0) {
|
|
8439
|
+
if (kind === "transport") throw err;
|
|
8440
|
+
break;
|
|
8441
|
+
}
|
|
8442
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
8422
8443
|
}
|
|
8423
8444
|
this.settingsStoreReady = false;
|
|
8424
8445
|
this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
|
|
8425
8446
|
return {};
|
|
8426
8447
|
}
|
|
8427
8448
|
};
|
|
8449
|
+
/** The settings store's own restart fingerprints. */
|
|
8450
|
+
var RESTART_RETRY_DELAYS_MS = [
|
|
8451
|
+
150,
|
|
8452
|
+
350,
|
|
8453
|
+
600,
|
|
8454
|
+
900
|
|
8455
|
+
];
|
|
8456
|
+
/** A hub restarting under a booting runner: ~100 s in total. */
|
|
8457
|
+
var TRANSPORT_RETRY_DELAYS_MS = [
|
|
8458
|
+
150,
|
|
8459
|
+
350,
|
|
8460
|
+
600,
|
|
8461
|
+
900,
|
|
8462
|
+
2e3,
|
|
8463
|
+
5e3,
|
|
8464
|
+
1e4,
|
|
8465
|
+
2e4,
|
|
8466
|
+
3e4,
|
|
8467
|
+
3e4
|
|
8468
|
+
];
|
|
8469
|
+
var RESTART_FINGERPRINTS = ["SqliteSettingsBackend not initialized", "provider not available"];
|
|
8470
|
+
/** Node / socket error codes of a connection that did not happen or broke. */
|
|
8471
|
+
var TRANSPORT_CODES = new Set([
|
|
8472
|
+
"ECONNREFUSED",
|
|
8473
|
+
"ECONNRESET",
|
|
8474
|
+
"ETIMEDOUT",
|
|
8475
|
+
"EPIPE",
|
|
8476
|
+
"EHOSTUNREACH",
|
|
8477
|
+
"ENETUNREACH"
|
|
8478
|
+
]);
|
|
8479
|
+
/** tRPC error codes that mean "the other side is not answering now", not "your call is wrong". */
|
|
8480
|
+
var UNAVAILABLE_TRPC_CODES = new Set([
|
|
8481
|
+
"TIMEOUT",
|
|
8482
|
+
"SERVICE_UNAVAILABLE",
|
|
8483
|
+
"BAD_GATEWAY",
|
|
8484
|
+
"GATEWAY_TIMEOUT"
|
|
8485
|
+
]);
|
|
8486
|
+
/** The exact phrases OUR transport raises when it cannot reach the hub. */
|
|
8487
|
+
var TRANSPORT_PHRASES = [
|
|
8488
|
+
"discovery deadline exceeded",
|
|
8489
|
+
"parent could not route child unowned cap call",
|
|
8490
|
+
"UDS request timed out after",
|
|
8491
|
+
"channel closed"
|
|
8492
|
+
];
|
|
8493
|
+
/** Moleculer error `type`s of a call that could not be served right now. */
|
|
8494
|
+
var MOLECULER_TRANSIENT_TYPES = new Set([
|
|
8495
|
+
"REQUEST_TIMEOUT",
|
|
8496
|
+
"SERVICE_NOT_FOUND",
|
|
8497
|
+
"SERVICE_NOT_AVAILABLE",
|
|
8498
|
+
"REQUEST_REJECTED",
|
|
8499
|
+
"BROKER_DISCONNECTED"
|
|
8500
|
+
]);
|
|
8501
|
+
function stringProp(value, key) {
|
|
8502
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
8503
|
+
const found = Reflect.get(value, key);
|
|
8504
|
+
return typeof found === "string" ? found : void 0;
|
|
8505
|
+
}
|
|
8506
|
+
/** The code an error carries: its own, its cause's, or a tRPC `data.code`. */
|
|
8507
|
+
function errorCode(err) {
|
|
8508
|
+
const out = {};
|
|
8509
|
+
const cause = typeof err === "object" && err !== null ? Reflect.get(err, "cause") : void 0;
|
|
8510
|
+
const data = typeof err === "object" && err !== null ? Reflect.get(err, "data") : void 0;
|
|
8511
|
+
const node = stringProp(err, "code") ?? stringProp(cause, "code");
|
|
8512
|
+
if (node !== void 0) out.node = node;
|
|
8513
|
+
const trpc = stringProp(data, "code");
|
|
8514
|
+
if (trpc !== void 0) out.trpc = trpc;
|
|
8515
|
+
return out;
|
|
8516
|
+
}
|
|
8517
|
+
/**
|
|
8518
|
+
* Is a settings read failure worth retrying, and with which budget? Only
|
|
8519
|
+
* EXPLICIT signals count: a socket error code, a tRPC "unavailable" code, or
|
|
8520
|
+
* one of the exact phrases our own transport raises. A message that merely
|
|
8521
|
+
* contains "timed out" or "unreachable" is not evidence of anything, and
|
|
8522
|
+
* `settings store not wired` is a wiring bug that retrying cannot fix.
|
|
8523
|
+
*/
|
|
8524
|
+
function classifyStoreError(err) {
|
|
8525
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8526
|
+
if (RESTART_FINGERPRINTS.some((f) => message.includes(f))) return "restart";
|
|
8527
|
+
const code = errorCode(err);
|
|
8528
|
+
if (code.node !== void 0 && TRANSPORT_CODES.has(code.node)) return "transport";
|
|
8529
|
+
if (code.trpc !== void 0 && UNAVAILABLE_TRPC_CODES.has(code.trpc)) return "transport";
|
|
8530
|
+
if (typeof err === "object" && err !== null) {
|
|
8531
|
+
if (Reflect.get(err, "retryable") === true) return "transport";
|
|
8532
|
+
const type = stringProp(err, "type");
|
|
8533
|
+
if (type !== void 0 && MOLECULER_TRANSIENT_TYPES.has(type)) return "transport";
|
|
8534
|
+
}
|
|
8535
|
+
if (TRANSPORT_PHRASES.some((f) => message.includes(f))) return "transport";
|
|
8536
|
+
return "permanent";
|
|
8537
|
+
}
|
|
8428
8538
|
/**
|
|
8429
8539
|
* Collect the keys of every field marked `perNode: true`, recursing into
|
|
8430
8540
|
* layout containers (`group` fields and `sub-tabs` tabs) the same way
|
|
@@ -8514,6 +8624,156 @@ var PeerBytesTicketSchema = object({
|
|
|
8514
8624
|
*/
|
|
8515
8625
|
declaredBytes: number().int().nonnegative().nullable()
|
|
8516
8626
|
});
|
|
8627
|
+
/** Limits and names of `ctx.records` (D881). One authority; the engine and the facade read it. */
|
|
8628
|
+
/** The files a kind may live in. `history` is device-history's (D850), never records. */
|
|
8629
|
+
var RECORD_DATABASES = ["settings", "events"];
|
|
8630
|
+
/** The classes of a kind: the `@durable` vocabulary, one authority (replaces the annotation). */
|
|
8631
|
+
var RECORD_CLASSES = [
|
|
8632
|
+
"config",
|
|
8633
|
+
"ledger",
|
|
8634
|
+
"audit",
|
|
8635
|
+
"mirror",
|
|
8636
|
+
"ephemeral"
|
|
8637
|
+
];
|
|
8638
|
+
var RECORD_DEFAULT_MAX_DATA_BYTES = 64 * 1024;
|
|
8639
|
+
var RECORD_MAX_DATA_BYTES = 1024 * 1024;
|
|
8640
|
+
var RECORD_BATCH_MAX = 1e3;
|
|
8641
|
+
var RECORD_QUERY_MAX = 1e3;
|
|
8642
|
+
function defOf(schema) {
|
|
8643
|
+
const zodBag = Reflect.get(schema, "_zod");
|
|
8644
|
+
if (typeof zodBag !== "object" || zodBag === null) return {};
|
|
8645
|
+
const def = Reflect.get(zodBag, "def");
|
|
8646
|
+
if (typeof def !== "object" || def === null) return {};
|
|
8647
|
+
return def;
|
|
8648
|
+
}
|
|
8649
|
+
function declaredHere(schema) {
|
|
8650
|
+
return globalRegistry.get(schema)?.secret === true;
|
|
8651
|
+
}
|
|
8652
|
+
/** Wrapper kinds whose `innerType` is the field itself. */
|
|
8653
|
+
var WRAPPERS = new Set([
|
|
8654
|
+
"optional",
|
|
8655
|
+
"nullable",
|
|
8656
|
+
"default",
|
|
8657
|
+
"prefault",
|
|
8658
|
+
"catch",
|
|
8659
|
+
"readonly",
|
|
8660
|
+
"nonoptional"
|
|
8661
|
+
]);
|
|
8662
|
+
/**
|
|
8663
|
+
* The schema layers that make up ONE field: the schema itself and every
|
|
8664
|
+
* wrapper below it (optional / default / nullable / readonly / catch), plus
|
|
8665
|
+
* both sides of a pipe (`z.preprocess` puts the real schema on `out`,
|
|
8666
|
+
* `.transform` on `in`).
|
|
8667
|
+
*/
|
|
8668
|
+
function layersOf(schema) {
|
|
8669
|
+
const out = [];
|
|
8670
|
+
const queue = [schema];
|
|
8671
|
+
while (queue.length > 0) {
|
|
8672
|
+
const s = queue.shift();
|
|
8673
|
+
if (!s || out.includes(s)) continue;
|
|
8674
|
+
out.push(s);
|
|
8675
|
+
const def = defOf(s);
|
|
8676
|
+
if (def.type !== void 0 && WRAPPERS.has(def.type) && def.innerType) queue.push(def.innerType);
|
|
8677
|
+
if (def.type === "pipe") {
|
|
8678
|
+
if (def.in) queue.push(def.in);
|
|
8679
|
+
if (def.out) queue.push(def.out);
|
|
8680
|
+
}
|
|
8681
|
+
}
|
|
8682
|
+
return out;
|
|
8683
|
+
}
|
|
8684
|
+
/** True when any layer of this field declares `.meta({ secret: true })`. */
|
|
8685
|
+
function isZodSecret(schema) {
|
|
8686
|
+
return layersOf(schema).some(declaredHere);
|
|
8687
|
+
}
|
|
8688
|
+
/**
|
|
8689
|
+
* Every declared secret path in a config schema: dotted keys, `[]` for "each
|
|
8690
|
+
* element of this array" (`connection.password`, `rows[].token`). A declared
|
|
8691
|
+
* object or array is reported as one path and not descended into — everything
|
|
8692
|
+
* under it is secret.
|
|
8693
|
+
*/
|
|
8694
|
+
function collectZodSecretPaths(schema, prefix = "") {
|
|
8695
|
+
if (isZodSecret(schema)) return prefix.length > 0 ? [prefix] : [];
|
|
8696
|
+
const paths = [];
|
|
8697
|
+
for (const layer of layersOf(schema)) {
|
|
8698
|
+
const def = defOf(layer);
|
|
8699
|
+
if (def.type === "object" && def.shape) for (const [key, child] of Object.entries(def.shape)) paths.push(...collectZodSecretPaths(child, prefix ? `${prefix}.${key}` : key));
|
|
8700
|
+
else if (def.type === "array" && def.element) paths.push(...collectZodSecretPaths(def.element, `${prefix}[]`));
|
|
8701
|
+
else if (def.type === "union" && def.options) for (const option of def.options) paths.push(...collectZodSecretPaths(option, prefix));
|
|
8702
|
+
else if (def.type === "intersection") {
|
|
8703
|
+
if (def.left) paths.push(...collectZodSecretPaths(def.left, prefix));
|
|
8704
|
+
if (def.right) paths.push(...collectZodSecretPaths(def.right, prefix));
|
|
8705
|
+
}
|
|
8706
|
+
}
|
|
8707
|
+
return [...new Set(paths)];
|
|
8708
|
+
}
|
|
8709
|
+
/**
|
|
8710
|
+
* Record kinds (D881): the declaration an addon makes of one kind of fact, the
|
|
8711
|
+
* Zod row schema that describes it, and the helper that turns the two into the
|
|
8712
|
+
* JSON the engine stores.
|
|
8713
|
+
*
|
|
8714
|
+
* A kind is declared ONCE, next to the code that owns it, and the engine's
|
|
8715
|
+
* reconciler creates its indexes - nothing creates DDL at runtime from a write.
|
|
8716
|
+
* Everything the generic machinery needs (secret fields, the entry descriptor)
|
|
8717
|
+
* is DERIVED from the Zod schema: `.meta({ secret: true })` marks a credential,
|
|
8718
|
+
* never a field name (D879).
|
|
8719
|
+
*/
|
|
8720
|
+
/** A JSON field path: `trackId`, `auth.accessToken`. Charset-restricted: it is rendered into DDL. */
|
|
8721
|
+
var RecordFieldPathSchema = string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,63}(\.[A-Za-z_][A-Za-z0-9_]{0,63}){0,3}$/);
|
|
8722
|
+
var RecordIndexSchema = object({
|
|
8723
|
+
name: string().regex(/^[a-z][a-z0-9_]{0,31}$/),
|
|
8724
|
+
fields: array(RecordFieldPathSchema).min(1).max(4),
|
|
8725
|
+
unique: boolean().optional()
|
|
8726
|
+
}).strict();
|
|
8727
|
+
var RecordRetentionSchema = union([
|
|
8728
|
+
object({
|
|
8729
|
+
ttlMs: number().int().positive(),
|
|
8730
|
+
from: _enum(["at", "write"])
|
|
8731
|
+
}).strict(),
|
|
8732
|
+
object({
|
|
8733
|
+
maxRows: number().int().positive().optional(),
|
|
8734
|
+
maxRowsPerDevice: number().int().positive().optional()
|
|
8735
|
+
}).strict().refine((r) => r.maxRows !== void 0 || r.maxRowsPerDevice !== void 0, { message: "name maxRows, maxRowsPerDevice or both" }),
|
|
8736
|
+
object({
|
|
8737
|
+
owner: string().min(1),
|
|
8738
|
+
reason: string().min(1)
|
|
8739
|
+
}).strict(),
|
|
8740
|
+
object({ none: string().min(1) }).strict()
|
|
8741
|
+
]);
|
|
8742
|
+
/** The descriptor a generic entries UI reads (D881 "generic entries"). */
|
|
8743
|
+
var EntryDescriptorSchema = object({
|
|
8744
|
+
title: string().min(1),
|
|
8745
|
+
/** The record body field shown as the entry's name. */
|
|
8746
|
+
nameField: string().min(1),
|
|
8747
|
+
/** JSON Schema of the entry body; `secret: true` marks a password field. */
|
|
8748
|
+
fields: record(string(), unknown())
|
|
8749
|
+
}).strict();
|
|
8750
|
+
/** What crosses the wire and sits in the engine's catalog: JSON only, no Zod. */
|
|
8751
|
+
var RecordKindDeclarationSchema = object({
|
|
8752
|
+
database: _enum(RECORD_DATABASES).default("settings"),
|
|
8753
|
+
class: _enum(RECORD_CLASSES),
|
|
8754
|
+
writeTrigger: string().min(1),
|
|
8755
|
+
device: _enum([
|
|
8756
|
+
"required",
|
|
8757
|
+
"optional",
|
|
8758
|
+
"none"
|
|
8759
|
+
]).default("none"),
|
|
8760
|
+
at: _enum(["required", "none"]).default("none"),
|
|
8761
|
+
indexes: array(RecordIndexSchema).max(8).default([]),
|
|
8762
|
+
retention: RecordRetentionSchema,
|
|
8763
|
+
deviceRemoval: _enum(["delete", "none"]).default("none"),
|
|
8764
|
+
maxDataBytes: number().int().positive().max(RECORD_MAX_DATA_BYTES).default(RECORD_DEFAULT_MAX_DATA_BYTES),
|
|
8765
|
+
/** Derived from the Zod schema; never written by hand. */
|
|
8766
|
+
secretPaths: array(string().min(1)).default([]),
|
|
8767
|
+
/** The id key of each array that carries a secret (`{ headers: 'name' }`). */
|
|
8768
|
+
secretArrayKeys: record(string(), string()).default({}),
|
|
8769
|
+
/** The legacy table this kind adopts from; the boot guard reads it (D853: no migration code). */
|
|
8770
|
+
adoptsFrom: string().min(1).optional(),
|
|
8771
|
+
/** Kinds that must agree through `transact` sit in one file under one family name. */
|
|
8772
|
+
transactFamily: string().min(1).optional(),
|
|
8773
|
+
entry: EntryDescriptorSchema.optional()
|
|
8774
|
+
}).strict();
|
|
8775
|
+
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
8776
|
+
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
8517
8777
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8518
8778
|
var CamProfileSchema = _enum([
|
|
8519
8779
|
"high",
|
|
@@ -8978,75 +9238,12 @@ method(object({ deviceId: number() }), array(StreamSourceEntrySchema)), method(o
|
|
|
8978
9238
|
kind: "mutation",
|
|
8979
9239
|
auth: "admin"
|
|
8980
9240
|
}), method(object({ deviceId: number() }), unknown().nullable()), method(object({ deviceId: number() }), RawStateResultSchema.nullable(), { auth: "protected" });
|
|
8981
|
-
function defOf(schema) {
|
|
8982
|
-
return schema._zod?.def ?? {};
|
|
8983
|
-
}
|
|
8984
|
-
function declaredHere(schema) {
|
|
8985
|
-
return globalRegistry.get(schema)?.secret === true;
|
|
8986
|
-
}
|
|
8987
|
-
/** Wrapper kinds whose `innerType` is the field itself. */
|
|
8988
|
-
var WRAPPERS = new Set([
|
|
8989
|
-
"optional",
|
|
8990
|
-
"nullable",
|
|
8991
|
-
"default",
|
|
8992
|
-
"prefault",
|
|
8993
|
-
"catch",
|
|
8994
|
-
"readonly",
|
|
8995
|
-
"nonoptional"
|
|
8996
|
-
]);
|
|
8997
|
-
/**
|
|
8998
|
-
* The schema layers that make up ONE field: the schema itself and every
|
|
8999
|
-
* wrapper below it (optional / default / nullable / readonly / catch), plus
|
|
9000
|
-
* both sides of a pipe (`z.preprocess` puts the real schema on `out`,
|
|
9001
|
-
* `.transform` on `in`).
|
|
9002
|
-
*/
|
|
9003
|
-
function layersOf(schema) {
|
|
9004
|
-
const out = [];
|
|
9005
|
-
const queue = [schema];
|
|
9006
|
-
while (queue.length > 0) {
|
|
9007
|
-
const s = queue.shift();
|
|
9008
|
-
if (!s || out.includes(s)) continue;
|
|
9009
|
-
out.push(s);
|
|
9010
|
-
const def = defOf(s);
|
|
9011
|
-
if (def.type !== void 0 && WRAPPERS.has(def.type) && def.innerType) queue.push(def.innerType);
|
|
9012
|
-
if (def.type === "pipe") {
|
|
9013
|
-
if (def.in) queue.push(def.in);
|
|
9014
|
-
if (def.out) queue.push(def.out);
|
|
9015
|
-
}
|
|
9016
|
-
}
|
|
9017
|
-
return out;
|
|
9018
|
-
}
|
|
9019
|
-
/** True when any layer of this field declares `.meta({ secret: true })`. */
|
|
9020
|
-
function isZodSecret(schema) {
|
|
9021
|
-
return layersOf(schema).some(declaredHere);
|
|
9022
|
-
}
|
|
9023
|
-
/**
|
|
9024
|
-
* Every declared secret path in a config schema: dotted keys, `[]` for "each
|
|
9025
|
-
* element of this array" (`connection.password`, `rows[].token`). A declared
|
|
9026
|
-
* object or array is reported as one path and not descended into — everything
|
|
9027
|
-
* under it is secret.
|
|
9028
|
-
*/
|
|
9029
|
-
function collectZodSecretPaths(schema, prefix = "") {
|
|
9030
|
-
if (isZodSecret(schema)) return prefix.length > 0 ? [prefix] : [];
|
|
9031
|
-
const paths = [];
|
|
9032
|
-
for (const layer of layersOf(schema)) {
|
|
9033
|
-
const def = defOf(layer);
|
|
9034
|
-
if (def.type === "object" && def.shape) for (const [key, child] of Object.entries(def.shape)) paths.push(...collectZodSecretPaths(child, prefix ? `${prefix}.${key}` : key));
|
|
9035
|
-
else if (def.type === "array" && def.element) paths.push(...collectZodSecretPaths(def.element, `${prefix}[]`));
|
|
9036
|
-
else if (def.type === "union" && def.options) for (const option of def.options) paths.push(...collectZodSecretPaths(option, prefix));
|
|
9037
|
-
else if (def.type === "intersection") {
|
|
9038
|
-
if (def.left) paths.push(...collectZodSecretPaths(def.left, prefix));
|
|
9039
|
-
if (def.right) paths.push(...collectZodSecretPaths(def.right, prefix));
|
|
9040
|
-
}
|
|
9041
|
-
}
|
|
9042
|
-
return [...new Set(paths)];
|
|
9043
|
-
}
|
|
9044
9241
|
object({
|
|
9045
9242
|
code: string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/),
|
|
9046
9243
|
params: record(string(), union([string(), number()])).optional()
|
|
9047
9244
|
});
|
|
9048
9245
|
//#endregion
|
|
9049
|
-
//#region ../types/dist/err-msg-
|
|
9246
|
+
//#region ../types/dist/err-msg-BXKzRBwg.mjs
|
|
9050
9247
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
9051
9248
|
DeviceType["Camera"] = "camera";
|
|
9052
9249
|
DeviceType["Hub"] = "hub";
|
|
@@ -9138,6 +9335,10 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
9138
9335
|
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
9139
9336
|
* integrations sharing the same food/desiccant/hopper surface. */
|
|
9140
9337
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
9338
|
+
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
9339
|
+
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
9340
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations. */
|
|
9341
|
+
DeviceType["Dishwasher"] = "dishwasher";
|
|
9141
9342
|
return DeviceType;
|
|
9142
9343
|
}({});
|
|
9143
9344
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -9315,6 +9516,9 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
9315
9516
|
/** Virtual HA toggle (input_boolean.*) — distinguishable from a
|
|
9316
9517
|
* real Switch device for UI rendering / export adapters. */
|
|
9317
9518
|
DeviceRole["BinaryHelper"] = "binary-helper";
|
|
9519
|
+
/** A smart plug: a `switch` whose source says it is an outlet (HA
|
|
9520
|
+
* `device_class: outlet`). The Alexa export shows it as a SMARTPLUG. */
|
|
9521
|
+
DeviceRole["Outlet"] = "outlet";
|
|
9318
9522
|
/** Generic motion / occupancy / moving event source. Distinct from
|
|
9319
9523
|
* the camera accessory PirSensor role: that one is a camera child;
|
|
9320
9524
|
* this is a standalone HA / 3rd-party motion sensor. */
|
|
@@ -9392,7 +9596,7 @@ function errMsg(err) {
|
|
|
9392
9596
|
return String(err);
|
|
9393
9597
|
}
|
|
9394
9598
|
//#endregion
|
|
9395
|
-
//#region ../types/dist/composition-
|
|
9599
|
+
//#region ../types/dist/composition-CB6PMT9p.mjs
|
|
9396
9600
|
/**
|
|
9397
9601
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
9398
9602
|
*
|
|
@@ -12596,11 +12800,10 @@ var ClipModelMetaSchema = object({
|
|
|
12596
12800
|
/**
|
|
12597
12801
|
* The `vector-store` index this model's vectors live in. ONE feature space
|
|
12598
12802
|
* per index: two models share an index only when their vectors are ranked
|
|
12599
|
-
* against each other, which for CLIP means never across families.
|
|
12600
|
-
*
|
|
12601
|
-
* `modelId`); any other model gets its own.
|
|
12803
|
+
* against each other, which for CLIP means never across families. Every
|
|
12804
|
+
* model gets its own.
|
|
12602
12805
|
*/
|
|
12603
|
-
vectorIndex: string().regex(/^object-clip
|
|
12806
|
+
vectorIndex: string().regex(/^object-clip-[a-z0-9][a-z0-9-]*$/),
|
|
12604
12807
|
/**
|
|
12605
12808
|
* The text encoder's tokenizer, a declared SIBLING file of its onnx. The name
|
|
12606
12809
|
* must be unique per tokenizer: every model's siblings land in ONE flat
|
|
@@ -13779,8 +13982,13 @@ var AlertSeveritySchema = _enum([
|
|
|
13779
13982
|
"info",
|
|
13780
13983
|
"success",
|
|
13781
13984
|
"warning",
|
|
13782
|
-
"error"
|
|
13985
|
+
"error",
|
|
13986
|
+
"critical"
|
|
13783
13987
|
]);
|
|
13988
|
+
var AlertActionSchema = object({
|
|
13989
|
+
label: string(),
|
|
13990
|
+
href: string().optional()
|
|
13991
|
+
});
|
|
13784
13992
|
var AlertStatusSchema = _enum([
|
|
13785
13993
|
"active",
|
|
13786
13994
|
"in-progress",
|
|
@@ -13798,6 +14006,7 @@ var AlertSchema = object({
|
|
|
13798
14006
|
severity: AlertSeveritySchema,
|
|
13799
14007
|
title: string(),
|
|
13800
14008
|
message: string(),
|
|
14009
|
+
action: AlertActionSchema.optional(),
|
|
13801
14010
|
status: AlertStatusSchema,
|
|
13802
14011
|
progress: number().optional(),
|
|
13803
14012
|
read: boolean(),
|
|
@@ -16333,6 +16542,41 @@ var ComposableCapabilitiesSchema = object({ caps: array(object({
|
|
|
16333
16542
|
keyField: string()
|
|
16334
16543
|
}).optional()
|
|
16335
16544
|
})) });
|
|
16545
|
+
/**
|
|
16546
|
+
* The report of a one-shot "move this owner's plaintext secrets into the
|
|
16547
|
+
* keychain" run (D878). COUNTS only - never a value, never a ref.
|
|
16548
|
+
*
|
|
16549
|
+
* The owner runs it on its own rows, through its own write path; an operator
|
|
16550
|
+
* script (`scripts/hub/migrate-raw-secrets.ts`) calls the owner's cap method.
|
|
16551
|
+
* Dry run (`apply: false`) reports what WOULD move and changes nothing.
|
|
16552
|
+
*/
|
|
16553
|
+
var RawSecretMigrationInputSchema = object({
|
|
16554
|
+
/** `false` (the default of the script) = report only. */
|
|
16555
|
+
apply: boolean() });
|
|
16556
|
+
var RawSecretMigrationReportSchema = object({
|
|
16557
|
+
apply: boolean(),
|
|
16558
|
+
/** Rows that can carry a secret (a profile, an enrolment). */
|
|
16559
|
+
rows: number().int(),
|
|
16560
|
+
/** Rows whose secret was plaintext when the run started. */
|
|
16561
|
+
raw: number().int(),
|
|
16562
|
+
/** Rows that already held a keychain marker when the run started. */
|
|
16563
|
+
markers: number().int(),
|
|
16564
|
+
/** Plaintext rows moved by THIS run (always 0 on a dry run). */
|
|
16565
|
+
migrated: number().int(),
|
|
16566
|
+
/** Plaintext rows left in place because the move or its read-back failed. */
|
|
16567
|
+
failed: number().int(),
|
|
16568
|
+
/** After the run: rows still holding plaintext. */
|
|
16569
|
+
remainingRaw: number().int(),
|
|
16570
|
+
/** After the run: markers the keychain could not resolve right now. */
|
|
16571
|
+
unresolvedMarkers: number().int(),
|
|
16572
|
+
/**
|
|
16573
|
+
* A second, redundant copy of the secrets' rows that the run found (and, on
|
|
16574
|
+
* `apply`, deleted after verifying the first). Owners with a single copy omit it.
|
|
16575
|
+
*/
|
|
16576
|
+
redundantCopies: number().int().optional(),
|
|
16577
|
+
/** True when nothing is raw and every marker resolves. */
|
|
16578
|
+
verified: boolean()
|
|
16579
|
+
});
|
|
16336
16580
|
/** Where a block runs. The operator chooses — a block driving a device on an
|
|
16337
16581
|
* agent is the reason placement is not fixed to the hub. */
|
|
16338
16582
|
var CoreBlockPlacementSchema = union([literal("hub"), string().min(1)]);
|
|
@@ -16559,6 +16803,9 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
|
|
|
16559
16803
|
}), SettingsUpdateResultSchema, {
|
|
16560
16804
|
kind: "mutation",
|
|
16561
16805
|
auth: "admin"
|
|
16806
|
+
}), method(RawSecretMigrationInputSchema, RawSecretMigrationReportSchema, {
|
|
16807
|
+
kind: "mutation",
|
|
16808
|
+
auth: "admin"
|
|
16562
16809
|
}), method(object({}), object({ libs: array(object({
|
|
16563
16810
|
filePath: string(),
|
|
16564
16811
|
content: string()
|
|
@@ -16822,6 +17069,347 @@ id: union([string(), number()]) }), {
|
|
|
16822
17069
|
auth: "admin"
|
|
16823
17070
|
});
|
|
16824
17071
|
/**
|
|
17072
|
+
* records - an addon's own facts and documents (D881): ledgers, audit rows,
|
|
17073
|
+
* config documents, mirrors. The third storage API next to `ctx.settings`
|
|
17074
|
+
* (operator intent, D870) and device-history (numbers over time, D850).
|
|
17075
|
+
*
|
|
17076
|
+
* Who the OWNER is: `callerAddonId`, stamped by the transport on a call that
|
|
17077
|
+
* crossed a process and stated by a hub in-process caller (`ctx.records` does
|
|
17078
|
+
* that with the addon id closed over). It is deliberately NOT in any input
|
|
17079
|
+
* schema, so a session can never supply it, and a call with no stamp is refused
|
|
17080
|
+
* `records/no-caller`. A kind is readable and writable only by its owner; other
|
|
17081
|
+
* addons go through the owner's capability.
|
|
17082
|
+
*
|
|
17083
|
+
* Every read is three-way: a row, `null`, or the call THROWS. A failed read is
|
|
17084
|
+
* never `[]`. Secret fields are never on the wire: a read shows the
|
|
17085
|
+
* redaction token, `secretRefs` hands the owner's `ctx.secrets` the refs it
|
|
17086
|
+
* resolves itself, and a write may carry only a keychain marker bound to the
|
|
17087
|
+
* row's own ref.
|
|
17088
|
+
*
|
|
17089
|
+
* Internal: addons reach it through `ctx.records`, never directly.
|
|
17090
|
+
*/
|
|
17091
|
+
var RecordIdSchema = string().min(1).max(256);
|
|
17092
|
+
/** A JSON object body. Size is the engine's check (`maxDataBytes`), not a schema's. */
|
|
17093
|
+
var RecordBodySchema = record(string(), unknown());
|
|
17094
|
+
var RecordInputSchema = object({
|
|
17095
|
+
id: RecordIdSchema,
|
|
17096
|
+
/** The device this row belongs to (D865 removal, per-device reads). */
|
|
17097
|
+
deviceId: number().int().optional(),
|
|
17098
|
+
/** The domain clock, ms: observed / created / opened. */
|
|
17099
|
+
at: number().int().optional(),
|
|
17100
|
+
/** Producer-set expiry, ms. Refused on a kind whose retention is an engine TTL. */
|
|
17101
|
+
expiresAt: number().int().optional(),
|
|
17102
|
+
data: RecordBodySchema
|
|
17103
|
+
});
|
|
17104
|
+
var RecordViewSchema = object({
|
|
17105
|
+
id: string(),
|
|
17106
|
+
deviceId: number().int().nullable(),
|
|
17107
|
+
at: number().nullable(),
|
|
17108
|
+
expiresAt: number().nullable(),
|
|
17109
|
+
rev: number().int(),
|
|
17110
|
+
updatedAt: number(),
|
|
17111
|
+
data: RecordBodySchema
|
|
17112
|
+
});
|
|
17113
|
+
/** Declared index fields only. Anything else does not compile, by design. */
|
|
17114
|
+
var RecordWhereSchema = record(RecordFieldPathSchema, union([
|
|
17115
|
+
string(),
|
|
17116
|
+
number(),
|
|
17117
|
+
boolean(),
|
|
17118
|
+
object({ in: array(union([
|
|
17119
|
+
string(),
|
|
17120
|
+
number(),
|
|
17121
|
+
boolean()
|
|
17122
|
+
])).min(1).max(RECORD_BATCH_MAX) }),
|
|
17123
|
+
object({
|
|
17124
|
+
gt: union([string(), number()]).optional(),
|
|
17125
|
+
gte: union([string(), number()]).optional(),
|
|
17126
|
+
lt: union([string(), number()]).optional(),
|
|
17127
|
+
lte: union([string(), number()]).optional()
|
|
17128
|
+
}).refine((r) => Object.keys(r).length > 0, { message: "name at least one bound" })
|
|
17129
|
+
]));
|
|
17130
|
+
var KindShape = { kind: RecordKindNameSchema };
|
|
17131
|
+
var TimeWindowShape = {
|
|
17132
|
+
deviceId: number().int().optional(),
|
|
17133
|
+
atFrom: number().optional(),
|
|
17134
|
+
atTo: number().optional()
|
|
17135
|
+
};
|
|
17136
|
+
var RecordQueryInputSchema = object({
|
|
17137
|
+
...KindShape,
|
|
17138
|
+
...TimeWindowShape,
|
|
17139
|
+
where: RecordWhereSchema.optional(),
|
|
17140
|
+
/** Without `where`: `at` (default for a kind with a clock) or `id`. With `where` the order is the index's. */
|
|
17141
|
+
order: _enum(["at", "id"]).optional(),
|
|
17142
|
+
desc: boolean().optional(),
|
|
17143
|
+
limit: number().int().min(1).max(RECORD_QUERY_MAX).default(100),
|
|
17144
|
+
/** Opaque keyset cursor from a previous answer. There is no offset. */
|
|
17145
|
+
cursor: string().min(1).optional()
|
|
17146
|
+
});
|
|
17147
|
+
var RecordQueryResultSchema = object({
|
|
17148
|
+
records: array(RecordViewSchema),
|
|
17149
|
+
nextCursor: string().nullable()
|
|
17150
|
+
});
|
|
17151
|
+
var RecordKindStateSchema = _enum([
|
|
17152
|
+
"created",
|
|
17153
|
+
"unchanged",
|
|
17154
|
+
"updated"
|
|
17155
|
+
]);
|
|
17156
|
+
var DeclareKindResultSchema = object({
|
|
17157
|
+
kindId: number().int(),
|
|
17158
|
+
state: RecordKindStateSchema,
|
|
17159
|
+
createdIndexes: array(string()),
|
|
17160
|
+
/** The boot guard: the kind is empty while its legacy table still holds rows. */
|
|
17161
|
+
adoptionPending: object({
|
|
17162
|
+
legacyTable: string(),
|
|
17163
|
+
legacyRows: number().int()
|
|
17164
|
+
}).nullable()
|
|
17165
|
+
});
|
|
17166
|
+
/** Keychain refs a write released (the old marker is gone from the row): the owner deletes the values. */
|
|
17167
|
+
var SecretRefsList = array(string());
|
|
17168
|
+
var RecordSecretRefsSchema = record(string(), record(string(), string()));
|
|
17169
|
+
method(object({ kinds: record(RecordKindNameSchema, RecordKindDeclarationSchema) }), object({ kinds: record(string(), DeclareKindResultSchema) }), {
|
|
17170
|
+
kind: "mutation",
|
|
17171
|
+
auth: "admin"
|
|
17172
|
+
}), method(object({
|
|
17173
|
+
...KindShape,
|
|
17174
|
+
id: RecordIdSchema
|
|
17175
|
+
}), RecordViewSchema.nullable(), { auth: "admin" }), method(object({
|
|
17176
|
+
...KindShape,
|
|
17177
|
+
ids: array(RecordIdSchema).min(1).max(RECORD_BATCH_MAX)
|
|
17178
|
+
}), array(RecordViewSchema), { auth: "admin" }), method(object({
|
|
17179
|
+
...KindShape,
|
|
17180
|
+
ids: array(RecordIdSchema).min(1).max(RECORD_BATCH_MAX)
|
|
17181
|
+
}), RecordSecretRefsSchema, { auth: "admin" }), method(object({
|
|
17182
|
+
...KindShape,
|
|
17183
|
+
record: RecordInputSchema,
|
|
17184
|
+
/** Compare-and-set. `0` means "the row must not exist". */
|
|
17185
|
+
ifRev: number().int().min(0).optional()
|
|
17186
|
+
}), object({
|
|
17187
|
+
rev: number().int(),
|
|
17188
|
+
releasedRefs: SecretRefsList
|
|
17189
|
+
}), {
|
|
17190
|
+
kind: "mutation",
|
|
17191
|
+
auth: "admin"
|
|
17192
|
+
}), method(object({
|
|
17193
|
+
...KindShape,
|
|
17194
|
+
records: array(RecordInputSchema).min(1).max(RECORD_BATCH_MAX)
|
|
17195
|
+
}), object({
|
|
17196
|
+
count: number().int(),
|
|
17197
|
+
releasedRefs: SecretRefsList
|
|
17198
|
+
}), {
|
|
17199
|
+
kind: "mutation",
|
|
17200
|
+
auth: "admin"
|
|
17201
|
+
}), method(object({
|
|
17202
|
+
...KindShape,
|
|
17203
|
+
id: RecordIdSchema,
|
|
17204
|
+
data: RecordBodySchema,
|
|
17205
|
+
at: number().int().nullable().optional(),
|
|
17206
|
+
expiresAt: number().int().nullable().optional(),
|
|
17207
|
+
ifRev: number().int().min(1).optional()
|
|
17208
|
+
}), object({
|
|
17209
|
+
rev: number().int(),
|
|
17210
|
+
releasedRefs: SecretRefsList
|
|
17211
|
+
}), {
|
|
17212
|
+
kind: "mutation",
|
|
17213
|
+
auth: "admin"
|
|
17214
|
+
}), method(object({
|
|
17215
|
+
...KindShape,
|
|
17216
|
+
id: RecordIdSchema
|
|
17217
|
+
}), object({
|
|
17218
|
+
deleted: boolean(),
|
|
17219
|
+
secretRefs: SecretRefsList
|
|
17220
|
+
}), {
|
|
17221
|
+
kind: "mutation",
|
|
17222
|
+
auth: "admin"
|
|
17223
|
+
}), method(object({
|
|
17224
|
+
...KindShape,
|
|
17225
|
+
ids: array(RecordIdSchema).min(1).max(RECORD_BATCH_MAX)
|
|
17226
|
+
}), object({
|
|
17227
|
+
deleted: number().int(),
|
|
17228
|
+
secretRefs: SecretRefsList
|
|
17229
|
+
}), {
|
|
17230
|
+
kind: "mutation",
|
|
17231
|
+
auth: "admin"
|
|
17232
|
+
}), method(RecordQueryInputSchema, RecordQueryResultSchema, { auth: "admin" }), method(object({
|
|
17233
|
+
...KindShape,
|
|
17234
|
+
...TimeWindowShape,
|
|
17235
|
+
where: RecordWhereSchema.optional()
|
|
17236
|
+
}), object({ count: number().int() }), { auth: "admin" }), method(object({
|
|
17237
|
+
...KindShape,
|
|
17238
|
+
deviceId: number().int().optional(),
|
|
17239
|
+
from: number(),
|
|
17240
|
+
to: number(),
|
|
17241
|
+
bucketMs: number().int().positive()
|
|
17242
|
+
}), object({ buckets: array(object({
|
|
17243
|
+
bucketStart: number(),
|
|
17244
|
+
count: number().int()
|
|
17245
|
+
})) }), { auth: "admin" }), method(object({
|
|
17246
|
+
...KindShape,
|
|
17247
|
+
op: _enum([
|
|
17248
|
+
"sum",
|
|
17249
|
+
"min",
|
|
17250
|
+
"max",
|
|
17251
|
+
"count"
|
|
17252
|
+
]),
|
|
17253
|
+
field: RecordFieldPathSchema.optional(),
|
|
17254
|
+
groupBy: RecordFieldPathSchema.optional(),
|
|
17255
|
+
where: RecordWhereSchema.optional()
|
|
17256
|
+
}), object({ rows: array(object({
|
|
17257
|
+
group: union([
|
|
17258
|
+
string(),
|
|
17259
|
+
number(),
|
|
17260
|
+
_null()
|
|
17261
|
+
]),
|
|
17262
|
+
value: number().nullable()
|
|
17263
|
+
})) }), { auth: "admin" }), method(object({
|
|
17264
|
+
...KindShape,
|
|
17265
|
+
deviceId: number().int().optional(),
|
|
17266
|
+
atBefore: number().optional(),
|
|
17267
|
+
where: RecordWhereSchema.optional()
|
|
17268
|
+
}), object({
|
|
17269
|
+
deleted: number().int(),
|
|
17270
|
+
secretRefs: SecretRefsList
|
|
17271
|
+
}), {
|
|
17272
|
+
kind: "mutation",
|
|
17273
|
+
auth: "admin"
|
|
17274
|
+
}), method(object({
|
|
17275
|
+
deviceId: number().int(),
|
|
17276
|
+
kinds: array(RecordKindNameSchema).optional()
|
|
17277
|
+
}), object({
|
|
17278
|
+
deleted: record(string(), number().int()),
|
|
17279
|
+
secretRefs: SecretRefsList
|
|
17280
|
+
}), {
|
|
17281
|
+
kind: "mutation",
|
|
17282
|
+
auth: "admin"
|
|
17283
|
+
}), method(object(KindShape), object({ id: number().int() }), {
|
|
17284
|
+
kind: "mutation",
|
|
17285
|
+
auth: "admin"
|
|
17286
|
+
});
|
|
17287
|
+
/** One table of the settings database. */
|
|
17288
|
+
var StorageTableSchema = object({
|
|
17289
|
+
/** The table's full name, e.g. `recorder:addon-settings` or `addon-device-settings`. */
|
|
17290
|
+
name: string(),
|
|
17291
|
+
/** The owner prefix of a scoped name (`recorder` for `recorder:addon-settings`), else null. */
|
|
17292
|
+
owner: string().nullable(),
|
|
17293
|
+
rows: number().int().nonnegative(),
|
|
17294
|
+
/** Bytes the table's pages occupy (`dbstat`); null when the engine cannot measure. */
|
|
17295
|
+
bytes: number().int().nonnegative().nullable(),
|
|
17296
|
+
/** Declared by an addon since this engine process started (a running addon claims it). */
|
|
17297
|
+
declaredThisBoot: boolean()
|
|
17298
|
+
});
|
|
17299
|
+
/** One declared record kind (D881) as System -> Data shows it. */
|
|
17300
|
+
var StorageKindSchema = object({
|
|
17301
|
+
owner: string(),
|
|
17302
|
+
kind: string(),
|
|
17303
|
+
database: _enum(["settings", "events"]),
|
|
17304
|
+
class: string(),
|
|
17305
|
+
state: _enum([
|
|
17306
|
+
"declared",
|
|
17307
|
+
"orphaned",
|
|
17308
|
+
"dropped"
|
|
17309
|
+
]),
|
|
17310
|
+
/** `null` when the caller asked for no counts (`counts: false`). */
|
|
17311
|
+
rows: number().int().nonnegative().nullable(),
|
|
17312
|
+
/** Rows x the average size of a sample; null for an empty kind. */
|
|
17313
|
+
bytesEstimate: number().int().nonnegative().nullable(),
|
|
17314
|
+
writeTrigger: string(),
|
|
17315
|
+
retention: RecordRetentionSchema,
|
|
17316
|
+
/** `true` when the kind is an entry kind (the generic entries UI lists it). */
|
|
17317
|
+
entry: boolean(),
|
|
17318
|
+
/** The whole declaration, secret paths and entry descriptor included (the entries service builds its handle from it). */
|
|
17319
|
+
declaration: RecordKindDeclarationSchema
|
|
17320
|
+
});
|
|
17321
|
+
method(object({ ownerPrefix: string().min(1).optional() }), object({ tables: array(StorageTableSchema) }), { auth: "admin" }), method(object({
|
|
17322
|
+
collection: string().min(1),
|
|
17323
|
+
expectRows: number().int().nonnegative()
|
|
17324
|
+
}), object({
|
|
17325
|
+
dropped: literal(true),
|
|
17326
|
+
rows: number().int().nonnegative()
|
|
17327
|
+
}), {
|
|
17328
|
+
kind: "mutation",
|
|
17329
|
+
auth: "admin"
|
|
17330
|
+
}), method(object({
|
|
17331
|
+
owner: string().min(1).optional(),
|
|
17332
|
+
/** `false` skips the per-kind row count (a catalog read only). Default true. */
|
|
17333
|
+
counts: boolean().optional()
|
|
17334
|
+
}), object({ kinds: array(StorageKindSchema) }), { auth: "admin" }), method(RecordQueryInputSchema.extend({
|
|
17335
|
+
owner: string().min(1),
|
|
17336
|
+
kind: RecordKindNameSchema
|
|
17337
|
+
}), RecordQueryResultSchema, { auth: "admin" }), method(object({
|
|
17338
|
+
owner: string().min(1),
|
|
17339
|
+
kind: RecordKindNameSchema,
|
|
17340
|
+
records: array(RecordInputSchema).max(RECORD_BATCH_MAX),
|
|
17341
|
+
/** The LAST batch: the copy is complete, the boot guard stops asking. */
|
|
17342
|
+
complete: boolean().optional()
|
|
17343
|
+
}).refine((input) => input.records.length > 0 || input.complete === true, { message: "records must be non-empty unless complete is true" }), object({ adopted: number().int() }), {
|
|
17344
|
+
kind: "mutation",
|
|
17345
|
+
auth: "admin"
|
|
17346
|
+
}), method(object({
|
|
17347
|
+
collection: string().min(1),
|
|
17348
|
+
cursor: string().optional(),
|
|
17349
|
+
limit: number().int().min(1).max(1e3).optional()
|
|
17350
|
+
}), object({
|
|
17351
|
+
rows: array(object({
|
|
17352
|
+
id: string(),
|
|
17353
|
+
data: record(string(), unknown())
|
|
17354
|
+
})),
|
|
17355
|
+
nextCursor: string().nullable()
|
|
17356
|
+
}), { auth: "admin" }), method(object({ collection: string().min(1) }), object({ adopted: boolean() }), { auth: "admin" });
|
|
17357
|
+
/**
|
|
17358
|
+
* record-entries - the ONE admin surface for every list of user-created entries
|
|
17359
|
+
* (D881): notification targets, brokers, LLM profiles, anything an addon
|
|
17360
|
+
* declares as an ENTRY kind (`entry: { title }` in `defineRecordKinds`).
|
|
17361
|
+
*
|
|
17362
|
+
* The UI is generic. `listEntryKinds` hands it, per kind, the JSON Schema of
|
|
17363
|
+
* the entry body with `secret: true` on every credential field, so a password
|
|
17364
|
+
* field is derived from the schema and never from a name. `putEntry` takes the
|
|
17365
|
+
* redaction token for an untouched secret (the stored value is kept), a string
|
|
17366
|
+
* for a new one, and the clear instruction to remove one. A read never carries
|
|
17367
|
+
* a secret value, and a locked keychain refuses the write with
|
|
17368
|
+
* `records/secret-unavailable` instead of storing plaintext.
|
|
17369
|
+
*
|
|
17370
|
+
* Hub-only, served in-process (it acts for each entry's owner on the keychain).
|
|
17371
|
+
*/
|
|
17372
|
+
var EntryKindInfoSchema = object({
|
|
17373
|
+
owner: string(),
|
|
17374
|
+
kind: RecordKindNameSchema,
|
|
17375
|
+
title: string(),
|
|
17376
|
+
nameField: string(),
|
|
17377
|
+
/** JSON Schema of the body; `secret: true` marks a password field. */
|
|
17378
|
+
fields: record(string(), unknown()),
|
|
17379
|
+
secretPaths: array(string()),
|
|
17380
|
+
rows: number().int().nonnegative()
|
|
17381
|
+
});
|
|
17382
|
+
var EntryViewSchema = object({
|
|
17383
|
+
id: RecordIdSchema,
|
|
17384
|
+
name: string(),
|
|
17385
|
+
rev: number().int(),
|
|
17386
|
+
updatedAt: number(),
|
|
17387
|
+
/** Secret fields hold the redaction token. */
|
|
17388
|
+
data: RecordBodySchema
|
|
17389
|
+
});
|
|
17390
|
+
var EntryAddress = {
|
|
17391
|
+
owner: string().min(1),
|
|
17392
|
+
kind: RecordKindNameSchema
|
|
17393
|
+
};
|
|
17394
|
+
method(object({}), object({ kinds: array(EntryKindInfoSchema) }), { auth: "admin" }), method(object({ ...EntryAddress }), object({ entries: array(EntryViewSchema) }), { auth: "admin" }), method(object({
|
|
17395
|
+
...EntryAddress,
|
|
17396
|
+
id: RecordIdSchema.optional(),
|
|
17397
|
+
data: RecordBodySchema,
|
|
17398
|
+
ifRev: number().int().min(1).optional()
|
|
17399
|
+
}), object({
|
|
17400
|
+
id: string(),
|
|
17401
|
+
rev: number().int()
|
|
17402
|
+
}), {
|
|
17403
|
+
kind: "mutation",
|
|
17404
|
+
auth: "admin"
|
|
17405
|
+
}), method(object({
|
|
17406
|
+
...EntryAddress,
|
|
17407
|
+
id: RecordIdSchema
|
|
17408
|
+
}), object({ deleted: boolean() }), {
|
|
17409
|
+
kind: "mutation",
|
|
17410
|
+
auth: "admin"
|
|
17411
|
+
});
|
|
17412
|
+
/**
|
|
16825
17413
|
* `keychain` — the hub's encrypted store of secret values (D787).
|
|
16826
17414
|
*
|
|
16827
17415
|
* Settings blobs never hold a secret: they hold a marker
|
|
@@ -17362,6 +17950,16 @@ method(object({}), KeychainStatusSchema, { auth: "admin" }), method(object({}),
|
|
|
17362
17950
|
kind: "mutation",
|
|
17363
17951
|
auth: "admin",
|
|
17364
17952
|
caller: "required"
|
|
17953
|
+
}), method(object({
|
|
17954
|
+
ref: string().min(1),
|
|
17955
|
+
value: string().min(1)
|
|
17956
|
+
}), object({
|
|
17957
|
+
ref: string(),
|
|
17958
|
+
version: number().int()
|
|
17959
|
+
}), {
|
|
17960
|
+
kind: "mutation",
|
|
17961
|
+
auth: "admin",
|
|
17962
|
+
caller: "required"
|
|
17365
17963
|
}), method(object({ refs: array(string().min(1)).max(1e3) }), object({
|
|
17366
17964
|
deleted: array(string()).readonly(),
|
|
17367
17965
|
kept: array(object({
|
|
@@ -40040,6 +40638,9 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, {
|
|
|
40040
40638
|
}), _void(), { kind: "mutation" }), method(object({}), array(LlmProfileKindDescriptorSchema)), method(object({}), array(LlmProfileSchema)), method(object({ profile: LlmProfileSchema }), LlmProfileSchema, {
|
|
40041
40639
|
kind: "mutation",
|
|
40042
40640
|
auth: "admin"
|
|
40641
|
+
}), method(RawSecretMigrationInputSchema, RawSecretMigrationReportSchema, {
|
|
40642
|
+
kind: "mutation",
|
|
40643
|
+
auth: "admin"
|
|
40043
40644
|
}), method(ProfileRefInputSchema, _void(), {
|
|
40044
40645
|
kind: "mutation",
|
|
40045
40646
|
auth: "admin"
|
|
@@ -50549,6 +51150,41 @@ var ServerRollbackInfoSchema = object({
|
|
|
50549
51150
|
atMs: number(),
|
|
50550
51151
|
reason: string()
|
|
50551
51152
|
});
|
|
51153
|
+
/**
|
|
51154
|
+
* The runner boot check (D877): the runners this node PLANNED (hub: one per
|
|
51155
|
+
* `resolveRunnerId` over its forked addons; agent: the runners its process
|
|
51156
|
+
* service holds, because only the hub plans) against the states the process
|
|
51157
|
+
* service reports. Kept in memory, recomputed by the same one-shot check after
|
|
51158
|
+
* every boot, served on `getServerPackageStatus`.
|
|
51159
|
+
*
|
|
51160
|
+
* `failed` is the D6 breaker's terminal state, `refused` a deterministic Init
|
|
51161
|
+
* refusal (an addon that said "I will not start, and here is why"), `missing` a
|
|
51162
|
+
* planned runner the process service has no entry for.
|
|
51163
|
+
*/
|
|
51164
|
+
var RunnerRefusalSchema = object({
|
|
51165
|
+
runnerId: string(),
|
|
51166
|
+
addonIds: array(string()),
|
|
51167
|
+
reason: string()
|
|
51168
|
+
});
|
|
51169
|
+
var RunnerBootCheckSchema = object({
|
|
51170
|
+
checkedAtMs: number(),
|
|
51171
|
+
/** Runners planned for this node. */
|
|
51172
|
+
expected: number(),
|
|
51173
|
+
/** Planned runners whose process is `running`. */
|
|
51174
|
+
running: number(),
|
|
51175
|
+
failed: array(string()),
|
|
51176
|
+
refused: array(RunnerRefusalSchema),
|
|
51177
|
+
missing: array(string()),
|
|
51178
|
+
/**
|
|
51179
|
+
* Runners still on their way: `starting`, or `crashed` waiting on a backoff
|
|
51180
|
+
* respawn. The check is FINAL only when this is empty; until then nothing is
|
|
51181
|
+
* pushed and the verdict is re-evaluated on the next runner state change.
|
|
51182
|
+
* Optional for version skew (absent = settled).
|
|
51183
|
+
*/
|
|
51184
|
+
pending: array(string()).optional(),
|
|
51185
|
+
/** True when the plan is the hub's (`missing` is then meaningful); false on an agent. */
|
|
51186
|
+
planKnown: boolean()
|
|
51187
|
+
});
|
|
50552
51188
|
var ServerPackageStatusSchema = object({
|
|
50553
51189
|
/** Root package name (`@camstack/server` on the hub). */
|
|
50554
51190
|
packageName: string(),
|
|
@@ -50611,7 +51247,14 @@ var ServerPackageStatusSchema = object({
|
|
|
50611
51247
|
* for version skew: an older provider's payload simply omits it, and an
|
|
50612
51248
|
* absent wrapper is unknown — never `native`.
|
|
50613
51249
|
*/
|
|
50614
|
-
wrapper: WrapperIdentitySchema.optional()
|
|
51250
|
+
wrapper: WrapperIdentitySchema.optional(),
|
|
51251
|
+
/**
|
|
51252
|
+
* What this node PLANNED to run against what its process service reports
|
|
51253
|
+
* (D877). Absent until the one-shot boot check has run (~60 s after boot) and
|
|
51254
|
+
* on a provider that predates it. Absent is "not checked yet", never "all
|
|
51255
|
+
* well": a consumer that needs the answer treats it as pending.
|
|
51256
|
+
*/
|
|
51257
|
+
runners: RunnerBootCheckSchema.optional()
|
|
50615
51258
|
});
|
|
50616
51259
|
var ServerUpdateCheckResultSchema = object({
|
|
50617
51260
|
packageName: string(),
|
|
@@ -50662,6 +51305,13 @@ var ServerUpdateOutcomeSchema = _enum([
|
|
|
50662
51305
|
"refused",
|
|
50663
51306
|
"failed"
|
|
50664
51307
|
]);
|
|
51308
|
+
/** One addon the pre-flight found the target version would refuse (D877). */
|
|
51309
|
+
var UpdateBlockerSchema = object({
|
|
51310
|
+
addonId: string(),
|
|
51311
|
+
reason: string(),
|
|
51312
|
+
/** What the operator does about it. */
|
|
51313
|
+
remedy: string()
|
|
51314
|
+
});
|
|
50665
51315
|
var ServerUpdateActionResultSchema = object({
|
|
50666
51316
|
accepted: boolean(),
|
|
50667
51317
|
targetVersion: string().nullable(),
|
|
@@ -50679,14 +51329,27 @@ var ServerUpdateActionResultSchema = object({
|
|
|
50679
51329
|
* The failure itself, verbatim enough to act on (the npm output for a
|
|
50680
51330
|
* staging install). Non-null only for `failed`.
|
|
50681
51331
|
*/
|
|
50682
|
-
error: string().nullable().optional()
|
|
51332
|
+
error: string().nullable().optional(),
|
|
51333
|
+
/**
|
|
51334
|
+
* The addons the target version would refuse to start on this node's live
|
|
51335
|
+
* store (D877), present when the pre-flight refused the update
|
|
51336
|
+
* (`reason: 'addon-would-refuse'`). Optional for version skew.
|
|
51337
|
+
*/
|
|
51338
|
+
blockers: array(UpdateBlockerSchema).optional()
|
|
50683
51339
|
});
|
|
50684
51340
|
method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
|
|
50685
51341
|
kind: "mutation",
|
|
50686
51342
|
auth: "admin"
|
|
50687
|
-
}), method(object({
|
|
50688
|
-
/** Explicit target version; omitted = latest from the registry. */
|
|
50689
|
-
version: string().optional()
|
|
51343
|
+
}), method(object({
|
|
51344
|
+
/** Explicit target version; omitted = latest from the registry. */
|
|
51345
|
+
version: string().optional(),
|
|
51346
|
+
/**
|
|
51347
|
+
* Apply even though the pre-flight (D877) found addons the target would
|
|
51348
|
+
* refuse to start. Off by default: those addons stay down until the
|
|
51349
|
+
* remedy is run, which is the incident this gate exists to prevent.
|
|
51350
|
+
*/
|
|
51351
|
+
acknowledgeRefusals: boolean().optional()
|
|
51352
|
+
}), ServerUpdateActionResultSchema, {
|
|
50690
51353
|
kind: "mutation",
|
|
50691
51354
|
auth: "admin",
|
|
50692
51355
|
timeoutMs: 16 * 6e4
|
|
@@ -53132,7 +53795,9 @@ var ManifestShapeSchema = object({
|
|
|
53132
53795
|
var AddonProcessSchema = object({
|
|
53133
53796
|
pid: number().optional(),
|
|
53134
53797
|
mode: string(),
|
|
53135
|
-
state: string()
|
|
53798
|
+
state: string(),
|
|
53799
|
+
/** Why the runner is `refused` (an addon's own words), when it is (D877). */
|
|
53800
|
+
reason: string().optional()
|
|
53136
53801
|
});
|
|
53137
53802
|
/**
|
|
53138
53803
|
* Per-addon health snapshot from the kernel's AddonHealthMonitor.
|
|
@@ -53900,7 +54565,8 @@ var batteryCapability = {
|
|
|
53900
54565
|
DeviceType.Button,
|
|
53901
54566
|
DeviceType.Switch,
|
|
53902
54567
|
DeviceType.PetFeeder,
|
|
53903
|
-
DeviceType.Container
|
|
54568
|
+
DeviceType.Container,
|
|
54569
|
+
DeviceType.Thermostat
|
|
53904
54570
|
],
|
|
53905
54571
|
methods: {
|
|
53906
54572
|
/**
|
|
@@ -54521,6 +55187,12 @@ var ClimateControlStatusSchema = object({
|
|
|
54521
55187
|
/** Horizontal louver swing on/off. Null when the device has no
|
|
54522
55188
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
54523
55189
|
swingHorizontal: boolean().nullable(),
|
|
55190
|
+
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
55191
|
+
minTemp: number().nullable().optional(),
|
|
55192
|
+
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
55193
|
+
maxTemp: number().nullable().optional(),
|
|
55194
|
+
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
55195
|
+
tempStep: number().positive().nullable().optional(),
|
|
54524
55196
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
54525
55197
|
lastFetchedAt: number()
|
|
54526
55198
|
});
|
|
@@ -55375,6 +56047,125 @@ onStatusChanged: { data: object({
|
|
|
55375
56047
|
* whether persisting is worth a SQLite commit. */
|
|
55376
56048
|
volatileStateFields: ["lastChangedAt"]
|
|
55377
56049
|
};
|
|
56050
|
+
/**
|
|
56051
|
+
* Smart-dishwasher cap — program lifecycle, door / remote-start gates,
|
|
56052
|
+
* consumable levels (salt, rinse aid) and common program options.
|
|
56053
|
+
*
|
|
56054
|
+
* Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
|
|
56055
|
+
* by any integration that exposes the same program / option surface.
|
|
56056
|
+
*
|
|
56057
|
+
* `kind: 'poll'` — cloud REST APIs typically have no push channel; the
|
|
56058
|
+
* provider refreshes the slice on an interval and eagerly after commands.
|
|
56059
|
+
*/
|
|
56060
|
+
var DishwasherStateSchema = _enum([
|
|
56061
|
+
"idle",
|
|
56062
|
+
"running",
|
|
56063
|
+
"paused",
|
|
56064
|
+
"finished",
|
|
56065
|
+
"error",
|
|
56066
|
+
"unavailable"
|
|
56067
|
+
]);
|
|
56068
|
+
var DishwasherConsumableLevelSchema = _enum([
|
|
56069
|
+
"ok",
|
|
56070
|
+
"low",
|
|
56071
|
+
"empty"
|
|
56072
|
+
]);
|
|
56073
|
+
var DishwasherStatusSchema = object({
|
|
56074
|
+
state: DishwasherStateSchema,
|
|
56075
|
+
/** Active program id/name, or null when none selected / unknown. */
|
|
56076
|
+
program: string().nullable(),
|
|
56077
|
+
/** Program tokens the hardware accepts — drives the UI selector. */
|
|
56078
|
+
availablePrograms: array(string()),
|
|
56079
|
+
/** Minutes remaining on the active cycle, or null when not running. */
|
|
56080
|
+
remainingMinutes: number().int().nonnegative().nullable(),
|
|
56081
|
+
/** Cycle completion 0..100, or null when not applicable. */
|
|
56082
|
+
progressPercent: number().min(0).max(100).nullable(),
|
|
56083
|
+
/** True when the door is reported open. */
|
|
56084
|
+
doorOpen: boolean(),
|
|
56085
|
+
/** True when remote start is allowed (door closed, power on, etc.). */
|
|
56086
|
+
remoteStartAllowed: boolean(),
|
|
56087
|
+
/** Main power / switched-on state. */
|
|
56088
|
+
powerOn: boolean(),
|
|
56089
|
+
saltLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
56090
|
+
rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
56091
|
+
halfLoad: boolean(),
|
|
56092
|
+
hygienePlus: boolean(),
|
|
56093
|
+
errorCode: number().nullable(),
|
|
56094
|
+
errorLabel: string().nullable(),
|
|
56095
|
+
lastFetchedAt: number()
|
|
56096
|
+
});
|
|
56097
|
+
var dishwasherCapability = {
|
|
56098
|
+
name: "dishwasher",
|
|
56099
|
+
scope: "device",
|
|
56100
|
+
deviceNative: true,
|
|
56101
|
+
mode: "singleton",
|
|
56102
|
+
deviceTypes: [DeviceType.Dishwasher],
|
|
56103
|
+
methods: {
|
|
56104
|
+
start: method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
56105
|
+
kind: "mutation",
|
|
56106
|
+
auth: "protected"
|
|
56107
|
+
}),
|
|
56108
|
+
pause: method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
56109
|
+
kind: "mutation",
|
|
56110
|
+
auth: "protected"
|
|
56111
|
+
}),
|
|
56112
|
+
stop: method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
56113
|
+
kind: "mutation",
|
|
56114
|
+
auth: "protected"
|
|
56115
|
+
}),
|
|
56116
|
+
setProgram: method(object({
|
|
56117
|
+
deviceId: number().int().nonnegative(),
|
|
56118
|
+
program: string().min(1)
|
|
56119
|
+
}), _void(), {
|
|
56120
|
+
kind: "mutation",
|
|
56121
|
+
auth: "protected"
|
|
56122
|
+
}),
|
|
56123
|
+
setPower: method(object({
|
|
56124
|
+
deviceId: number().int().nonnegative(),
|
|
56125
|
+
on: boolean()
|
|
56126
|
+
}), _void(), {
|
|
56127
|
+
kind: "mutation",
|
|
56128
|
+
auth: "protected"
|
|
56129
|
+
}),
|
|
56130
|
+
setHalfLoad: method(object({
|
|
56131
|
+
deviceId: number().int().nonnegative(),
|
|
56132
|
+
on: boolean()
|
|
56133
|
+
}), _void(), {
|
|
56134
|
+
kind: "mutation",
|
|
56135
|
+
auth: "protected"
|
|
56136
|
+
}),
|
|
56137
|
+
setHygienePlus: method(object({
|
|
56138
|
+
deviceId: number().int().nonnegative(),
|
|
56139
|
+
on: boolean()
|
|
56140
|
+
}), _void(), {
|
|
56141
|
+
kind: "mutation",
|
|
56142
|
+
auth: "protected"
|
|
56143
|
+
}),
|
|
56144
|
+
setOption: method(object({
|
|
56145
|
+
deviceId: number().int().nonnegative(),
|
|
56146
|
+
key: string().min(1),
|
|
56147
|
+
value: union([
|
|
56148
|
+
boolean(),
|
|
56149
|
+
string(),
|
|
56150
|
+
number()
|
|
56151
|
+
])
|
|
56152
|
+
}), _void(), {
|
|
56153
|
+
kind: "mutation",
|
|
56154
|
+
auth: "protected"
|
|
56155
|
+
})
|
|
56156
|
+
},
|
|
56157
|
+
status: {
|
|
56158
|
+
schema: DishwasherStatusSchema,
|
|
56159
|
+
kind: "poll"
|
|
56160
|
+
},
|
|
56161
|
+
runtimeState: DishwasherStatusSchema,
|
|
56162
|
+
durability: "session",
|
|
56163
|
+
history: { fields: { progressPercent: {
|
|
56164
|
+
kind: "gauge",
|
|
56165
|
+
unit: "%",
|
|
56166
|
+
deadband: 2
|
|
56167
|
+
} } }
|
|
56168
|
+
};
|
|
55378
56169
|
var DoorbellStatusSchema = object({
|
|
55379
56170
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
55380
56171
|
lastPressedAt: number().nullable(),
|
|
@@ -56177,6 +56968,32 @@ var gasCapability = {
|
|
|
56177
56968
|
* whether persisting is worth a SQLite commit. */
|
|
56178
56969
|
volatileStateFields: ["lastChangedAt"]
|
|
56179
56970
|
};
|
|
56971
|
+
var HeatingValveStatusSchema = object({
|
|
56972
|
+
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
56973
|
+
position: number().min(0).max(100).nullable(),
|
|
56974
|
+
/** Ms epoch when the slice was last updated (push or poll). */
|
|
56975
|
+
lastFetchedAt: number()
|
|
56976
|
+
});
|
|
56977
|
+
var heatingValveCapability = {
|
|
56978
|
+
name: "heating-valve",
|
|
56979
|
+
scope: "device",
|
|
56980
|
+
deviceNative: true,
|
|
56981
|
+
mode: "singleton",
|
|
56982
|
+
deviceTypes: [DeviceType.Thermostat],
|
|
56983
|
+
methods: {},
|
|
56984
|
+
status: {
|
|
56985
|
+
schema: HeatingValveStatusSchema,
|
|
56986
|
+
kind: "push"
|
|
56987
|
+
},
|
|
56988
|
+
runtimeState: HeatingValveStatusSchema,
|
|
56989
|
+
durability: "session",
|
|
56990
|
+
history: { fields: { position: {
|
|
56991
|
+
kind: "gauge",
|
|
56992
|
+
unit: "%",
|
|
56993
|
+
deadband: 1
|
|
56994
|
+
} } },
|
|
56995
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
56996
|
+
};
|
|
56180
56997
|
/**
|
|
56181
56998
|
* Humidifier / dehumidifier cap. Models HA `humidifier.*` entities —
|
|
56182
56999
|
* an on/off actuator with an optional target-humidity setpoint and an
|
|
@@ -57309,7 +58126,19 @@ var TlsStatusSchema = object({
|
|
|
57309
58126
|
sans: array(string()),
|
|
57310
58127
|
caCertPem: string().nullable(),
|
|
57311
58128
|
reissueError: string().nullable(),
|
|
57312
|
-
restartRequired: boolean()
|
|
58129
|
+
restartRequired: boolean(),
|
|
58130
|
+
/** An uploaded certificate is served but no CA is kept for it and it is not publicly signed (D873). */
|
|
58131
|
+
caMissing: boolean(),
|
|
58132
|
+
/** Does the hub's own generated CA carry a critical name constraint? `null` while it has none. */
|
|
58133
|
+
localCaConstrained: boolean().nullable(),
|
|
58134
|
+
/** ISO time the generated CA was replaced by a constrained one; devices must re-download it. */
|
|
58135
|
+
caReplacedAt: string().nullable(),
|
|
58136
|
+
/** The uploaded certificate kept on disk, selectable again after "Revert to generated". */
|
|
58137
|
+
storedUpload: object({
|
|
58138
|
+
leafFingerprintSha256: string(),
|
|
58139
|
+
validTo: string(),
|
|
58140
|
+
hasCa: boolean()
|
|
58141
|
+
}).nullable()
|
|
57313
58142
|
});
|
|
57314
58143
|
method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
|
|
57315
58144
|
/**
|
|
@@ -57365,6 +58194,9 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
|
|
|
57365
58194
|
}), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
|
|
57366
58195
|
kind: "mutation",
|
|
57367
58196
|
auth: "admin"
|
|
58197
|
+
}), method(_void(), TlsStatusSchema, {
|
|
58198
|
+
kind: "mutation",
|
|
58199
|
+
auth: "admin"
|
|
57368
58200
|
});
|
|
57369
58201
|
var LockControlStatusSchema = object({
|
|
57370
58202
|
/** Lifecycle state of the lock. `jammed` means the motor reported
|
|
@@ -63858,7 +64690,11 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
|
|
|
63858
64690
|
kind: "mutation",
|
|
63859
64691
|
auth: "admin",
|
|
63860
64692
|
access: "delete"
|
|
63861
|
-
}), method(object({ userId: string() }), TotpStatusSchema, { auth: "admin" }), method(
|
|
64693
|
+
}), method(object({ userId: string() }), TotpStatusSchema, { auth: "admin" }), method(RawSecretMigrationInputSchema, RawSecretMigrationReportSchema, {
|
|
64694
|
+
kind: "mutation",
|
|
64695
|
+
auth: "admin",
|
|
64696
|
+
access: "create"
|
|
64697
|
+
}), method(object({
|
|
63862
64698
|
userId: string(),
|
|
63863
64699
|
code: string()
|
|
63864
64700
|
}), object({ valid: boolean() }), {
|
|
@@ -65578,6 +66414,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
65578
66414
|
dayNight: dayNightCapability,
|
|
65579
66415
|
deviceDiscovery: deviceDiscoveryCapability,
|
|
65580
66416
|
deviceStatus: deviceStatusCapability,
|
|
66417
|
+
dishwasher: dishwasherCapability,
|
|
65581
66418
|
doorbell: doorbellCapability,
|
|
65582
66419
|
enumSensor: enumSensorCapability,
|
|
65583
66420
|
eventEmitter: eventEmitterCapability,
|
|
@@ -65585,6 +66422,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
65585
66422
|
featureProbe: featureProbeCapability,
|
|
65586
66423
|
flood: floodCapability,
|
|
65587
66424
|
gas: gasCapability,
|
|
66425
|
+
heatingValve: heatingValveCapability,
|
|
65588
66426
|
humidifier: humidifierCapability,
|
|
65589
66427
|
humiditySensor: humiditySensorCapability,
|
|
65590
66428
|
image: imageCapability,
|
|
@@ -65670,13 +66508,14 @@ var BaseDevice = class {
|
|
|
65670
66508
|
get state() {
|
|
65671
66509
|
if (!this._stateProxyCache) {
|
|
65672
66510
|
const cache = {};
|
|
65673
|
-
const handler = { get: (
|
|
66511
|
+
const handler = { get: (target, key) => {
|
|
65674
66512
|
const k = key;
|
|
65675
|
-
|
|
66513
|
+
const existing = Reflect.get(target, k);
|
|
66514
|
+
if (existing !== void 0) return existing;
|
|
65676
66515
|
const cap = DEVICE_LOCAL_STATE_CAPS[k];
|
|
65677
66516
|
if (!cap) return void 0;
|
|
65678
66517
|
const proxy = this.sliceProxy(cap);
|
|
65679
|
-
|
|
66518
|
+
Reflect.set(target, k, proxy);
|
|
65680
66519
|
return proxy;
|
|
65681
66520
|
} };
|
|
65682
66521
|
this._stateProxyCache = new Proxy(cache, handler);
|
|
@@ -65875,7 +66714,7 @@ var BaseDevice = class {
|
|
|
65875
66714
|
async updateSourceInfo(patch) {
|
|
65876
66715
|
const next = mergeSourceInfo(this.sourceInfo, patch);
|
|
65877
66716
|
this._sourceInfoCache = Object.freeze({ ...next });
|
|
65878
|
-
const action = this.ctx.api
|
|
66717
|
+
const action = this.ctx.api.deviceManager?.setMetadata;
|
|
65879
66718
|
if (action) try {
|
|
65880
66719
|
await action.mutate({
|
|
65881
66720
|
deviceId: this.id,
|
|
@@ -65910,7 +66749,7 @@ var BaseDevice = class {
|
|
|
65910
66749
|
* device boot on a meta refresh.
|
|
65911
66750
|
*/
|
|
65912
66751
|
async refreshFeatures() {
|
|
65913
|
-
const action = this.ctx.api
|
|
66752
|
+
const action = this.ctx.api.deviceManager?.registerDevice;
|
|
65914
66753
|
if (!action) return;
|
|
65915
66754
|
try {
|
|
65916
66755
|
await action.mutate({
|
|
@@ -66309,6 +67148,12 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
66309
67148
|
provider: this
|
|
66310
67149
|
}];
|
|
66311
67150
|
}
|
|
67151
|
+
/** Flatten `super.onInitialize()` whether it returned an array or an envelope. */
|
|
67152
|
+
providerRegistrationsFromSuper(result) {
|
|
67153
|
+
if (Array.isArray(result)) return result;
|
|
67154
|
+
if (result !== void 0 && result.providers !== void 0) return [...result.providers];
|
|
67155
|
+
return [];
|
|
67156
|
+
}
|
|
66312
67157
|
async onShutdown() {
|
|
66313
67158
|
this._restoreShuttingDown = true;
|
|
66314
67159
|
this.cancelRestoreRetries();
|
|
@@ -66835,7 +67680,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
66835
67680
|
return toDeviceSummary(device, this.addonId);
|
|
66836
67681
|
}
|
|
66837
67682
|
};
|
|
66838
|
-
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;
|
|
67683
|
+
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;
|
|
66839
67684
|
new Set(Object.values(DeviceType));
|
|
66840
67685
|
Object.freeze({
|
|
66841
67686
|
"accessories.getStatus": {
|
|
@@ -67984,6 +68829,12 @@ Object.freeze({
|
|
|
67984
68829
|
addonId: null,
|
|
67985
68830
|
access: "view"
|
|
67986
68831
|
},
|
|
68832
|
+
"coreBlocks.migrateRawSecrets": {
|
|
68833
|
+
capName: "core-blocks",
|
|
68834
|
+
capScope: "system",
|
|
68835
|
+
addonId: null,
|
|
68836
|
+
access: "create"
|
|
68837
|
+
},
|
|
67987
68838
|
"coreBlocks.restart": {
|
|
67988
68839
|
capName: "core-blocks",
|
|
67989
68840
|
capScope: "system",
|
|
@@ -69250,6 +70101,60 @@ Object.freeze({
|
|
|
69250
70101
|
addonId: null,
|
|
69251
70102
|
access: "view"
|
|
69252
70103
|
},
|
|
70104
|
+
"dishwasher.getStatus": {
|
|
70105
|
+
capName: "dishwasher",
|
|
70106
|
+
capScope: "device",
|
|
70107
|
+
addonId: null,
|
|
70108
|
+
access: "view"
|
|
70109
|
+
},
|
|
70110
|
+
"dishwasher.pause": {
|
|
70111
|
+
capName: "dishwasher",
|
|
70112
|
+
capScope: "device",
|
|
70113
|
+
addonId: null,
|
|
70114
|
+
access: "create"
|
|
70115
|
+
},
|
|
70116
|
+
"dishwasher.setHalfLoad": {
|
|
70117
|
+
capName: "dishwasher",
|
|
70118
|
+
capScope: "device",
|
|
70119
|
+
addonId: null,
|
|
70120
|
+
access: "create"
|
|
70121
|
+
},
|
|
70122
|
+
"dishwasher.setHygienePlus": {
|
|
70123
|
+
capName: "dishwasher",
|
|
70124
|
+
capScope: "device",
|
|
70125
|
+
addonId: null,
|
|
70126
|
+
access: "create"
|
|
70127
|
+
},
|
|
70128
|
+
"dishwasher.setOption": {
|
|
70129
|
+
capName: "dishwasher",
|
|
70130
|
+
capScope: "device",
|
|
70131
|
+
addonId: null,
|
|
70132
|
+
access: "create"
|
|
70133
|
+
},
|
|
70134
|
+
"dishwasher.setPower": {
|
|
70135
|
+
capName: "dishwasher",
|
|
70136
|
+
capScope: "device",
|
|
70137
|
+
addonId: null,
|
|
70138
|
+
access: "create"
|
|
70139
|
+
},
|
|
70140
|
+
"dishwasher.setProgram": {
|
|
70141
|
+
capName: "dishwasher",
|
|
70142
|
+
capScope: "device",
|
|
70143
|
+
addonId: null,
|
|
70144
|
+
access: "create"
|
|
70145
|
+
},
|
|
70146
|
+
"dishwasher.start": {
|
|
70147
|
+
capName: "dishwasher",
|
|
70148
|
+
capScope: "device",
|
|
70149
|
+
addonId: null,
|
|
70150
|
+
access: "create"
|
|
70151
|
+
},
|
|
70152
|
+
"dishwasher.stop": {
|
|
70153
|
+
capName: "dishwasher",
|
|
70154
|
+
capScope: "device",
|
|
70155
|
+
addonId: null,
|
|
70156
|
+
access: "create"
|
|
70157
|
+
},
|
|
69253
70158
|
"doorbell.getStatus": {
|
|
69254
70159
|
capName: "doorbell",
|
|
69255
70160
|
capScope: "device",
|
|
@@ -69460,6 +70365,12 @@ Object.freeze({
|
|
|
69460
70365
|
addonId: null,
|
|
69461
70366
|
access: "view"
|
|
69462
70367
|
},
|
|
70368
|
+
"heatingValve.getStatus": {
|
|
70369
|
+
capName: "heating-valve",
|
|
70370
|
+
capScope: "device",
|
|
70371
|
+
addonId: null,
|
|
70372
|
+
access: "view"
|
|
70373
|
+
},
|
|
69463
70374
|
"humidifier.getStatus": {
|
|
69464
70375
|
capName: "humidifier",
|
|
69465
70376
|
capScope: "device",
|
|
@@ -69670,6 +70581,12 @@ Object.freeze({
|
|
|
69670
70581
|
addonId: null,
|
|
69671
70582
|
access: "create"
|
|
69672
70583
|
},
|
|
70584
|
+
"keychainAdmin.importSecret": {
|
|
70585
|
+
capName: "keychain-admin",
|
|
70586
|
+
capScope: "system",
|
|
70587
|
+
addonId: null,
|
|
70588
|
+
access: "create"
|
|
70589
|
+
},
|
|
69673
70590
|
"keychainAdmin.listAudit": {
|
|
69674
70591
|
capName: "keychain-admin",
|
|
69675
70592
|
capScope: "system",
|
|
@@ -69838,6 +70755,12 @@ Object.freeze({
|
|
|
69838
70755
|
addonId: null,
|
|
69839
70756
|
access: "view"
|
|
69840
70757
|
},
|
|
70758
|
+
"llm.migrateRawSecrets": {
|
|
70759
|
+
capName: "llm",
|
|
70760
|
+
capScope: "system",
|
|
70761
|
+
addonId: null,
|
|
70762
|
+
access: "create"
|
|
70763
|
+
},
|
|
69841
70764
|
"llm.resolveModelRef": {
|
|
69842
70765
|
capName: "llm",
|
|
69843
70766
|
capScope: "system",
|
|
@@ -70066,6 +70989,12 @@ Object.freeze({
|
|
|
70066
70989
|
addonId: null,
|
|
70067
70990
|
access: "create"
|
|
70068
70991
|
},
|
|
70992
|
+
"localNetwork.useStoredUploadedCertificate": {
|
|
70993
|
+
capName: "local-network",
|
|
70994
|
+
capScope: "system",
|
|
70995
|
+
addonId: null,
|
|
70996
|
+
access: "create"
|
|
70997
|
+
},
|
|
70069
70998
|
"lockControl.getStatus": {
|
|
70070
70999
|
capName: "lock-control",
|
|
70071
71000
|
capScope: "device",
|
|
@@ -72718,6 +73647,30 @@ Object.freeze({
|
|
|
72718
73647
|
addonId: null,
|
|
72719
73648
|
access: "create"
|
|
72720
73649
|
},
|
|
73650
|
+
"recordEntries.deleteEntry": {
|
|
73651
|
+
capName: "record-entries",
|
|
73652
|
+
capScope: "system",
|
|
73653
|
+
addonId: null,
|
|
73654
|
+
access: "delete"
|
|
73655
|
+
},
|
|
73656
|
+
"recordEntries.listEntries": {
|
|
73657
|
+
capName: "record-entries",
|
|
73658
|
+
capScope: "system",
|
|
73659
|
+
addonId: null,
|
|
73660
|
+
access: "view"
|
|
73661
|
+
},
|
|
73662
|
+
"recordEntries.listEntryKinds": {
|
|
73663
|
+
capName: "record-entries",
|
|
73664
|
+
capScope: "system",
|
|
73665
|
+
addonId: null,
|
|
73666
|
+
access: "view"
|
|
73667
|
+
},
|
|
73668
|
+
"recordEntries.putEntry": {
|
|
73669
|
+
capName: "record-entries",
|
|
73670
|
+
capScope: "system",
|
|
73671
|
+
addonId: null,
|
|
73672
|
+
access: "create"
|
|
73673
|
+
},
|
|
72721
73674
|
"recording.getAvailability": {
|
|
72722
73675
|
capName: "recording",
|
|
72723
73676
|
capScope: "device",
|
|
@@ -73018,6 +73971,102 @@ Object.freeze({
|
|
|
73018
73971
|
addonId: null,
|
|
73019
73972
|
access: "view"
|
|
73020
73973
|
},
|
|
73974
|
+
"records.aggregate": {
|
|
73975
|
+
capName: "records",
|
|
73976
|
+
capScope: "system",
|
|
73977
|
+
addonId: null,
|
|
73978
|
+
access: "view"
|
|
73979
|
+
},
|
|
73980
|
+
"records.allocateId": {
|
|
73981
|
+
capName: "records",
|
|
73982
|
+
capScope: "system",
|
|
73983
|
+
addonId: null,
|
|
73984
|
+
access: "create"
|
|
73985
|
+
},
|
|
73986
|
+
"records.count": {
|
|
73987
|
+
capName: "records",
|
|
73988
|
+
capScope: "system",
|
|
73989
|
+
addonId: null,
|
|
73990
|
+
access: "view"
|
|
73991
|
+
},
|
|
73992
|
+
"records.declareKinds": {
|
|
73993
|
+
capName: "records",
|
|
73994
|
+
capScope: "system",
|
|
73995
|
+
addonId: null,
|
|
73996
|
+
access: "create"
|
|
73997
|
+
},
|
|
73998
|
+
"records.delete": {
|
|
73999
|
+
capName: "records",
|
|
74000
|
+
capScope: "system",
|
|
74001
|
+
addonId: null,
|
|
74002
|
+
access: "delete"
|
|
74003
|
+
},
|
|
74004
|
+
"records.deleteDevice": {
|
|
74005
|
+
capName: "records",
|
|
74006
|
+
capScope: "system",
|
|
74007
|
+
addonId: null,
|
|
74008
|
+
access: "delete"
|
|
74009
|
+
},
|
|
74010
|
+
"records.deleteMany": {
|
|
74011
|
+
capName: "records",
|
|
74012
|
+
capScope: "system",
|
|
74013
|
+
addonId: null,
|
|
74014
|
+
access: "delete"
|
|
74015
|
+
},
|
|
74016
|
+
"records.deleteWhere": {
|
|
74017
|
+
capName: "records",
|
|
74018
|
+
capScope: "system",
|
|
74019
|
+
addonId: null,
|
|
74020
|
+
access: "delete"
|
|
74021
|
+
},
|
|
74022
|
+
"records.get": {
|
|
74023
|
+
capName: "records",
|
|
74024
|
+
capScope: "system",
|
|
74025
|
+
addonId: null,
|
|
74026
|
+
access: "view"
|
|
74027
|
+
},
|
|
74028
|
+
"records.getMany": {
|
|
74029
|
+
capName: "records",
|
|
74030
|
+
capScope: "system",
|
|
74031
|
+
addonId: null,
|
|
74032
|
+
access: "view"
|
|
74033
|
+
},
|
|
74034
|
+
"records.histogram": {
|
|
74035
|
+
capName: "records",
|
|
74036
|
+
capScope: "system",
|
|
74037
|
+
addonId: null,
|
|
74038
|
+
access: "view"
|
|
74039
|
+
},
|
|
74040
|
+
"records.patch": {
|
|
74041
|
+
capName: "records",
|
|
74042
|
+
capScope: "system",
|
|
74043
|
+
addonId: null,
|
|
74044
|
+
access: "create"
|
|
74045
|
+
},
|
|
74046
|
+
"records.put": {
|
|
74047
|
+
capName: "records",
|
|
74048
|
+
capScope: "system",
|
|
74049
|
+
addonId: null,
|
|
74050
|
+
access: "create"
|
|
74051
|
+
},
|
|
74052
|
+
"records.putMany": {
|
|
74053
|
+
capName: "records",
|
|
74054
|
+
capScope: "system",
|
|
74055
|
+
addonId: null,
|
|
74056
|
+
access: "create"
|
|
74057
|
+
},
|
|
74058
|
+
"records.query": {
|
|
74059
|
+
capName: "records",
|
|
74060
|
+
capScope: "system",
|
|
74061
|
+
addonId: null,
|
|
74062
|
+
access: "view"
|
|
74063
|
+
},
|
|
74064
|
+
"records.secretRefs": {
|
|
74065
|
+
capName: "records",
|
|
74066
|
+
capScope: "system",
|
|
74067
|
+
addonId: null,
|
|
74068
|
+
access: "view"
|
|
74069
|
+
},
|
|
73021
74070
|
"sceneMonitor.captureReference": {
|
|
73022
74071
|
capName: "scene-monitor",
|
|
73023
74072
|
capScope: "device",
|
|
@@ -73450,6 +74499,48 @@ Object.freeze({
|
|
|
73450
74499
|
addonId: null,
|
|
73451
74500
|
access: "create"
|
|
73452
74501
|
},
|
|
74502
|
+
"storageAdmin.adoptRecords": {
|
|
74503
|
+
capName: "storage-admin",
|
|
74504
|
+
capScope: "system",
|
|
74505
|
+
addonId: null,
|
|
74506
|
+
access: "create"
|
|
74507
|
+
},
|
|
74508
|
+
"storageAdmin.dropCollection": {
|
|
74509
|
+
capName: "storage-admin",
|
|
74510
|
+
capScope: "system",
|
|
74511
|
+
addonId: null,
|
|
74512
|
+
access: "delete"
|
|
74513
|
+
},
|
|
74514
|
+
"storageAdmin.isAdoptedLegacyTable": {
|
|
74515
|
+
capName: "storage-admin",
|
|
74516
|
+
capScope: "system",
|
|
74517
|
+
addonId: null,
|
|
74518
|
+
access: "view"
|
|
74519
|
+
},
|
|
74520
|
+
"storageAdmin.listKinds": {
|
|
74521
|
+
capName: "storage-admin",
|
|
74522
|
+
capScope: "system",
|
|
74523
|
+
addonId: null,
|
|
74524
|
+
access: "view"
|
|
74525
|
+
},
|
|
74526
|
+
"storageAdmin.listTables": {
|
|
74527
|
+
capName: "storage-admin",
|
|
74528
|
+
capScope: "system",
|
|
74529
|
+
addonId: null,
|
|
74530
|
+
access: "view"
|
|
74531
|
+
},
|
|
74532
|
+
"storageAdmin.readLegacyCollection": {
|
|
74533
|
+
capName: "storage-admin",
|
|
74534
|
+
capScope: "system",
|
|
74535
|
+
addonId: null,
|
|
74536
|
+
access: "view"
|
|
74537
|
+
},
|
|
74538
|
+
"storageAdmin.readRecords": {
|
|
74539
|
+
capName: "storage-admin",
|
|
74540
|
+
capScope: "system",
|
|
74541
|
+
addonId: null,
|
|
74542
|
+
access: "view"
|
|
74543
|
+
},
|
|
73453
74544
|
"storageEvictable.evict": {
|
|
73454
74545
|
capName: "storage-evictable",
|
|
73455
74546
|
capScope: "system",
|
|
@@ -74362,6 +75453,12 @@ Object.freeze({
|
|
|
74362
75453
|
addonId: null,
|
|
74363
75454
|
access: "view"
|
|
74364
75455
|
},
|
|
75456
|
+
"userManagement.migrateRawSecrets": {
|
|
75457
|
+
capName: "user-management",
|
|
75458
|
+
capScope: "system",
|
|
75459
|
+
addonId: null,
|
|
75460
|
+
access: "create"
|
|
75461
|
+
},
|
|
74365
75462
|
"userManagement.oauthExchangeCode": {
|
|
74366
75463
|
capName: "user-management",
|
|
74367
75464
|
capScope: "system",
|
|
@@ -74861,7 +75958,7 @@ Object.freeze({
|
|
|
74861
75958
|
access: "create"
|
|
74862
75959
|
}
|
|
74863
75960
|
});
|
|
74864
|
-
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;
|
|
75961
|
+
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;
|
|
74865
75962
|
DeviceFeature.BatteryOperated;
|
|
74866
75963
|
Object.freeze({
|
|
74867
75964
|
"accessories.getStatus": [{
|
|
@@ -75685,6 +76782,51 @@ Object.freeze({
|
|
|
75685
76782
|
form: "single",
|
|
75686
76783
|
optional: false
|
|
75687
76784
|
}],
|
|
76785
|
+
"dishwasher.getStatus": [{
|
|
76786
|
+
name: "deviceId",
|
|
76787
|
+
form: "single",
|
|
76788
|
+
optional: false
|
|
76789
|
+
}],
|
|
76790
|
+
"dishwasher.pause": [{
|
|
76791
|
+
name: "deviceId",
|
|
76792
|
+
form: "single",
|
|
76793
|
+
optional: false
|
|
76794
|
+
}],
|
|
76795
|
+
"dishwasher.setHalfLoad": [{
|
|
76796
|
+
name: "deviceId",
|
|
76797
|
+
form: "single",
|
|
76798
|
+
optional: false
|
|
76799
|
+
}],
|
|
76800
|
+
"dishwasher.setHygienePlus": [{
|
|
76801
|
+
name: "deviceId",
|
|
76802
|
+
form: "single",
|
|
76803
|
+
optional: false
|
|
76804
|
+
}],
|
|
76805
|
+
"dishwasher.setOption": [{
|
|
76806
|
+
name: "deviceId",
|
|
76807
|
+
form: "single",
|
|
76808
|
+
optional: false
|
|
76809
|
+
}],
|
|
76810
|
+
"dishwasher.setPower": [{
|
|
76811
|
+
name: "deviceId",
|
|
76812
|
+
form: "single",
|
|
76813
|
+
optional: false
|
|
76814
|
+
}],
|
|
76815
|
+
"dishwasher.setProgram": [{
|
|
76816
|
+
name: "deviceId",
|
|
76817
|
+
form: "single",
|
|
76818
|
+
optional: false
|
|
76819
|
+
}],
|
|
76820
|
+
"dishwasher.start": [{
|
|
76821
|
+
name: "deviceId",
|
|
76822
|
+
form: "single",
|
|
76823
|
+
optional: false
|
|
76824
|
+
}],
|
|
76825
|
+
"dishwasher.stop": [{
|
|
76826
|
+
name: "deviceId",
|
|
76827
|
+
form: "single",
|
|
76828
|
+
optional: false
|
|
76829
|
+
}],
|
|
75688
76830
|
"doorbell.getStatus": [{
|
|
75689
76831
|
name: "deviceId",
|
|
75690
76832
|
form: "single",
|
|
@@ -75754,6 +76896,11 @@ Object.freeze({
|
|
|
75754
76896
|
form: "single",
|
|
75755
76897
|
optional: false
|
|
75756
76898
|
}],
|
|
76899
|
+
"heatingValve.getStatus": [{
|
|
76900
|
+
name: "deviceId",
|
|
76901
|
+
form: "single",
|
|
76902
|
+
optional: false
|
|
76903
|
+
}],
|
|
75757
76904
|
"humidifier.getStatus": [{
|
|
75758
76905
|
name: "deviceId",
|
|
75759
76906
|
form: "single",
|
|
@@ -77038,6 +78185,37 @@ Object.freeze({
|
|
|
77038
78185
|
form: "single",
|
|
77039
78186
|
optional: false
|
|
77040
78187
|
}],
|
|
78188
|
+
"records.count": [{
|
|
78189
|
+
name: "deviceId",
|
|
78190
|
+
form: "single",
|
|
78191
|
+
optional: true
|
|
78192
|
+
}],
|
|
78193
|
+
"records.deleteDevice": [{
|
|
78194
|
+
name: "deviceId",
|
|
78195
|
+
form: "single",
|
|
78196
|
+
optional: false
|
|
78197
|
+
}],
|
|
78198
|
+
"records.deleteWhere": [{
|
|
78199
|
+
name: "deviceId",
|
|
78200
|
+
form: "single",
|
|
78201
|
+
optional: true
|
|
78202
|
+
}],
|
|
78203
|
+
"records.histogram": [{
|
|
78204
|
+
name: "deviceId",
|
|
78205
|
+
form: "single",
|
|
78206
|
+
optional: true
|
|
78207
|
+
}],
|
|
78208
|
+
"records.putMany": [{
|
|
78209
|
+
name: "records",
|
|
78210
|
+
form: "object-array",
|
|
78211
|
+
optional: false,
|
|
78212
|
+
itemField: "deviceId"
|
|
78213
|
+
}],
|
|
78214
|
+
"records.query": [{
|
|
78215
|
+
name: "deviceId",
|
|
78216
|
+
form: "single",
|
|
78217
|
+
optional: true
|
|
78218
|
+
}],
|
|
77041
78219
|
"sceneMonitor.captureReference": [{
|
|
77042
78220
|
name: "deviceId",
|
|
77043
78221
|
form: "single",
|
|
@@ -77154,6 +78332,17 @@ Object.freeze({
|
|
|
77154
78332
|
form: "single",
|
|
77155
78333
|
optional: false
|
|
77156
78334
|
}],
|
|
78335
|
+
"storageAdmin.adoptRecords": [{
|
|
78336
|
+
name: "records",
|
|
78337
|
+
form: "object-array",
|
|
78338
|
+
optional: false,
|
|
78339
|
+
itemField: "deviceId"
|
|
78340
|
+
}],
|
|
78341
|
+
"storageAdmin.readRecords": [{
|
|
78342
|
+
name: "deviceId",
|
|
78343
|
+
form: "single",
|
|
78344
|
+
optional: true
|
|
78345
|
+
}],
|
|
77157
78346
|
"streamBroker.acquireEgressTranscode": [{
|
|
77158
78347
|
name: "deviceId",
|
|
77159
78348
|
form: "single",
|
|
@@ -80020,7 +81209,7 @@ var TuyaProviderAddon = class extends BaseDeviceProvider {
|
|
|
80020
81209
|
super({});
|
|
80021
81210
|
}
|
|
80022
81211
|
async onInitialize() {
|
|
80023
|
-
const regs = await super.onInitialize();
|
|
81212
|
+
const regs = this.providerRegistrationsFromSuper(await super.onInitialize());
|
|
80024
81213
|
this.clients = new TuyaClientRegistry(this.ctx.logger, tuyaConnections);
|
|
80025
81214
|
this.clients.setOnConnected((integrationId) => {
|
|
80026
81215
|
this.ctx.logger.info("Tuya: integration connected", { meta: { integrationId } });
|