@camstack/addon-training 0.1.49 → 0.1.51
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/{MotionZonesSettings-B1g6IUfQ.mjs → MotionZonesSettings-UIEvGQ7i.mjs} +2 -2
- package/dist/{PrivacyMaskSettings-D4WRZZeD.mjs → PrivacyMaskSettings-8HsoAjc4.mjs} +2 -2
- package/dist/{SceneMonitorEditor-pYZfyXtn.mjs → SceneMonitorEditor-B-2phYr7.mjs} +1 -1
- package/dist/_stub.js +4583 -4578
- package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-OY71DavC.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-BitwJXj2.mjs} +3 -3
- package/dist/{_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BVsoOuTM.mjs → _virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B91cVqvt.mjs} +1 -1
- package/dist/{dist-DvgVhVUN.js → dist-1Yys6sQo.js} +177 -26
- package/dist/{dist-D-7oMcBM.mjs → dist-tkgio-iT.mjs} +177 -26
- package/dist/{hostInit-B3DR-ujG.mjs → hostInit-DdbXSPxl.mjs} +2 -2
- package/dist/{icons-BwkaMam3.mjs → icons-BnErSNU6.mjs} +1056 -1073
- package/dist/index.js +1 -1
- package/dist/orchestrator/training.addon.js +1 -1
- package/dist/orchestrator/training.addon.mjs +1 -1
- package/dist/{player-overlays-B4V_uIvb.mjs → player-overlays-C8W-hfE1.mjs} +1 -1
- package/dist/providers/modal/training-modal.addon.js +1 -1
- package/dist/providers/modal/training-modal.addon.mjs +1 -1
- package/dist/remoteEntry.js +1 -1
- package/dist/{responsive-1iwc-rj2.mjs → responsive-BkgEJLES.mjs} +1 -1
- package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-Dk6Nf5b3.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js--X40FWTZ.mjs} +1 -1
- package/dist/{zoom-out-DDZCsqkQ.mjs → zoom-out-hR5SOKZW.mjs} +82 -65
- package/package.json +1 -1
|
@@ -5420,7 +5420,7 @@ var ZodIssueCode = {
|
|
|
5420
5420
|
var ZodFirstPartyTypeKind;
|
|
5421
5421
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5422
5422
|
//#endregion
|
|
5423
|
-
//#region ../types/dist/sleep-
|
|
5423
|
+
//#region ../types/dist/sleep-bwsTj221.mjs
|
|
5424
5424
|
/**
|
|
5425
5425
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5426
5426
|
* window to float samples (D455).
|
|
@@ -6671,7 +6671,6 @@ function createHandle(raw, opts) {
|
|
|
6671
6671
|
const writeAddon = (patch) => write("addon", opts.addonTree(), void 0, patch, () => readStoredAddonBlob(raw), (p) => raw.writeAddonStore(p));
|
|
6672
6672
|
const readAddonStoreResult = raw.readAddonStoreResult;
|
|
6673
6673
|
const readAddonStoreKeyResult = raw.readAddonStoreKeyResult;
|
|
6674
|
-
const readDeviceStoreBatch = raw.readDeviceStoreBatch;
|
|
6675
6674
|
const overrides = {
|
|
6676
6675
|
readAddonStore: async () => resolveRead("addon", await raw.readAddonStore()),
|
|
6677
6676
|
...readAddonStoreResult !== void 0 ? { readAddonStoreResult: async () => {
|
|
@@ -6695,12 +6694,12 @@ function createHandle(raw, opts) {
|
|
|
6695
6694
|
};
|
|
6696
6695
|
} } : {},
|
|
6697
6696
|
readDeviceStore: async (deviceId) => resolveRead(`device:${deviceId}`, await raw.readDeviceStore(deviceId)),
|
|
6698
|
-
|
|
6699
|
-
const rows = await readDeviceStoreBatch
|
|
6697
|
+
readDeviceStoreBatch: async (deviceIds) => {
|
|
6698
|
+
const rows = await raw.readDeviceStoreBatch(deviceIds);
|
|
6700
6699
|
const out = /* @__PURE__ */ new Map();
|
|
6701
6700
|
for (const [deviceId, blob] of rows) out.set(deviceId, await resolveRead(`device:${deviceId}`, blob));
|
|
6702
6701
|
return out;
|
|
6703
|
-
}
|
|
6702
|
+
},
|
|
6704
6703
|
writeAddonStore: async (patch) => {
|
|
6705
6704
|
await writeAddon(patch);
|
|
6706
6705
|
},
|
|
@@ -7527,7 +7526,7 @@ var BaseAddon = class {
|
|
|
7527
7526
|
return this._addonSecretTree;
|
|
7528
7527
|
}
|
|
7529
7528
|
deviceSecretTree() {
|
|
7530
|
-
this._deviceSecretTree ??= secretTreeFromSchema(this.deviceSettingsSchema());
|
|
7529
|
+
this._deviceSecretTree ??= mergeSecretStatePaths(secretTreeFromSchema(this.deviceSettingsSchema()), this.secretStatePaths);
|
|
7531
7530
|
return this._deviceSecretTree;
|
|
7532
7531
|
}
|
|
7533
7532
|
/**
|
|
@@ -7603,42 +7602,135 @@ var BaseAddon = class {
|
|
|
7603
7602
|
this[timerOf] = timer;
|
|
7604
7603
|
}
|
|
7605
7604
|
/**
|
|
7606
|
-
* Wrap `ctx.settings.readAddonStore()` with a
|
|
7607
|
-
*
|
|
7608
|
-
* swap, or any race where the SqliteSettingsBackend is between shutdown and
|
|
7609
|
-
* re-initialize) doesn't propagate up into `initialize()` and leave the
|
|
7605
|
+
* Wrap `ctx.settings.readAddonStore()` with a retry budget so a transient
|
|
7606
|
+
* settings-store outage doesn't propagate up into `initialize()` and leave the
|
|
7610
7607
|
* addon permanently broken.
|
|
7611
7608
|
*
|
|
7612
|
-
*
|
|
7613
|
-
*
|
|
7614
|
-
* `
|
|
7609
|
+
* Two kinds of outage, two budgets:
|
|
7610
|
+
* - the store's own restart fingerprints (`SqliteSettingsBackend not
|
|
7611
|
+
* initialized`, `provider not available`): a short budget, then the addon
|
|
7612
|
+
* falls back to `{}` (defaults) - its first successful patch rehydrates;
|
|
7613
|
+
* - a TRANSPORT failure (the hub is restarting while this runner boots:
|
|
7614
|
+
* `discovery deadline exceeded`, `parent could not route`, a refused or
|
|
7615
|
+
* timed-out connection). Since D870 a runner's settings read THROWS instead
|
|
7616
|
+
* of answering `{}`, so without a budget a hub restart ends in a respawn
|
|
7617
|
+
* loop. A long, bounded budget; only after it the error propagates - the
|
|
7618
|
+
* addon never runs on defaults for a store it could not ask.
|
|
7619
|
+
* Anything else propagates immediately so real bugs surface.
|
|
7615
7620
|
*/
|
|
7616
7621
|
async readAddonStoreWithRetry() {
|
|
7617
7622
|
const settings = this.rawSettings();
|
|
7618
7623
|
if (!settings) return {};
|
|
7619
|
-
const delaysMs = [
|
|
7620
|
-
150,
|
|
7621
|
-
350,
|
|
7622
|
-
600,
|
|
7623
|
-
900
|
|
7624
|
-
];
|
|
7625
7624
|
let lastErr;
|
|
7626
|
-
for (let attempt = 0
|
|
7625
|
+
for (let attempt = 0;; attempt++) try {
|
|
7627
7626
|
const stored = await settings.readAddonStore() ?? {};
|
|
7628
7627
|
this.settingsStoreReady = true;
|
|
7629
7628
|
return stored;
|
|
7630
7629
|
} catch (err) {
|
|
7631
7630
|
lastErr = err;
|
|
7632
|
-
const
|
|
7633
|
-
if (
|
|
7634
|
-
|
|
7635
|
-
|
|
7631
|
+
const kind = classifyStoreError(err);
|
|
7632
|
+
if (kind === "permanent") throw err;
|
|
7633
|
+
const delay = (kind === "transport" ? TRANSPORT_RETRY_DELAYS_MS : RESTART_RETRY_DELAYS_MS)[attempt];
|
|
7634
|
+
if (delay === void 0) {
|
|
7635
|
+
if (kind === "transport") throw err;
|
|
7636
|
+
break;
|
|
7637
|
+
}
|
|
7638
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
7636
7639
|
}
|
|
7637
7640
|
this.settingsStoreReady = false;
|
|
7638
7641
|
this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
|
|
7639
7642
|
return {};
|
|
7640
7643
|
}
|
|
7641
7644
|
};
|
|
7645
|
+
/** The settings store's own restart fingerprints. */
|
|
7646
|
+
var RESTART_RETRY_DELAYS_MS = [
|
|
7647
|
+
150,
|
|
7648
|
+
350,
|
|
7649
|
+
600,
|
|
7650
|
+
900
|
|
7651
|
+
];
|
|
7652
|
+
/** A hub restarting under a booting runner: ~100 s in total. */
|
|
7653
|
+
var TRANSPORT_RETRY_DELAYS_MS = [
|
|
7654
|
+
150,
|
|
7655
|
+
350,
|
|
7656
|
+
600,
|
|
7657
|
+
900,
|
|
7658
|
+
2e3,
|
|
7659
|
+
5e3,
|
|
7660
|
+
1e4,
|
|
7661
|
+
2e4,
|
|
7662
|
+
3e4,
|
|
7663
|
+
3e4
|
|
7664
|
+
];
|
|
7665
|
+
var RESTART_FINGERPRINTS = ["SqliteSettingsBackend not initialized", "provider not available"];
|
|
7666
|
+
/** Node / socket error codes of a connection that did not happen or broke. */
|
|
7667
|
+
var TRANSPORT_CODES = new Set([
|
|
7668
|
+
"ECONNREFUSED",
|
|
7669
|
+
"ECONNRESET",
|
|
7670
|
+
"ETIMEDOUT",
|
|
7671
|
+
"EPIPE",
|
|
7672
|
+
"EHOSTUNREACH",
|
|
7673
|
+
"ENETUNREACH"
|
|
7674
|
+
]);
|
|
7675
|
+
/** tRPC error codes that mean "the other side is not answering now", not "your call is wrong". */
|
|
7676
|
+
var UNAVAILABLE_TRPC_CODES = new Set([
|
|
7677
|
+
"TIMEOUT",
|
|
7678
|
+
"SERVICE_UNAVAILABLE",
|
|
7679
|
+
"BAD_GATEWAY",
|
|
7680
|
+
"GATEWAY_TIMEOUT"
|
|
7681
|
+
]);
|
|
7682
|
+
/** The exact phrases OUR transport raises when it cannot reach the hub. */
|
|
7683
|
+
var TRANSPORT_PHRASES = [
|
|
7684
|
+
"discovery deadline exceeded",
|
|
7685
|
+
"parent could not route child unowned cap call",
|
|
7686
|
+
"UDS request timed out after",
|
|
7687
|
+
"channel closed"
|
|
7688
|
+
];
|
|
7689
|
+
/** Moleculer error `type`s of a call that could not be served right now. */
|
|
7690
|
+
var MOLECULER_TRANSIENT_TYPES = new Set([
|
|
7691
|
+
"REQUEST_TIMEOUT",
|
|
7692
|
+
"SERVICE_NOT_FOUND",
|
|
7693
|
+
"SERVICE_NOT_AVAILABLE",
|
|
7694
|
+
"REQUEST_REJECTED",
|
|
7695
|
+
"BROKER_DISCONNECTED"
|
|
7696
|
+
]);
|
|
7697
|
+
function stringProp(value, key) {
|
|
7698
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
7699
|
+
const found = Reflect.get(value, key);
|
|
7700
|
+
return typeof found === "string" ? found : void 0;
|
|
7701
|
+
}
|
|
7702
|
+
/** The code an error carries: its own, its cause's, or a tRPC `data.code`. */
|
|
7703
|
+
function errorCode(err) {
|
|
7704
|
+
const out = {};
|
|
7705
|
+
const cause = typeof err === "object" && err !== null ? Reflect.get(err, "cause") : void 0;
|
|
7706
|
+
const data = typeof err === "object" && err !== null ? Reflect.get(err, "data") : void 0;
|
|
7707
|
+
const node = stringProp(err, "code") ?? stringProp(cause, "code");
|
|
7708
|
+
if (node !== void 0) out.node = node;
|
|
7709
|
+
const trpc = stringProp(data, "code");
|
|
7710
|
+
if (trpc !== void 0) out.trpc = trpc;
|
|
7711
|
+
return out;
|
|
7712
|
+
}
|
|
7713
|
+
/**
|
|
7714
|
+
* Is a settings read failure worth retrying, and with which budget? Only
|
|
7715
|
+
* EXPLICIT signals count: a socket error code, a tRPC "unavailable" code, or
|
|
7716
|
+
* one of the exact phrases our own transport raises. A message that merely
|
|
7717
|
+
* contains "timed out" or "unreachable" is not evidence of anything, and
|
|
7718
|
+
* `settings store not wired` is a wiring bug that retrying cannot fix.
|
|
7719
|
+
*/
|
|
7720
|
+
function classifyStoreError(err) {
|
|
7721
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7722
|
+
if (RESTART_FINGERPRINTS.some((f) => message.includes(f))) return "restart";
|
|
7723
|
+
const code = errorCode(err);
|
|
7724
|
+
if (code.node !== void 0 && TRANSPORT_CODES.has(code.node)) return "transport";
|
|
7725
|
+
if (code.trpc !== void 0 && UNAVAILABLE_TRPC_CODES.has(code.trpc)) return "transport";
|
|
7726
|
+
if (typeof err === "object" && err !== null) {
|
|
7727
|
+
if (Reflect.get(err, "retryable") === true) return "transport";
|
|
7728
|
+
const type = stringProp(err, "type");
|
|
7729
|
+
if (type !== void 0 && MOLECULER_TRANSIENT_TYPES.has(type)) return "transport";
|
|
7730
|
+
}
|
|
7731
|
+
if (TRANSPORT_PHRASES.some((f) => message.includes(f))) return "transport";
|
|
7732
|
+
return "permanent";
|
|
7733
|
+
}
|
|
7642
7734
|
/**
|
|
7643
7735
|
* Collect the keys of every field marked `perNode: true`, recursing into
|
|
7644
7736
|
* layout containers (`group` fields and `sub-tabs` tabs) the same way
|
|
@@ -8193,7 +8285,7 @@ object({
|
|
|
8193
8285
|
params: record(string(), union([string(), number()])).optional()
|
|
8194
8286
|
});
|
|
8195
8287
|
//#endregion
|
|
8196
|
-
//#region ../types/dist/err-msg
|
|
8288
|
+
//#region ../types/dist/err-msg--2RrYiLO.mjs
|
|
8197
8289
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
8198
8290
|
DeviceType["Camera"] = "camera";
|
|
8199
8291
|
DeviceType["Hub"] = "hub";
|
|
@@ -8462,6 +8554,9 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
8462
8554
|
/** Virtual HA toggle (input_boolean.*) — distinguishable from a
|
|
8463
8555
|
* real Switch device for UI rendering / export adapters. */
|
|
8464
8556
|
DeviceRole["BinaryHelper"] = "binary-helper";
|
|
8557
|
+
/** A smart plug: a `switch` whose source says it is an outlet (HA
|
|
8558
|
+
* `device_class: outlet`). The Alexa export shows it as a SMARTPLUG. */
|
|
8559
|
+
DeviceRole["Outlet"] = "outlet";
|
|
8465
8560
|
/** Generic motion / occupancy / moving event source. Distinct from
|
|
8466
8561
|
* the camera accessory PirSensor role: that one is a camera child;
|
|
8467
8562
|
* this is a standalone HA / 3rd-party motion sensor. */
|
|
@@ -8529,7 +8624,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
8529
8624
|
return DeviceRole;
|
|
8530
8625
|
}({});
|
|
8531
8626
|
//#endregion
|
|
8532
|
-
//#region ../types/dist/composition-
|
|
8627
|
+
//#region ../types/dist/composition-DOwQB_Ua.mjs
|
|
8533
8628
|
/**
|
|
8534
8629
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
8535
8630
|
*
|
|
@@ -15886,6 +15981,28 @@ id: union([string(), number()]) }), {
|
|
|
15886
15981
|
kind: "mutation",
|
|
15887
15982
|
auth: "admin"
|
|
15888
15983
|
});
|
|
15984
|
+
/** One table of the settings database. */
|
|
15985
|
+
var StorageTableSchema = object({
|
|
15986
|
+
/** The table's full name, e.g. `recorder:addon-settings` or `addon-device-settings`. */
|
|
15987
|
+
name: string(),
|
|
15988
|
+
/** The owner prefix of a scoped name (`recorder` for `recorder:addon-settings`), else null. */
|
|
15989
|
+
owner: string().nullable(),
|
|
15990
|
+
rows: number().int().nonnegative(),
|
|
15991
|
+
/** Bytes the table's pages occupy (`dbstat`); null when the engine cannot measure. */
|
|
15992
|
+
bytes: number().int().nonnegative().nullable(),
|
|
15993
|
+
/** Declared by an addon since this engine process started (a running addon claims it). */
|
|
15994
|
+
declaredThisBoot: boolean()
|
|
15995
|
+
});
|
|
15996
|
+
method(object({ ownerPrefix: string().min(1).optional() }), object({ tables: array(StorageTableSchema) }), { auth: "admin" }), method(object({
|
|
15997
|
+
collection: string().min(1),
|
|
15998
|
+
expectRows: number().int().nonnegative()
|
|
15999
|
+
}), object({
|
|
16000
|
+
dropped: literal(true),
|
|
16001
|
+
rows: number().int().nonnegative()
|
|
16002
|
+
}), {
|
|
16003
|
+
kind: "mutation",
|
|
16004
|
+
auth: "admin"
|
|
16005
|
+
});
|
|
15889
16006
|
/**
|
|
15890
16007
|
* `keychain` — the hub's encrypted store of secret values (D787).
|
|
15891
16008
|
*
|
|
@@ -16427,6 +16544,16 @@ method(object({}), KeychainStatusSchema, { auth: "admin" }), method(object({}),
|
|
|
16427
16544
|
kind: "mutation",
|
|
16428
16545
|
auth: "admin",
|
|
16429
16546
|
caller: "required"
|
|
16547
|
+
}), method(object({
|
|
16548
|
+
ref: string().min(1),
|
|
16549
|
+
value: string().min(1)
|
|
16550
|
+
}), object({
|
|
16551
|
+
ref: string(),
|
|
16552
|
+
version: number().int()
|
|
16553
|
+
}), {
|
|
16554
|
+
kind: "mutation",
|
|
16555
|
+
auth: "admin",
|
|
16556
|
+
caller: "required"
|
|
16430
16557
|
}), method(object({ refs: array(string().min(1)).max(1e3) }), object({
|
|
16431
16558
|
deleted: array(string()).readonly(),
|
|
16432
16559
|
kept: array(object({
|
|
@@ -52872,6 +52999,12 @@ object({
|
|
|
52872
52999
|
/** Horizontal louver swing on/off. Null when the device has no
|
|
52873
53000
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
52874
53001
|
swingHorizontal: boolean().nullable(),
|
|
53002
|
+
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
53003
|
+
minTemp: number().nullable().optional(),
|
|
53004
|
+
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
53005
|
+
maxTemp: number().nullable().optional(),
|
|
53006
|
+
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
53007
|
+
tempStep: number().positive().nullable().optional(),
|
|
52875
53008
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
52876
53009
|
lastFetchedAt: number()
|
|
52877
53010
|
});
|
|
@@ -63879,6 +64012,12 @@ Object.freeze({
|
|
|
63879
64012
|
addonId: null,
|
|
63880
64013
|
access: "create"
|
|
63881
64014
|
},
|
|
64015
|
+
"keychainAdmin.importSecret": {
|
|
64016
|
+
capName: "keychain-admin",
|
|
64017
|
+
capScope: "system",
|
|
64018
|
+
addonId: null,
|
|
64019
|
+
access: "create"
|
|
64020
|
+
},
|
|
63882
64021
|
"keychainAdmin.listAudit": {
|
|
63883
64022
|
capName: "keychain-admin",
|
|
63884
64023
|
capScope: "system",
|
|
@@ -67665,6 +67804,18 @@ Object.freeze({
|
|
|
67665
67804
|
addonId: null,
|
|
67666
67805
|
access: "create"
|
|
67667
67806
|
},
|
|
67807
|
+
"storageAdmin.dropCollection": {
|
|
67808
|
+
capName: "storage-admin",
|
|
67809
|
+
capScope: "system",
|
|
67810
|
+
addonId: null,
|
|
67811
|
+
access: "delete"
|
|
67812
|
+
},
|
|
67813
|
+
"storageAdmin.listTables": {
|
|
67814
|
+
capName: "storage-admin",
|
|
67815
|
+
capScope: "system",
|
|
67816
|
+
addonId: null,
|
|
67817
|
+
access: "view"
|
|
67818
|
+
},
|
|
67668
67819
|
"storageEvictable.evict": {
|
|
67669
67820
|
capName: "storage-evictable",
|
|
67670
67821
|
capScope: "system",
|
|
@@ -5387,7 +5387,7 @@ var ZodIssueCode = {
|
|
|
5387
5387
|
var ZodFirstPartyTypeKind;
|
|
5388
5388
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5389
5389
|
//#endregion
|
|
5390
|
-
//#region ../types/dist/sleep-
|
|
5390
|
+
//#region ../types/dist/sleep-bwsTj221.mjs
|
|
5391
5391
|
/**
|
|
5392
5392
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5393
5393
|
* window to float samples (D455).
|
|
@@ -6638,7 +6638,6 @@ function createHandle(raw, opts) {
|
|
|
6638
6638
|
const writeAddon = (patch) => write("addon", opts.addonTree(), void 0, patch, () => readStoredAddonBlob(raw), (p) => raw.writeAddonStore(p));
|
|
6639
6639
|
const readAddonStoreResult = raw.readAddonStoreResult;
|
|
6640
6640
|
const readAddonStoreKeyResult = raw.readAddonStoreKeyResult;
|
|
6641
|
-
const readDeviceStoreBatch = raw.readDeviceStoreBatch;
|
|
6642
6641
|
const overrides = {
|
|
6643
6642
|
readAddonStore: async () => resolveRead("addon", await raw.readAddonStore()),
|
|
6644
6643
|
...readAddonStoreResult !== void 0 ? { readAddonStoreResult: async () => {
|
|
@@ -6662,12 +6661,12 @@ function createHandle(raw, opts) {
|
|
|
6662
6661
|
};
|
|
6663
6662
|
} } : {},
|
|
6664
6663
|
readDeviceStore: async (deviceId) => resolveRead(`device:${deviceId}`, await raw.readDeviceStore(deviceId)),
|
|
6665
|
-
|
|
6666
|
-
const rows = await readDeviceStoreBatch
|
|
6664
|
+
readDeviceStoreBatch: async (deviceIds) => {
|
|
6665
|
+
const rows = await raw.readDeviceStoreBatch(deviceIds);
|
|
6667
6666
|
const out = /* @__PURE__ */ new Map();
|
|
6668
6667
|
for (const [deviceId, blob] of rows) out.set(deviceId, await resolveRead(`device:${deviceId}`, blob));
|
|
6669
6668
|
return out;
|
|
6670
|
-
}
|
|
6669
|
+
},
|
|
6671
6670
|
writeAddonStore: async (patch) => {
|
|
6672
6671
|
await writeAddon(patch);
|
|
6673
6672
|
},
|
|
@@ -7494,7 +7493,7 @@ var BaseAddon = class {
|
|
|
7494
7493
|
return this._addonSecretTree;
|
|
7495
7494
|
}
|
|
7496
7495
|
deviceSecretTree() {
|
|
7497
|
-
this._deviceSecretTree ??= secretTreeFromSchema(this.deviceSettingsSchema());
|
|
7496
|
+
this._deviceSecretTree ??= mergeSecretStatePaths(secretTreeFromSchema(this.deviceSettingsSchema()), this.secretStatePaths);
|
|
7498
7497
|
return this._deviceSecretTree;
|
|
7499
7498
|
}
|
|
7500
7499
|
/**
|
|
@@ -7570,42 +7569,135 @@ var BaseAddon = class {
|
|
|
7570
7569
|
this[timerOf] = timer;
|
|
7571
7570
|
}
|
|
7572
7571
|
/**
|
|
7573
|
-
* Wrap `ctx.settings.readAddonStore()` with a
|
|
7574
|
-
*
|
|
7575
|
-
* swap, or any race where the SqliteSettingsBackend is between shutdown and
|
|
7576
|
-
* re-initialize) doesn't propagate up into `initialize()` and leave the
|
|
7572
|
+
* Wrap `ctx.settings.readAddonStore()` with a retry budget so a transient
|
|
7573
|
+
* settings-store outage doesn't propagate up into `initialize()` and leave the
|
|
7577
7574
|
* addon permanently broken.
|
|
7578
7575
|
*
|
|
7579
|
-
*
|
|
7580
|
-
*
|
|
7581
|
-
* `
|
|
7576
|
+
* Two kinds of outage, two budgets:
|
|
7577
|
+
* - the store's own restart fingerprints (`SqliteSettingsBackend not
|
|
7578
|
+
* initialized`, `provider not available`): a short budget, then the addon
|
|
7579
|
+
* falls back to `{}` (defaults) - its first successful patch rehydrates;
|
|
7580
|
+
* - a TRANSPORT failure (the hub is restarting while this runner boots:
|
|
7581
|
+
* `discovery deadline exceeded`, `parent could not route`, a refused or
|
|
7582
|
+
* timed-out connection). Since D870 a runner's settings read THROWS instead
|
|
7583
|
+
* of answering `{}`, so without a budget a hub restart ends in a respawn
|
|
7584
|
+
* loop. A long, bounded budget; only after it the error propagates - the
|
|
7585
|
+
* addon never runs on defaults for a store it could not ask.
|
|
7586
|
+
* Anything else propagates immediately so real bugs surface.
|
|
7582
7587
|
*/
|
|
7583
7588
|
async readAddonStoreWithRetry() {
|
|
7584
7589
|
const settings = this.rawSettings();
|
|
7585
7590
|
if (!settings) return {};
|
|
7586
|
-
const delaysMs = [
|
|
7587
|
-
150,
|
|
7588
|
-
350,
|
|
7589
|
-
600,
|
|
7590
|
-
900
|
|
7591
|
-
];
|
|
7592
7591
|
let lastErr;
|
|
7593
|
-
for (let attempt = 0
|
|
7592
|
+
for (let attempt = 0;; attempt++) try {
|
|
7594
7593
|
const stored = await settings.readAddonStore() ?? {};
|
|
7595
7594
|
this.settingsStoreReady = true;
|
|
7596
7595
|
return stored;
|
|
7597
7596
|
} catch (err) {
|
|
7598
7597
|
lastErr = err;
|
|
7599
|
-
const
|
|
7600
|
-
if (
|
|
7601
|
-
|
|
7602
|
-
|
|
7598
|
+
const kind = classifyStoreError(err);
|
|
7599
|
+
if (kind === "permanent") throw err;
|
|
7600
|
+
const delay = (kind === "transport" ? TRANSPORT_RETRY_DELAYS_MS : RESTART_RETRY_DELAYS_MS)[attempt];
|
|
7601
|
+
if (delay === void 0) {
|
|
7602
|
+
if (kind === "transport") throw err;
|
|
7603
|
+
break;
|
|
7604
|
+
}
|
|
7605
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
7603
7606
|
}
|
|
7604
7607
|
this.settingsStoreReady = false;
|
|
7605
7608
|
this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
|
|
7606
7609
|
return {};
|
|
7607
7610
|
}
|
|
7608
7611
|
};
|
|
7612
|
+
/** The settings store's own restart fingerprints. */
|
|
7613
|
+
var RESTART_RETRY_DELAYS_MS = [
|
|
7614
|
+
150,
|
|
7615
|
+
350,
|
|
7616
|
+
600,
|
|
7617
|
+
900
|
|
7618
|
+
];
|
|
7619
|
+
/** A hub restarting under a booting runner: ~100 s in total. */
|
|
7620
|
+
var TRANSPORT_RETRY_DELAYS_MS = [
|
|
7621
|
+
150,
|
|
7622
|
+
350,
|
|
7623
|
+
600,
|
|
7624
|
+
900,
|
|
7625
|
+
2e3,
|
|
7626
|
+
5e3,
|
|
7627
|
+
1e4,
|
|
7628
|
+
2e4,
|
|
7629
|
+
3e4,
|
|
7630
|
+
3e4
|
|
7631
|
+
];
|
|
7632
|
+
var RESTART_FINGERPRINTS = ["SqliteSettingsBackend not initialized", "provider not available"];
|
|
7633
|
+
/** Node / socket error codes of a connection that did not happen or broke. */
|
|
7634
|
+
var TRANSPORT_CODES = new Set([
|
|
7635
|
+
"ECONNREFUSED",
|
|
7636
|
+
"ECONNRESET",
|
|
7637
|
+
"ETIMEDOUT",
|
|
7638
|
+
"EPIPE",
|
|
7639
|
+
"EHOSTUNREACH",
|
|
7640
|
+
"ENETUNREACH"
|
|
7641
|
+
]);
|
|
7642
|
+
/** tRPC error codes that mean "the other side is not answering now", not "your call is wrong". */
|
|
7643
|
+
var UNAVAILABLE_TRPC_CODES = new Set([
|
|
7644
|
+
"TIMEOUT",
|
|
7645
|
+
"SERVICE_UNAVAILABLE",
|
|
7646
|
+
"BAD_GATEWAY",
|
|
7647
|
+
"GATEWAY_TIMEOUT"
|
|
7648
|
+
]);
|
|
7649
|
+
/** The exact phrases OUR transport raises when it cannot reach the hub. */
|
|
7650
|
+
var TRANSPORT_PHRASES = [
|
|
7651
|
+
"discovery deadline exceeded",
|
|
7652
|
+
"parent could not route child unowned cap call",
|
|
7653
|
+
"UDS request timed out after",
|
|
7654
|
+
"channel closed"
|
|
7655
|
+
];
|
|
7656
|
+
/** Moleculer error `type`s of a call that could not be served right now. */
|
|
7657
|
+
var MOLECULER_TRANSIENT_TYPES = new Set([
|
|
7658
|
+
"REQUEST_TIMEOUT",
|
|
7659
|
+
"SERVICE_NOT_FOUND",
|
|
7660
|
+
"SERVICE_NOT_AVAILABLE",
|
|
7661
|
+
"REQUEST_REJECTED",
|
|
7662
|
+
"BROKER_DISCONNECTED"
|
|
7663
|
+
]);
|
|
7664
|
+
function stringProp(value, key) {
|
|
7665
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
7666
|
+
const found = Reflect.get(value, key);
|
|
7667
|
+
return typeof found === "string" ? found : void 0;
|
|
7668
|
+
}
|
|
7669
|
+
/** The code an error carries: its own, its cause's, or a tRPC `data.code`. */
|
|
7670
|
+
function errorCode(err) {
|
|
7671
|
+
const out = {};
|
|
7672
|
+
const cause = typeof err === "object" && err !== null ? Reflect.get(err, "cause") : void 0;
|
|
7673
|
+
const data = typeof err === "object" && err !== null ? Reflect.get(err, "data") : void 0;
|
|
7674
|
+
const node = stringProp(err, "code") ?? stringProp(cause, "code");
|
|
7675
|
+
if (node !== void 0) out.node = node;
|
|
7676
|
+
const trpc = stringProp(data, "code");
|
|
7677
|
+
if (trpc !== void 0) out.trpc = trpc;
|
|
7678
|
+
return out;
|
|
7679
|
+
}
|
|
7680
|
+
/**
|
|
7681
|
+
* Is a settings read failure worth retrying, and with which budget? Only
|
|
7682
|
+
* EXPLICIT signals count: a socket error code, a tRPC "unavailable" code, or
|
|
7683
|
+
* one of the exact phrases our own transport raises. A message that merely
|
|
7684
|
+
* contains "timed out" or "unreachable" is not evidence of anything, and
|
|
7685
|
+
* `settings store not wired` is a wiring bug that retrying cannot fix.
|
|
7686
|
+
*/
|
|
7687
|
+
function classifyStoreError(err) {
|
|
7688
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7689
|
+
if (RESTART_FINGERPRINTS.some((f) => message.includes(f))) return "restart";
|
|
7690
|
+
const code = errorCode(err);
|
|
7691
|
+
if (code.node !== void 0 && TRANSPORT_CODES.has(code.node)) return "transport";
|
|
7692
|
+
if (code.trpc !== void 0 && UNAVAILABLE_TRPC_CODES.has(code.trpc)) return "transport";
|
|
7693
|
+
if (typeof err === "object" && err !== null) {
|
|
7694
|
+
if (Reflect.get(err, "retryable") === true) return "transport";
|
|
7695
|
+
const type = stringProp(err, "type");
|
|
7696
|
+
if (type !== void 0 && MOLECULER_TRANSIENT_TYPES.has(type)) return "transport";
|
|
7697
|
+
}
|
|
7698
|
+
if (TRANSPORT_PHRASES.some((f) => message.includes(f))) return "transport";
|
|
7699
|
+
return "permanent";
|
|
7700
|
+
}
|
|
7609
7701
|
/**
|
|
7610
7702
|
* Collect the keys of every field marked `perNode: true`, recursing into
|
|
7611
7703
|
* layout containers (`group` fields and `sub-tabs` tabs) the same way
|
|
@@ -8160,7 +8252,7 @@ object({
|
|
|
8160
8252
|
params: record(string(), union([string(), number()])).optional()
|
|
8161
8253
|
});
|
|
8162
8254
|
//#endregion
|
|
8163
|
-
//#region ../types/dist/err-msg
|
|
8255
|
+
//#region ../types/dist/err-msg--2RrYiLO.mjs
|
|
8164
8256
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
8165
8257
|
DeviceType["Camera"] = "camera";
|
|
8166
8258
|
DeviceType["Hub"] = "hub";
|
|
@@ -8429,6 +8521,9 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
8429
8521
|
/** Virtual HA toggle (input_boolean.*) — distinguishable from a
|
|
8430
8522
|
* real Switch device for UI rendering / export adapters. */
|
|
8431
8523
|
DeviceRole["BinaryHelper"] = "binary-helper";
|
|
8524
|
+
/** A smart plug: a `switch` whose source says it is an outlet (HA
|
|
8525
|
+
* `device_class: outlet`). The Alexa export shows it as a SMARTPLUG. */
|
|
8526
|
+
DeviceRole["Outlet"] = "outlet";
|
|
8432
8527
|
/** Generic motion / occupancy / moving event source. Distinct from
|
|
8433
8528
|
* the camera accessory PirSensor role: that one is a camera child;
|
|
8434
8529
|
* this is a standalone HA / 3rd-party motion sensor. */
|
|
@@ -8496,7 +8591,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
8496
8591
|
return DeviceRole;
|
|
8497
8592
|
}({});
|
|
8498
8593
|
//#endregion
|
|
8499
|
-
//#region ../types/dist/composition-
|
|
8594
|
+
//#region ../types/dist/composition-DOwQB_Ua.mjs
|
|
8500
8595
|
/**
|
|
8501
8596
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
8502
8597
|
*
|
|
@@ -15853,6 +15948,28 @@ id: union([string(), number()]) }), {
|
|
|
15853
15948
|
kind: "mutation",
|
|
15854
15949
|
auth: "admin"
|
|
15855
15950
|
});
|
|
15951
|
+
/** One table of the settings database. */
|
|
15952
|
+
var StorageTableSchema = object({
|
|
15953
|
+
/** The table's full name, e.g. `recorder:addon-settings` or `addon-device-settings`. */
|
|
15954
|
+
name: string(),
|
|
15955
|
+
/** The owner prefix of a scoped name (`recorder` for `recorder:addon-settings`), else null. */
|
|
15956
|
+
owner: string().nullable(),
|
|
15957
|
+
rows: number().int().nonnegative(),
|
|
15958
|
+
/** Bytes the table's pages occupy (`dbstat`); null when the engine cannot measure. */
|
|
15959
|
+
bytes: number().int().nonnegative().nullable(),
|
|
15960
|
+
/** Declared by an addon since this engine process started (a running addon claims it). */
|
|
15961
|
+
declaredThisBoot: boolean()
|
|
15962
|
+
});
|
|
15963
|
+
method(object({ ownerPrefix: string().min(1).optional() }), object({ tables: array(StorageTableSchema) }), { auth: "admin" }), method(object({
|
|
15964
|
+
collection: string().min(1),
|
|
15965
|
+
expectRows: number().int().nonnegative()
|
|
15966
|
+
}), object({
|
|
15967
|
+
dropped: literal(true),
|
|
15968
|
+
rows: number().int().nonnegative()
|
|
15969
|
+
}), {
|
|
15970
|
+
kind: "mutation",
|
|
15971
|
+
auth: "admin"
|
|
15972
|
+
});
|
|
15856
15973
|
/**
|
|
15857
15974
|
* `keychain` — the hub's encrypted store of secret values (D787).
|
|
15858
15975
|
*
|
|
@@ -16394,6 +16511,16 @@ method(object({}), KeychainStatusSchema, { auth: "admin" }), method(object({}),
|
|
|
16394
16511
|
kind: "mutation",
|
|
16395
16512
|
auth: "admin",
|
|
16396
16513
|
caller: "required"
|
|
16514
|
+
}), method(object({
|
|
16515
|
+
ref: string().min(1),
|
|
16516
|
+
value: string().min(1)
|
|
16517
|
+
}), object({
|
|
16518
|
+
ref: string(),
|
|
16519
|
+
version: number().int()
|
|
16520
|
+
}), {
|
|
16521
|
+
kind: "mutation",
|
|
16522
|
+
auth: "admin",
|
|
16523
|
+
caller: "required"
|
|
16397
16524
|
}), method(object({ refs: array(string().min(1)).max(1e3) }), object({
|
|
16398
16525
|
deleted: array(string()).readonly(),
|
|
16399
16526
|
kept: array(object({
|
|
@@ -52839,6 +52966,12 @@ object({
|
|
|
52839
52966
|
/** Horizontal louver swing on/off. Null when the device has no
|
|
52840
52967
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
52841
52968
|
swingHorizontal: boolean().nullable(),
|
|
52969
|
+
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
52970
|
+
minTemp: number().nullable().optional(),
|
|
52971
|
+
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
52972
|
+
maxTemp: number().nullable().optional(),
|
|
52973
|
+
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
52974
|
+
tempStep: number().positive().nullable().optional(),
|
|
52842
52975
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
52843
52976
|
lastFetchedAt: number()
|
|
52844
52977
|
});
|
|
@@ -63846,6 +63979,12 @@ Object.freeze({
|
|
|
63846
63979
|
addonId: null,
|
|
63847
63980
|
access: "create"
|
|
63848
63981
|
},
|
|
63982
|
+
"keychainAdmin.importSecret": {
|
|
63983
|
+
capName: "keychain-admin",
|
|
63984
|
+
capScope: "system",
|
|
63985
|
+
addonId: null,
|
|
63986
|
+
access: "create"
|
|
63987
|
+
},
|
|
63849
63988
|
"keychainAdmin.listAudit": {
|
|
63850
63989
|
capName: "keychain-admin",
|
|
63851
63990
|
capScope: "system",
|
|
@@ -67632,6 +67771,18 @@ Object.freeze({
|
|
|
67632
67771
|
addonId: null,
|
|
67633
67772
|
access: "create"
|
|
67634
67773
|
},
|
|
67774
|
+
"storageAdmin.dropCollection": {
|
|
67775
|
+
capName: "storage-admin",
|
|
67776
|
+
capScope: "system",
|
|
67777
|
+
addonId: null,
|
|
67778
|
+
access: "delete"
|
|
67779
|
+
},
|
|
67780
|
+
"storageAdmin.listTables": {
|
|
67781
|
+
capName: "storage-admin",
|
|
67782
|
+
capScope: "system",
|
|
67783
|
+
addonId: null,
|
|
67784
|
+
access: "view"
|
|
67785
|
+
},
|
|
67635
67786
|
"storageEvictable.evict": {
|
|
67636
67787
|
capName: "storage-evictable",
|
|
67637
67788
|
capScope: "system",
|
|
@@ -36,7 +36,7 @@ async function r() {
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"@camstack/types": {
|
|
39
|
-
version: "1.2.
|
|
39
|
+
version: "1.2.377",
|
|
40
40
|
scope: "default",
|
|
41
41
|
shareConfig: {
|
|
42
42
|
singleton: !0,
|
|
@@ -81,7 +81,7 @@ async function r() {
|
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
"@camstack/ui-library": {
|
|
84
|
-
version: "1.2.
|
|
84
|
+
version: "1.2.295",
|
|
85
85
|
scope: "default",
|
|
86
86
|
shareConfig: {
|
|
87
87
|
singleton: !0,
|