@camstack/addon-model-studio 1.1.263 → 1.1.265
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-DtoUJxd6.mjs → MotionZonesSettings-DXOf3xDp.mjs} +2 -2
- package/dist/{PrivacyMaskSettings-Bd5lL0CO.mjs → PrivacyMaskSettings-DasEXHXg.mjs} +4 -4
- package/dist/{SceneMonitorEditor-BG0CBUrr.mjs → SceneMonitorEditor-ClVvQVl6.mjs} +3 -3
- package/dist/_stub.js +3115 -3093
- package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-DANjfgEB.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-DSIDYb1S.mjs} +3 -3
- package/dist/{_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DlW3IlLM.mjs → _virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B0F3F6BP.mjs} +1 -1
- package/dist/{hostInit-DE_6Mq5X.mjs → hostInit-DuCPmdPM.mjs} +2 -2
- package/dist/model-studio.addon.js +177 -26
- package/dist/model-studio.addon.mjs +177 -26
- package/dist/{player-overlays-DXeDukPC.mjs → player-overlays-BWxIhTSh.mjs} +1 -1
- package/dist/remoteEntry.js +1 -1
- package/dist/{responsive-D9Bo78lO.mjs → responsive-Bb8t1Rws.mjs} +1 -1
- package/dist/{scene-monitor-copy-CQr7egaT.mjs → scene-monitor-copy-Bps8TGiG.mjs} +1 -1
- package/dist/{square-d__poSpa.mjs → square-DSJt_nVw.mjs} +1 -1
- package/dist/{trash-2-C0XdoZQu.mjs → trash-2-CzUTU-oX.mjs} +1 -1
- package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-CxkFEexB.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-LnfkvJQ6.mjs} +1 -1
- package/package.json +1 -1
|
@@ -5782,7 +5782,7 @@ var ZodIssueCode = {
|
|
|
5782
5782
|
var ZodFirstPartyTypeKind;
|
|
5783
5783
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5784
5784
|
//#endregion
|
|
5785
|
-
//#region ../types/dist/sleep-
|
|
5785
|
+
//#region ../types/dist/sleep-bwsTj221.mjs
|
|
5786
5786
|
/**
|
|
5787
5787
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5788
5788
|
* window to float samples (D455).
|
|
@@ -7033,7 +7033,6 @@ function createHandle(raw, opts) {
|
|
|
7033
7033
|
const writeAddon = (patch) => write("addon", opts.addonTree(), void 0, patch, () => readStoredAddonBlob(raw), (p) => raw.writeAddonStore(p));
|
|
7034
7034
|
const readAddonStoreResult = raw.readAddonStoreResult;
|
|
7035
7035
|
const readAddonStoreKeyResult = raw.readAddonStoreKeyResult;
|
|
7036
|
-
const readDeviceStoreBatch = raw.readDeviceStoreBatch;
|
|
7037
7036
|
const overrides = {
|
|
7038
7037
|
readAddonStore: async () => resolveRead("addon", await raw.readAddonStore()),
|
|
7039
7038
|
...readAddonStoreResult !== void 0 ? { readAddonStoreResult: async () => {
|
|
@@ -7057,12 +7056,12 @@ function createHandle(raw, opts) {
|
|
|
7057
7056
|
};
|
|
7058
7057
|
} } : {},
|
|
7059
7058
|
readDeviceStore: async (deviceId) => resolveRead(`device:${deviceId}`, await raw.readDeviceStore(deviceId)),
|
|
7060
|
-
|
|
7061
|
-
const rows = await readDeviceStoreBatch
|
|
7059
|
+
readDeviceStoreBatch: async (deviceIds) => {
|
|
7060
|
+
const rows = await raw.readDeviceStoreBatch(deviceIds);
|
|
7062
7061
|
const out = /* @__PURE__ */ new Map();
|
|
7063
7062
|
for (const [deviceId, blob] of rows) out.set(deviceId, await resolveRead(`device:${deviceId}`, blob));
|
|
7064
7063
|
return out;
|
|
7065
|
-
}
|
|
7064
|
+
},
|
|
7066
7065
|
writeAddonStore: async (patch) => {
|
|
7067
7066
|
await writeAddon(patch);
|
|
7068
7067
|
},
|
|
@@ -7889,7 +7888,7 @@ var BaseAddon = class {
|
|
|
7889
7888
|
return this._addonSecretTree;
|
|
7890
7889
|
}
|
|
7891
7890
|
deviceSecretTree() {
|
|
7892
|
-
this._deviceSecretTree ??= secretTreeFromSchema(this.deviceSettingsSchema());
|
|
7891
|
+
this._deviceSecretTree ??= mergeSecretStatePaths(secretTreeFromSchema(this.deviceSettingsSchema()), this.secretStatePaths);
|
|
7893
7892
|
return this._deviceSecretTree;
|
|
7894
7893
|
}
|
|
7895
7894
|
/**
|
|
@@ -7965,42 +7964,135 @@ var BaseAddon = class {
|
|
|
7965
7964
|
this[timerOf] = timer;
|
|
7966
7965
|
}
|
|
7967
7966
|
/**
|
|
7968
|
-
* Wrap `ctx.settings.readAddonStore()` with a
|
|
7969
|
-
*
|
|
7970
|
-
* swap, or any race where the SqliteSettingsBackend is between shutdown and
|
|
7971
|
-
* re-initialize) doesn't propagate up into `initialize()` and leave the
|
|
7967
|
+
* Wrap `ctx.settings.readAddonStore()` with a retry budget so a transient
|
|
7968
|
+
* settings-store outage doesn't propagate up into `initialize()` and leave the
|
|
7972
7969
|
* addon permanently broken.
|
|
7973
7970
|
*
|
|
7974
|
-
*
|
|
7975
|
-
*
|
|
7976
|
-
* `
|
|
7971
|
+
* Two kinds of outage, two budgets:
|
|
7972
|
+
* - the store's own restart fingerprints (`SqliteSettingsBackend not
|
|
7973
|
+
* initialized`, `provider not available`): a short budget, then the addon
|
|
7974
|
+
* falls back to `{}` (defaults) - its first successful patch rehydrates;
|
|
7975
|
+
* - a TRANSPORT failure (the hub is restarting while this runner boots:
|
|
7976
|
+
* `discovery deadline exceeded`, `parent could not route`, a refused or
|
|
7977
|
+
* timed-out connection). Since D870 a runner's settings read THROWS instead
|
|
7978
|
+
* of answering `{}`, so without a budget a hub restart ends in a respawn
|
|
7979
|
+
* loop. A long, bounded budget; only after it the error propagates - the
|
|
7980
|
+
* addon never runs on defaults for a store it could not ask.
|
|
7981
|
+
* Anything else propagates immediately so real bugs surface.
|
|
7977
7982
|
*/
|
|
7978
7983
|
async readAddonStoreWithRetry() {
|
|
7979
7984
|
const settings = this.rawSettings();
|
|
7980
7985
|
if (!settings) return {};
|
|
7981
|
-
const delaysMs = [
|
|
7982
|
-
150,
|
|
7983
|
-
350,
|
|
7984
|
-
600,
|
|
7985
|
-
900
|
|
7986
|
-
];
|
|
7987
7986
|
let lastErr;
|
|
7988
|
-
for (let attempt = 0
|
|
7987
|
+
for (let attempt = 0;; attempt++) try {
|
|
7989
7988
|
const stored = await settings.readAddonStore() ?? {};
|
|
7990
7989
|
this.settingsStoreReady = true;
|
|
7991
7990
|
return stored;
|
|
7992
7991
|
} catch (err) {
|
|
7993
7992
|
lastErr = err;
|
|
7994
|
-
const
|
|
7995
|
-
if (
|
|
7996
|
-
|
|
7997
|
-
|
|
7993
|
+
const kind = classifyStoreError(err);
|
|
7994
|
+
if (kind === "permanent") throw err;
|
|
7995
|
+
const delay = (kind === "transport" ? TRANSPORT_RETRY_DELAYS_MS : RESTART_RETRY_DELAYS_MS)[attempt];
|
|
7996
|
+
if (delay === void 0) {
|
|
7997
|
+
if (kind === "transport") throw err;
|
|
7998
|
+
break;
|
|
7999
|
+
}
|
|
8000
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
7998
8001
|
}
|
|
7999
8002
|
this.settingsStoreReady = false;
|
|
8000
8003
|
this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
|
|
8001
8004
|
return {};
|
|
8002
8005
|
}
|
|
8003
8006
|
};
|
|
8007
|
+
/** The settings store's own restart fingerprints. */
|
|
8008
|
+
var RESTART_RETRY_DELAYS_MS = [
|
|
8009
|
+
150,
|
|
8010
|
+
350,
|
|
8011
|
+
600,
|
|
8012
|
+
900
|
|
8013
|
+
];
|
|
8014
|
+
/** A hub restarting under a booting runner: ~100 s in total. */
|
|
8015
|
+
var TRANSPORT_RETRY_DELAYS_MS = [
|
|
8016
|
+
150,
|
|
8017
|
+
350,
|
|
8018
|
+
600,
|
|
8019
|
+
900,
|
|
8020
|
+
2e3,
|
|
8021
|
+
5e3,
|
|
8022
|
+
1e4,
|
|
8023
|
+
2e4,
|
|
8024
|
+
3e4,
|
|
8025
|
+
3e4
|
|
8026
|
+
];
|
|
8027
|
+
var RESTART_FINGERPRINTS = ["SqliteSettingsBackend not initialized", "provider not available"];
|
|
8028
|
+
/** Node / socket error codes of a connection that did not happen or broke. */
|
|
8029
|
+
var TRANSPORT_CODES = new Set([
|
|
8030
|
+
"ECONNREFUSED",
|
|
8031
|
+
"ECONNRESET",
|
|
8032
|
+
"ETIMEDOUT",
|
|
8033
|
+
"EPIPE",
|
|
8034
|
+
"EHOSTUNREACH",
|
|
8035
|
+
"ENETUNREACH"
|
|
8036
|
+
]);
|
|
8037
|
+
/** tRPC error codes that mean "the other side is not answering now", not "your call is wrong". */
|
|
8038
|
+
var UNAVAILABLE_TRPC_CODES = new Set([
|
|
8039
|
+
"TIMEOUT",
|
|
8040
|
+
"SERVICE_UNAVAILABLE",
|
|
8041
|
+
"BAD_GATEWAY",
|
|
8042
|
+
"GATEWAY_TIMEOUT"
|
|
8043
|
+
]);
|
|
8044
|
+
/** The exact phrases OUR transport raises when it cannot reach the hub. */
|
|
8045
|
+
var TRANSPORT_PHRASES = [
|
|
8046
|
+
"discovery deadline exceeded",
|
|
8047
|
+
"parent could not route child unowned cap call",
|
|
8048
|
+
"UDS request timed out after",
|
|
8049
|
+
"channel closed"
|
|
8050
|
+
];
|
|
8051
|
+
/** Moleculer error `type`s of a call that could not be served right now. */
|
|
8052
|
+
var MOLECULER_TRANSIENT_TYPES = new Set([
|
|
8053
|
+
"REQUEST_TIMEOUT",
|
|
8054
|
+
"SERVICE_NOT_FOUND",
|
|
8055
|
+
"SERVICE_NOT_AVAILABLE",
|
|
8056
|
+
"REQUEST_REJECTED",
|
|
8057
|
+
"BROKER_DISCONNECTED"
|
|
8058
|
+
]);
|
|
8059
|
+
function stringProp(value, key) {
|
|
8060
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
8061
|
+
const found = Reflect.get(value, key);
|
|
8062
|
+
return typeof found === "string" ? found : void 0;
|
|
8063
|
+
}
|
|
8064
|
+
/** The code an error carries: its own, its cause's, or a tRPC `data.code`. */
|
|
8065
|
+
function errorCode(err) {
|
|
8066
|
+
const out = {};
|
|
8067
|
+
const cause = typeof err === "object" && err !== null ? Reflect.get(err, "cause") : void 0;
|
|
8068
|
+
const data = typeof err === "object" && err !== null ? Reflect.get(err, "data") : void 0;
|
|
8069
|
+
const node = stringProp(err, "code") ?? stringProp(cause, "code");
|
|
8070
|
+
if (node !== void 0) out.node = node;
|
|
8071
|
+
const trpc = stringProp(data, "code");
|
|
8072
|
+
if (trpc !== void 0) out.trpc = trpc;
|
|
8073
|
+
return out;
|
|
8074
|
+
}
|
|
8075
|
+
/**
|
|
8076
|
+
* Is a settings read failure worth retrying, and with which budget? Only
|
|
8077
|
+
* EXPLICIT signals count: a socket error code, a tRPC "unavailable" code, or
|
|
8078
|
+
* one of the exact phrases our own transport raises. A message that merely
|
|
8079
|
+
* contains "timed out" or "unreachable" is not evidence of anything, and
|
|
8080
|
+
* `settings store not wired` is a wiring bug that retrying cannot fix.
|
|
8081
|
+
*/
|
|
8082
|
+
function classifyStoreError(err) {
|
|
8083
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8084
|
+
if (RESTART_FINGERPRINTS.some((f) => message.includes(f))) return "restart";
|
|
8085
|
+
const code = errorCode(err);
|
|
8086
|
+
if (code.node !== void 0 && TRANSPORT_CODES.has(code.node)) return "transport";
|
|
8087
|
+
if (code.trpc !== void 0 && UNAVAILABLE_TRPC_CODES.has(code.trpc)) return "transport";
|
|
8088
|
+
if (typeof err === "object" && err !== null) {
|
|
8089
|
+
if (Reflect.get(err, "retryable") === true) return "transport";
|
|
8090
|
+
const type = stringProp(err, "type");
|
|
8091
|
+
if (type !== void 0 && MOLECULER_TRANSIENT_TYPES.has(type)) return "transport";
|
|
8092
|
+
}
|
|
8093
|
+
if (TRANSPORT_PHRASES.some((f) => message.includes(f))) return "transport";
|
|
8094
|
+
return "permanent";
|
|
8095
|
+
}
|
|
8004
8096
|
/**
|
|
8005
8097
|
* Collect the keys of every field marked `perNode: true`, recursing into
|
|
8006
8098
|
* layout containers (`group` fields and `sub-tabs` tabs) the same way
|
|
@@ -8636,7 +8728,7 @@ object({
|
|
|
8636
8728
|
params: record(string(), union([string(), number()])).optional()
|
|
8637
8729
|
});
|
|
8638
8730
|
//#endregion
|
|
8639
|
-
//#region ../types/dist/err-msg
|
|
8731
|
+
//#region ../types/dist/err-msg--2RrYiLO.mjs
|
|
8640
8732
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
8641
8733
|
DeviceType["Camera"] = "camera";
|
|
8642
8734
|
DeviceType["Hub"] = "hub";
|
|
@@ -8905,6 +8997,9 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
8905
8997
|
/** Virtual HA toggle (input_boolean.*) — distinguishable from a
|
|
8906
8998
|
* real Switch device for UI rendering / export adapters. */
|
|
8907
8999
|
DeviceRole["BinaryHelper"] = "binary-helper";
|
|
9000
|
+
/** A smart plug: a `switch` whose source says it is an outlet (HA
|
|
9001
|
+
* `device_class: outlet`). The Alexa export shows it as a SMARTPLUG. */
|
|
9002
|
+
DeviceRole["Outlet"] = "outlet";
|
|
8908
9003
|
/** Generic motion / occupancy / moving event source. Distinct from
|
|
8909
9004
|
* the camera accessory PirSensor role: that one is a camera child;
|
|
8910
9005
|
* this is a standalone HA / 3rd-party motion sensor. */
|
|
@@ -8972,7 +9067,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
8972
9067
|
return DeviceRole;
|
|
8973
9068
|
}({});
|
|
8974
9069
|
//#endregion
|
|
8975
|
-
//#region ../types/dist/composition-
|
|
9070
|
+
//#region ../types/dist/composition-DOwQB_Ua.mjs
|
|
8976
9071
|
/**
|
|
8977
9072
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
8978
9073
|
*
|
|
@@ -16478,6 +16573,28 @@ id: union([string(), number()]) }), {
|
|
|
16478
16573
|
kind: "mutation",
|
|
16479
16574
|
auth: "admin"
|
|
16480
16575
|
});
|
|
16576
|
+
/** One table of the settings database. */
|
|
16577
|
+
var StorageTableSchema = object({
|
|
16578
|
+
/** The table's full name, e.g. `recorder:addon-settings` or `addon-device-settings`. */
|
|
16579
|
+
name: string(),
|
|
16580
|
+
/** The owner prefix of a scoped name (`recorder` for `recorder:addon-settings`), else null. */
|
|
16581
|
+
owner: string().nullable(),
|
|
16582
|
+
rows: number().int().nonnegative(),
|
|
16583
|
+
/** Bytes the table's pages occupy (`dbstat`); null when the engine cannot measure. */
|
|
16584
|
+
bytes: number().int().nonnegative().nullable(),
|
|
16585
|
+
/** Declared by an addon since this engine process started (a running addon claims it). */
|
|
16586
|
+
declaredThisBoot: boolean()
|
|
16587
|
+
});
|
|
16588
|
+
method(object({ ownerPrefix: string().min(1).optional() }), object({ tables: array(StorageTableSchema) }), { auth: "admin" }), method(object({
|
|
16589
|
+
collection: string().min(1),
|
|
16590
|
+
expectRows: number().int().nonnegative()
|
|
16591
|
+
}), object({
|
|
16592
|
+
dropped: literal(true),
|
|
16593
|
+
rows: number().int().nonnegative()
|
|
16594
|
+
}), {
|
|
16595
|
+
kind: "mutation",
|
|
16596
|
+
auth: "admin"
|
|
16597
|
+
});
|
|
16481
16598
|
/**
|
|
16482
16599
|
* `keychain` — the hub's encrypted store of secret values (D787).
|
|
16483
16600
|
*
|
|
@@ -17019,6 +17136,16 @@ method(object({}), KeychainStatusSchema, { auth: "admin" }), method(object({}),
|
|
|
17019
17136
|
kind: "mutation",
|
|
17020
17137
|
auth: "admin",
|
|
17021
17138
|
caller: "required"
|
|
17139
|
+
}), method(object({
|
|
17140
|
+
ref: string().min(1),
|
|
17141
|
+
value: string().min(1)
|
|
17142
|
+
}), object({
|
|
17143
|
+
ref: string(),
|
|
17144
|
+
version: number().int()
|
|
17145
|
+
}), {
|
|
17146
|
+
kind: "mutation",
|
|
17147
|
+
auth: "admin",
|
|
17148
|
+
caller: "required"
|
|
17022
17149
|
}), method(object({ refs: array(string().min(1)).max(1e3) }), object({
|
|
17023
17150
|
deleted: array(string()).readonly(),
|
|
17024
17151
|
kept: array(object({
|
|
@@ -53470,6 +53597,12 @@ object({
|
|
|
53470
53597
|
/** Horizontal louver swing on/off. Null when the device has no
|
|
53471
53598
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
53472
53599
|
swingHorizontal: boolean().nullable(),
|
|
53600
|
+
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
53601
|
+
minTemp: number().nullable().optional(),
|
|
53602
|
+
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
53603
|
+
maxTemp: number().nullable().optional(),
|
|
53604
|
+
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
53605
|
+
tempStep: number().positive().nullable().optional(),
|
|
53473
53606
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
53474
53607
|
lastFetchedAt: number()
|
|
53475
53608
|
});
|
|
@@ -64475,6 +64608,12 @@ Object.freeze({
|
|
|
64475
64608
|
addonId: null,
|
|
64476
64609
|
access: "create"
|
|
64477
64610
|
},
|
|
64611
|
+
"keychainAdmin.importSecret": {
|
|
64612
|
+
capName: "keychain-admin",
|
|
64613
|
+
capScope: "system",
|
|
64614
|
+
addonId: null,
|
|
64615
|
+
access: "create"
|
|
64616
|
+
},
|
|
64478
64617
|
"keychainAdmin.listAudit": {
|
|
64479
64618
|
capName: "keychain-admin",
|
|
64480
64619
|
capScope: "system",
|
|
@@ -68261,6 +68400,18 @@ Object.freeze({
|
|
|
68261
68400
|
addonId: null,
|
|
68262
68401
|
access: "create"
|
|
68263
68402
|
},
|
|
68403
|
+
"storageAdmin.dropCollection": {
|
|
68404
|
+
capName: "storage-admin",
|
|
68405
|
+
capScope: "system",
|
|
68406
|
+
addonId: null,
|
|
68407
|
+
access: "delete"
|
|
68408
|
+
},
|
|
68409
|
+
"storageAdmin.listTables": {
|
|
68410
|
+
capName: "storage-admin",
|
|
68411
|
+
capScope: "system",
|
|
68412
|
+
addonId: null,
|
|
68413
|
+
access: "view"
|
|
68414
|
+
},
|
|
68264
68415
|
"storageEvictable.evict": {
|
|
68265
68416
|
capName: "storage-evictable",
|
|
68266
68417
|
capScope: "system",
|
|
@@ -5756,7 +5756,7 @@ var ZodIssueCode = {
|
|
|
5756
5756
|
var ZodFirstPartyTypeKind;
|
|
5757
5757
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5758
5758
|
//#endregion
|
|
5759
|
-
//#region ../types/dist/sleep-
|
|
5759
|
+
//#region ../types/dist/sleep-bwsTj221.mjs
|
|
5760
5760
|
/**
|
|
5761
5761
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5762
5762
|
* window to float samples (D455).
|
|
@@ -7007,7 +7007,6 @@ function createHandle(raw, opts) {
|
|
|
7007
7007
|
const writeAddon = (patch) => write("addon", opts.addonTree(), void 0, patch, () => readStoredAddonBlob(raw), (p) => raw.writeAddonStore(p));
|
|
7008
7008
|
const readAddonStoreResult = raw.readAddonStoreResult;
|
|
7009
7009
|
const readAddonStoreKeyResult = raw.readAddonStoreKeyResult;
|
|
7010
|
-
const readDeviceStoreBatch = raw.readDeviceStoreBatch;
|
|
7011
7010
|
const overrides = {
|
|
7012
7011
|
readAddonStore: async () => resolveRead("addon", await raw.readAddonStore()),
|
|
7013
7012
|
...readAddonStoreResult !== void 0 ? { readAddonStoreResult: async () => {
|
|
@@ -7031,12 +7030,12 @@ function createHandle(raw, opts) {
|
|
|
7031
7030
|
};
|
|
7032
7031
|
} } : {},
|
|
7033
7032
|
readDeviceStore: async (deviceId) => resolveRead(`device:${deviceId}`, await raw.readDeviceStore(deviceId)),
|
|
7034
|
-
|
|
7035
|
-
const rows = await readDeviceStoreBatch
|
|
7033
|
+
readDeviceStoreBatch: async (deviceIds) => {
|
|
7034
|
+
const rows = await raw.readDeviceStoreBatch(deviceIds);
|
|
7036
7035
|
const out = /* @__PURE__ */ new Map();
|
|
7037
7036
|
for (const [deviceId, blob] of rows) out.set(deviceId, await resolveRead(`device:${deviceId}`, blob));
|
|
7038
7037
|
return out;
|
|
7039
|
-
}
|
|
7038
|
+
},
|
|
7040
7039
|
writeAddonStore: async (patch) => {
|
|
7041
7040
|
await writeAddon(patch);
|
|
7042
7041
|
},
|
|
@@ -7863,7 +7862,7 @@ var BaseAddon = class {
|
|
|
7863
7862
|
return this._addonSecretTree;
|
|
7864
7863
|
}
|
|
7865
7864
|
deviceSecretTree() {
|
|
7866
|
-
this._deviceSecretTree ??= secretTreeFromSchema(this.deviceSettingsSchema());
|
|
7865
|
+
this._deviceSecretTree ??= mergeSecretStatePaths(secretTreeFromSchema(this.deviceSettingsSchema()), this.secretStatePaths);
|
|
7867
7866
|
return this._deviceSecretTree;
|
|
7868
7867
|
}
|
|
7869
7868
|
/**
|
|
@@ -7939,42 +7938,135 @@ var BaseAddon = class {
|
|
|
7939
7938
|
this[timerOf] = timer;
|
|
7940
7939
|
}
|
|
7941
7940
|
/**
|
|
7942
|
-
* Wrap `ctx.settings.readAddonStore()` with a
|
|
7943
|
-
*
|
|
7944
|
-
* swap, or any race where the SqliteSettingsBackend is between shutdown and
|
|
7945
|
-
* re-initialize) doesn't propagate up into `initialize()` and leave the
|
|
7941
|
+
* Wrap `ctx.settings.readAddonStore()` with a retry budget so a transient
|
|
7942
|
+
* settings-store outage doesn't propagate up into `initialize()` and leave the
|
|
7946
7943
|
* addon permanently broken.
|
|
7947
7944
|
*
|
|
7948
|
-
*
|
|
7949
|
-
*
|
|
7950
|
-
* `
|
|
7945
|
+
* Two kinds of outage, two budgets:
|
|
7946
|
+
* - the store's own restart fingerprints (`SqliteSettingsBackend not
|
|
7947
|
+
* initialized`, `provider not available`): a short budget, then the addon
|
|
7948
|
+
* falls back to `{}` (defaults) - its first successful patch rehydrates;
|
|
7949
|
+
* - a TRANSPORT failure (the hub is restarting while this runner boots:
|
|
7950
|
+
* `discovery deadline exceeded`, `parent could not route`, a refused or
|
|
7951
|
+
* timed-out connection). Since D870 a runner's settings read THROWS instead
|
|
7952
|
+
* of answering `{}`, so without a budget a hub restart ends in a respawn
|
|
7953
|
+
* loop. A long, bounded budget; only after it the error propagates - the
|
|
7954
|
+
* addon never runs on defaults for a store it could not ask.
|
|
7955
|
+
* Anything else propagates immediately so real bugs surface.
|
|
7951
7956
|
*/
|
|
7952
7957
|
async readAddonStoreWithRetry() {
|
|
7953
7958
|
const settings = this.rawSettings();
|
|
7954
7959
|
if (!settings) return {};
|
|
7955
|
-
const delaysMs = [
|
|
7956
|
-
150,
|
|
7957
|
-
350,
|
|
7958
|
-
600,
|
|
7959
|
-
900
|
|
7960
|
-
];
|
|
7961
7960
|
let lastErr;
|
|
7962
|
-
for (let attempt = 0
|
|
7961
|
+
for (let attempt = 0;; attempt++) try {
|
|
7963
7962
|
const stored = await settings.readAddonStore() ?? {};
|
|
7964
7963
|
this.settingsStoreReady = true;
|
|
7965
7964
|
return stored;
|
|
7966
7965
|
} catch (err) {
|
|
7967
7966
|
lastErr = err;
|
|
7968
|
-
const
|
|
7969
|
-
if (
|
|
7970
|
-
|
|
7971
|
-
|
|
7967
|
+
const kind = classifyStoreError(err);
|
|
7968
|
+
if (kind === "permanent") throw err;
|
|
7969
|
+
const delay = (kind === "transport" ? TRANSPORT_RETRY_DELAYS_MS : RESTART_RETRY_DELAYS_MS)[attempt];
|
|
7970
|
+
if (delay === void 0) {
|
|
7971
|
+
if (kind === "transport") throw err;
|
|
7972
|
+
break;
|
|
7973
|
+
}
|
|
7974
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
7972
7975
|
}
|
|
7973
7976
|
this.settingsStoreReady = false;
|
|
7974
7977
|
this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
|
|
7975
7978
|
return {};
|
|
7976
7979
|
}
|
|
7977
7980
|
};
|
|
7981
|
+
/** The settings store's own restart fingerprints. */
|
|
7982
|
+
var RESTART_RETRY_DELAYS_MS = [
|
|
7983
|
+
150,
|
|
7984
|
+
350,
|
|
7985
|
+
600,
|
|
7986
|
+
900
|
|
7987
|
+
];
|
|
7988
|
+
/** A hub restarting under a booting runner: ~100 s in total. */
|
|
7989
|
+
var TRANSPORT_RETRY_DELAYS_MS = [
|
|
7990
|
+
150,
|
|
7991
|
+
350,
|
|
7992
|
+
600,
|
|
7993
|
+
900,
|
|
7994
|
+
2e3,
|
|
7995
|
+
5e3,
|
|
7996
|
+
1e4,
|
|
7997
|
+
2e4,
|
|
7998
|
+
3e4,
|
|
7999
|
+
3e4
|
|
8000
|
+
];
|
|
8001
|
+
var RESTART_FINGERPRINTS = ["SqliteSettingsBackend not initialized", "provider not available"];
|
|
8002
|
+
/** Node / socket error codes of a connection that did not happen or broke. */
|
|
8003
|
+
var TRANSPORT_CODES = new Set([
|
|
8004
|
+
"ECONNREFUSED",
|
|
8005
|
+
"ECONNRESET",
|
|
8006
|
+
"ETIMEDOUT",
|
|
8007
|
+
"EPIPE",
|
|
8008
|
+
"EHOSTUNREACH",
|
|
8009
|
+
"ENETUNREACH"
|
|
8010
|
+
]);
|
|
8011
|
+
/** tRPC error codes that mean "the other side is not answering now", not "your call is wrong". */
|
|
8012
|
+
var UNAVAILABLE_TRPC_CODES = new Set([
|
|
8013
|
+
"TIMEOUT",
|
|
8014
|
+
"SERVICE_UNAVAILABLE",
|
|
8015
|
+
"BAD_GATEWAY",
|
|
8016
|
+
"GATEWAY_TIMEOUT"
|
|
8017
|
+
]);
|
|
8018
|
+
/** The exact phrases OUR transport raises when it cannot reach the hub. */
|
|
8019
|
+
var TRANSPORT_PHRASES = [
|
|
8020
|
+
"discovery deadline exceeded",
|
|
8021
|
+
"parent could not route child unowned cap call",
|
|
8022
|
+
"UDS request timed out after",
|
|
8023
|
+
"channel closed"
|
|
8024
|
+
];
|
|
8025
|
+
/** Moleculer error `type`s of a call that could not be served right now. */
|
|
8026
|
+
var MOLECULER_TRANSIENT_TYPES = new Set([
|
|
8027
|
+
"REQUEST_TIMEOUT",
|
|
8028
|
+
"SERVICE_NOT_FOUND",
|
|
8029
|
+
"SERVICE_NOT_AVAILABLE",
|
|
8030
|
+
"REQUEST_REJECTED",
|
|
8031
|
+
"BROKER_DISCONNECTED"
|
|
8032
|
+
]);
|
|
8033
|
+
function stringProp(value, key) {
|
|
8034
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
8035
|
+
const found = Reflect.get(value, key);
|
|
8036
|
+
return typeof found === "string" ? found : void 0;
|
|
8037
|
+
}
|
|
8038
|
+
/** The code an error carries: its own, its cause's, or a tRPC `data.code`. */
|
|
8039
|
+
function errorCode(err) {
|
|
8040
|
+
const out = {};
|
|
8041
|
+
const cause = typeof err === "object" && err !== null ? Reflect.get(err, "cause") : void 0;
|
|
8042
|
+
const data = typeof err === "object" && err !== null ? Reflect.get(err, "data") : void 0;
|
|
8043
|
+
const node = stringProp(err, "code") ?? stringProp(cause, "code");
|
|
8044
|
+
if (node !== void 0) out.node = node;
|
|
8045
|
+
const trpc = stringProp(data, "code");
|
|
8046
|
+
if (trpc !== void 0) out.trpc = trpc;
|
|
8047
|
+
return out;
|
|
8048
|
+
}
|
|
8049
|
+
/**
|
|
8050
|
+
* Is a settings read failure worth retrying, and with which budget? Only
|
|
8051
|
+
* EXPLICIT signals count: a socket error code, a tRPC "unavailable" code, or
|
|
8052
|
+
* one of the exact phrases our own transport raises. A message that merely
|
|
8053
|
+
* contains "timed out" or "unreachable" is not evidence of anything, and
|
|
8054
|
+
* `settings store not wired` is a wiring bug that retrying cannot fix.
|
|
8055
|
+
*/
|
|
8056
|
+
function classifyStoreError(err) {
|
|
8057
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8058
|
+
if (RESTART_FINGERPRINTS.some((f) => message.includes(f))) return "restart";
|
|
8059
|
+
const code = errorCode(err);
|
|
8060
|
+
if (code.node !== void 0 && TRANSPORT_CODES.has(code.node)) return "transport";
|
|
8061
|
+
if (code.trpc !== void 0 && UNAVAILABLE_TRPC_CODES.has(code.trpc)) return "transport";
|
|
8062
|
+
if (typeof err === "object" && err !== null) {
|
|
8063
|
+
if (Reflect.get(err, "retryable") === true) return "transport";
|
|
8064
|
+
const type = stringProp(err, "type");
|
|
8065
|
+
if (type !== void 0 && MOLECULER_TRANSIENT_TYPES.has(type)) return "transport";
|
|
8066
|
+
}
|
|
8067
|
+
if (TRANSPORT_PHRASES.some((f) => message.includes(f))) return "transport";
|
|
8068
|
+
return "permanent";
|
|
8069
|
+
}
|
|
7978
8070
|
/**
|
|
7979
8071
|
* Collect the keys of every field marked `perNode: true`, recursing into
|
|
7980
8072
|
* layout containers (`group` fields and `sub-tabs` tabs) the same way
|
|
@@ -8610,7 +8702,7 @@ object({
|
|
|
8610
8702
|
params: record(string(), union([string(), number()])).optional()
|
|
8611
8703
|
});
|
|
8612
8704
|
//#endregion
|
|
8613
|
-
//#region ../types/dist/err-msg
|
|
8705
|
+
//#region ../types/dist/err-msg--2RrYiLO.mjs
|
|
8614
8706
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
8615
8707
|
DeviceType["Camera"] = "camera";
|
|
8616
8708
|
DeviceType["Hub"] = "hub";
|
|
@@ -8879,6 +8971,9 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
8879
8971
|
/** Virtual HA toggle (input_boolean.*) — distinguishable from a
|
|
8880
8972
|
* real Switch device for UI rendering / export adapters. */
|
|
8881
8973
|
DeviceRole["BinaryHelper"] = "binary-helper";
|
|
8974
|
+
/** A smart plug: a `switch` whose source says it is an outlet (HA
|
|
8975
|
+
* `device_class: outlet`). The Alexa export shows it as a SMARTPLUG. */
|
|
8976
|
+
DeviceRole["Outlet"] = "outlet";
|
|
8882
8977
|
/** Generic motion / occupancy / moving event source. Distinct from
|
|
8883
8978
|
* the camera accessory PirSensor role: that one is a camera child;
|
|
8884
8979
|
* this is a standalone HA / 3rd-party motion sensor. */
|
|
@@ -8946,7 +9041,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
8946
9041
|
return DeviceRole;
|
|
8947
9042
|
}({});
|
|
8948
9043
|
//#endregion
|
|
8949
|
-
//#region ../types/dist/composition-
|
|
9044
|
+
//#region ../types/dist/composition-DOwQB_Ua.mjs
|
|
8950
9045
|
/**
|
|
8951
9046
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
8952
9047
|
*
|
|
@@ -16452,6 +16547,28 @@ id: union([string(), number()]) }), {
|
|
|
16452
16547
|
kind: "mutation",
|
|
16453
16548
|
auth: "admin"
|
|
16454
16549
|
});
|
|
16550
|
+
/** One table of the settings database. */
|
|
16551
|
+
var StorageTableSchema = object({
|
|
16552
|
+
/** The table's full name, e.g. `recorder:addon-settings` or `addon-device-settings`. */
|
|
16553
|
+
name: string(),
|
|
16554
|
+
/** The owner prefix of a scoped name (`recorder` for `recorder:addon-settings`), else null. */
|
|
16555
|
+
owner: string().nullable(),
|
|
16556
|
+
rows: number().int().nonnegative(),
|
|
16557
|
+
/** Bytes the table's pages occupy (`dbstat`); null when the engine cannot measure. */
|
|
16558
|
+
bytes: number().int().nonnegative().nullable(),
|
|
16559
|
+
/** Declared by an addon since this engine process started (a running addon claims it). */
|
|
16560
|
+
declaredThisBoot: boolean()
|
|
16561
|
+
});
|
|
16562
|
+
method(object({ ownerPrefix: string().min(1).optional() }), object({ tables: array(StorageTableSchema) }), { auth: "admin" }), method(object({
|
|
16563
|
+
collection: string().min(1),
|
|
16564
|
+
expectRows: number().int().nonnegative()
|
|
16565
|
+
}), object({
|
|
16566
|
+
dropped: literal(true),
|
|
16567
|
+
rows: number().int().nonnegative()
|
|
16568
|
+
}), {
|
|
16569
|
+
kind: "mutation",
|
|
16570
|
+
auth: "admin"
|
|
16571
|
+
});
|
|
16455
16572
|
/**
|
|
16456
16573
|
* `keychain` — the hub's encrypted store of secret values (D787).
|
|
16457
16574
|
*
|
|
@@ -16993,6 +17110,16 @@ method(object({}), KeychainStatusSchema, { auth: "admin" }), method(object({}),
|
|
|
16993
17110
|
kind: "mutation",
|
|
16994
17111
|
auth: "admin",
|
|
16995
17112
|
caller: "required"
|
|
17113
|
+
}), method(object({
|
|
17114
|
+
ref: string().min(1),
|
|
17115
|
+
value: string().min(1)
|
|
17116
|
+
}), object({
|
|
17117
|
+
ref: string(),
|
|
17118
|
+
version: number().int()
|
|
17119
|
+
}), {
|
|
17120
|
+
kind: "mutation",
|
|
17121
|
+
auth: "admin",
|
|
17122
|
+
caller: "required"
|
|
16996
17123
|
}), method(object({ refs: array(string().min(1)).max(1e3) }), object({
|
|
16997
17124
|
deleted: array(string()).readonly(),
|
|
16998
17125
|
kept: array(object({
|
|
@@ -53444,6 +53571,12 @@ object({
|
|
|
53444
53571
|
/** Horizontal louver swing on/off. Null when the device has no
|
|
53445
53572
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
53446
53573
|
swingHorizontal: boolean().nullable(),
|
|
53574
|
+
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
53575
|
+
minTemp: number().nullable().optional(),
|
|
53576
|
+
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
53577
|
+
maxTemp: number().nullable().optional(),
|
|
53578
|
+
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
53579
|
+
tempStep: number().positive().nullable().optional(),
|
|
53447
53580
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
53448
53581
|
lastFetchedAt: number()
|
|
53449
53582
|
});
|
|
@@ -64449,6 +64582,12 @@ Object.freeze({
|
|
|
64449
64582
|
addonId: null,
|
|
64450
64583
|
access: "create"
|
|
64451
64584
|
},
|
|
64585
|
+
"keychainAdmin.importSecret": {
|
|
64586
|
+
capName: "keychain-admin",
|
|
64587
|
+
capScope: "system",
|
|
64588
|
+
addonId: null,
|
|
64589
|
+
access: "create"
|
|
64590
|
+
},
|
|
64452
64591
|
"keychainAdmin.listAudit": {
|
|
64453
64592
|
capName: "keychain-admin",
|
|
64454
64593
|
capScope: "system",
|
|
@@ -68235,6 +68374,18 @@ Object.freeze({
|
|
|
68235
68374
|
addonId: null,
|
|
68236
68375
|
access: "create"
|
|
68237
68376
|
},
|
|
68377
|
+
"storageAdmin.dropCollection": {
|
|
68378
|
+
capName: "storage-admin",
|
|
68379
|
+
capScope: "system",
|
|
68380
|
+
addonId: null,
|
|
68381
|
+
access: "delete"
|
|
68382
|
+
},
|
|
68383
|
+
"storageAdmin.listTables": {
|
|
68384
|
+
capName: "storage-admin",
|
|
68385
|
+
capScope: "system",
|
|
68386
|
+
addonId: null,
|
|
68387
|
+
access: "view"
|
|
68388
|
+
},
|
|
68238
68389
|
"storageEvictable.evict": {
|
|
68239
68390
|
capName: "storage-evictable",
|
|
68240
68391
|
capScope: "system",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { S as e, d as t, u as n, v as r } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare__react__loadShare__.js-DMBKVIH7.mjs";
|
|
2
2
|
import { n as i, r as a, t as o } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-ds_Ehzaa.mjs";
|
|
3
|
-
import { g as s, h as c } from "./responsive-
|
|
3
|
+
import { g as s, h as c } from "./responsive-Bb8t1Rws.mjs";
|
|
4
4
|
var l = s("chevron-down", [["path", {
|
|
5
5
|
d: "m6 9 6 6 6-6",
|
|
6
6
|
key: "qrunsl"
|
package/dist/remoteEntry.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as e, t } from "./virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-
|
|
1
|
+
import { n as e, t } from "./virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-LnfkvJQ6.mjs";
|
|
2
2
|
export { t as get, e as init };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { S as e, d as t, g as n, i as r, l as i, n as a, r as o, u as s, v as c, y as l } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare__react__loadShare__.js-DMBKVIH7.mjs";
|
|
2
2
|
import "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-ds_Ehzaa.mjs";
|
|
3
|
-
import { h as u } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-
|
|
3
|
+
import { h as u } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B0F3F6BP.mjs";
|
|
4
4
|
//#region ../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
|
|
5
5
|
e();
|
|
6
6
|
var d = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) === t).join(" ").trim(), f = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), p = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), m = (e) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { S as e, g as t, l as n, v as r } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare__react__loadShare__.js-DMBKVIH7.mjs";
|
|
2
2
|
import { n as i } from "./ui-text-BqZa5BNK.mjs";
|
|
3
|
-
import { g as a } from "./responsive-
|
|
3
|
+
import { g as a } from "./responsive-Bb8t1Rws.mjs";
|
|
4
4
|
var o = a("camera", [["path", {
|
|
5
5
|
d: "M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z",
|
|
6
6
|
key: "18u6gg"
|