@camstack/addon-pipeline 1.2.369 → 1.2.371
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/audio-analyzer/index.js +3 -3
- package/dist/audio-analyzer/index.mjs +3 -3
- package/dist/{custom-model-catalog-uHzR2xWY.mjs → custom-model-catalog-C6C2cSwd.mjs} +2 -2
- package/dist/{custom-model-catalog-C3PYjN8c.js → custom-model-catalog-n9v8MUL6.js} +2 -2
- package/dist/detection-pipeline/index.js +4 -4
- package/dist/detection-pipeline/index.mjs +4 -4
- package/dist/{dist-DKSwif2M.mjs → dist-8AEiKOFO.mjs} +386 -30
- package/dist/{dist-D3PtiAhd.js → dist-DmuX7IFJ.js} +403 -29
- package/dist/{model-catalogs-CVd4TcTQ.mjs → model-catalogs-BSWAHZJh.mjs} +1 -1
- package/dist/{model-catalogs-kGqNkIuV.js → model-catalogs-DO4aA1qo.js} +1 -1
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-C_Fqti3A.mjs → node-Bd4va7c-.mjs} +1 -1
- package/dist/{node--15m1sN3.js → node-DqA6nD1z.js} +1 -1
- package/dist/pipeline-runner/index.js +3 -3
- package/dist/pipeline-runner/index.mjs +3 -3
- package/dist/{process-memory-DELcKfDf.js → process-memory-2OQ2oxrz.js} +1 -1
- package/dist/{process-memory-Dq_Omilr.mjs → process-memory-BvS2Z88w.mjs} +1 -1
- package/dist/recorder/index.js +184 -54
- package/dist/recorder/index.mjs +184 -54
- package/dist/{segment-demux-js-DSYbEqvj.js → segment-demux-js-BkGK1rhu.js} +1 -1
- package/dist/{segment-demux-js-BTUbXt7b.mjs → segment-demux-js-By9MLn_g.mjs} +1 -1
- package/dist/stream-broker/_stub.js +1188 -861
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CMHYV8dG.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DjoAY42S.mjs} +3 -3
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-C3ssSNKh.mjs +26 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-nua-KuDg.mjs +26 -0
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-Cz1kTtGe.mjs → hostInit-DPiGNc5u.mjs} +3 -3
- package/dist/stream-broker/index.js +302 -90
- package/dist/stream-broker/index.mjs +302 -90
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/i18n/en.json +8 -0
- package/i18n/it.json +8 -0
- package/package.json +6 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DBku2n1V.mjs +0 -26
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DNC4tvrD.mjs +0 -26
|
@@ -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-DRqxtc0C.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).
|
|
@@ -5536,7 +5536,7 @@ function isKeychainStoredField(field) {
|
|
|
5536
5536
|
var SECRET_CLEAR = { $secretClear: true };
|
|
5537
5537
|
/** The `'***'` token D634 redaction writes for non-admins. */
|
|
5538
5538
|
var LEGACY_DEVICE_REDACTION = "***";
|
|
5539
|
-
function isRecord$2(value) {
|
|
5539
|
+
function isRecord$2$1(value) {
|
|
5540
5540
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5541
5541
|
}
|
|
5542
5542
|
function makeSecretMarker(ref) {
|
|
@@ -5547,12 +5547,12 @@ function makeSecretMarker(ref) {
|
|
|
5547
5547
|
}
|
|
5548
5548
|
/** A stored marker: an object whose `$secret` is a non-empty string. */
|
|
5549
5549
|
function isSecretMarker(value) {
|
|
5550
|
-
if (!isRecord$2(value)) return false;
|
|
5550
|
+
if (!isRecord$2$1(value)) return false;
|
|
5551
5551
|
const ref = value["$secret"];
|
|
5552
5552
|
return typeof ref === "string" && ref.length > 0;
|
|
5553
5553
|
}
|
|
5554
5554
|
function isSecretClear(value) {
|
|
5555
|
-
return isRecord$2(value) && value["$secretClear"] === true;
|
|
5555
|
+
return isRecord$2$1(value) && value["$secretClear"] === true;
|
|
5556
5556
|
}
|
|
5557
5557
|
/**
|
|
5558
5558
|
* The UI view of a stored secret field value: a marker becomes "set", inline
|
|
@@ -6178,7 +6178,7 @@ var KeychainWriteRefusedError = class extends Error {
|
|
|
6178
6178
|
}
|
|
6179
6179
|
};
|
|
6180
6180
|
var KEEP = { kind: "keep" };
|
|
6181
|
-
function isRecord$1
|
|
6181
|
+
function isRecord$1(value) {
|
|
6182
6182
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6183
6183
|
}
|
|
6184
6184
|
function defaultMintId() {
|
|
@@ -6191,7 +6191,7 @@ function collectSecretMarkerRefs(value, out = []) {
|
|
|
6191
6191
|
return out;
|
|
6192
6192
|
}
|
|
6193
6193
|
if (Array.isArray(value)) for (const item of value) collectSecretMarkerRefs(item, out);
|
|
6194
|
-
else if (isRecord$1
|
|
6194
|
+
else if (isRecord$1(value)) for (const child of Object.values(value)) collectSecretMarkerRefs(child, out);
|
|
6195
6195
|
return out;
|
|
6196
6196
|
}
|
|
6197
6197
|
async function storedValueEquals(secrets, marker, candidate) {
|
|
@@ -6246,7 +6246,7 @@ function rowId(row, idKey) {
|
|
|
6246
6246
|
return null;
|
|
6247
6247
|
}
|
|
6248
6248
|
async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
6249
|
-
const storedRows = Array.isArray(stored) ? stored.filter(isRecord$1
|
|
6249
|
+
const storedRows = Array.isArray(stored) ? stored.filter(isRecord$1) : [];
|
|
6250
6250
|
if (!Array.isArray(incoming)) {
|
|
6251
6251
|
ctx.deletes.push(...collectSecretMarkerRefs(storedRows));
|
|
6252
6252
|
return {
|
|
@@ -6262,7 +6262,7 @@ async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
|
6262
6262
|
const kept = /* @__PURE__ */ new Set();
|
|
6263
6263
|
const rows = [];
|
|
6264
6264
|
for (const row of incoming) {
|
|
6265
|
-
if (!isRecord$1
|
|
6265
|
+
if (!isRecord$1(row)) {
|
|
6266
6266
|
rows.push(row);
|
|
6267
6267
|
continue;
|
|
6268
6268
|
}
|
|
@@ -6287,7 +6287,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
|
|
|
6287
6287
|
case "leaf": return writeLeaf(ctx, incoming, stored, fieldPath);
|
|
6288
6288
|
case "array": return writeArray(ctx, node, incoming, stored, fieldPath);
|
|
6289
6289
|
case "object": {
|
|
6290
|
-
if (!isRecord$1
|
|
6290
|
+
if (!isRecord$1(incoming)) {
|
|
6291
6291
|
if (incoming === void 0) return KEEP;
|
|
6292
6292
|
ctx.deletes.push(...collectSecretMarkerRefs(stored));
|
|
6293
6293
|
return {
|
|
@@ -6295,7 +6295,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
|
|
|
6295
6295
|
value: incoming
|
|
6296
6296
|
};
|
|
6297
6297
|
}
|
|
6298
|
-
const storedObj = isRecord$1
|
|
6298
|
+
const storedObj = isRecord$1(stored) ? stored : {};
|
|
6299
6299
|
return {
|
|
6300
6300
|
kind: "value",
|
|
6301
6301
|
value: await writeMembers(ctx, node.children, incoming, storedObj, (m) => `${fieldPath}.${m}`)
|
|
@@ -6418,7 +6418,7 @@ async function resolveSecretMarkers(value, secrets, options = {}) {
|
|
|
6418
6418
|
value: items
|
|
6419
6419
|
};
|
|
6420
6420
|
}
|
|
6421
|
-
if (isRecord$1
|
|
6421
|
+
if (isRecord$1(v)) {
|
|
6422
6422
|
const out = {};
|
|
6423
6423
|
for (const [k, child] of Object.entries(v)) {
|
|
6424
6424
|
const s = substitute(child);
|
|
@@ -8354,6 +8354,24 @@ method(object({ deviceId: number() }), array(StreamSourceEntrySchema)), method(o
|
|
|
8354
8354
|
}), method(object({ deviceId: number() }), unknown().nullable()), method(object({ deviceId: number() }), RawStateResultSchema.nullable(), { auth: "protected" });
|
|
8355
8355
|
var HF_REPO = "camstack/camstack-models";
|
|
8356
8356
|
`${HF_REPO}`;
|
|
8357
|
+
object({
|
|
8358
|
+
code: string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/),
|
|
8359
|
+
params: record(string(), union([string(), number()])).optional()
|
|
8360
|
+
});
|
|
8361
|
+
var CamstackError = class extends Error {
|
|
8362
|
+
i18nCode;
|
|
8363
|
+
i18nParams;
|
|
8364
|
+
constructor(code, params, englishMessage) {
|
|
8365
|
+
super(englishMessage);
|
|
8366
|
+
this.name = "CamstackError";
|
|
8367
|
+
this.i18nCode = code;
|
|
8368
|
+
this.i18nParams = params;
|
|
8369
|
+
}
|
|
8370
|
+
};
|
|
8371
|
+
/** `throw userError('device.not-found', { id }, 'Device 12 not found')` */
|
|
8372
|
+
function userError(code, params, englishFallback) {
|
|
8373
|
+
return new CamstackError(code, params, englishFallback);
|
|
8374
|
+
}
|
|
8357
8375
|
/**
|
|
8358
8376
|
* The ONE retry schedule for work that can fail simply because the node was
|
|
8359
8377
|
* still booting.
|
|
@@ -8421,6 +8439,8 @@ var CREDENTIAL_PARAM_PATTERNS = [
|
|
|
8421
8439
|
/^code$/i,
|
|
8422
8440
|
/^state$/i,
|
|
8423
8441
|
/^challenge$/i,
|
|
8442
|
+
/^code[_-]?challenge$/i,
|
|
8443
|
+
/^confirm$/i,
|
|
8424
8444
|
/^link$/i
|
|
8425
8445
|
];
|
|
8426
8446
|
function isCredentialParam(name) {
|
|
@@ -8489,7 +8509,7 @@ function sleep(ms) {
|
|
|
8489
8509
|
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
8490
8510
|
}
|
|
8491
8511
|
//#endregion
|
|
8492
|
-
//#region ../types/dist/err-msg-
|
|
8512
|
+
//#region ../types/dist/err-msg-DLerKiVO.mjs
|
|
8493
8513
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
8494
8514
|
DeviceType["Camera"] = "camera";
|
|
8495
8515
|
DeviceType["Hub"] = "hub";
|
|
@@ -8739,6 +8759,22 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
8739
8759
|
DeviceRole["Nightvision"] = "nightvision";
|
|
8740
8760
|
DeviceRole["PrivacyMask"] = "privacy-mask";
|
|
8741
8761
|
DeviceRole["Doorbell"] = "doorbell";
|
|
8762
|
+
/** Interior blind / shade / roller blind. HA `device_class: blind|shade`. */
|
|
8763
|
+
DeviceRole["CoverBlind"] = "cover-blind";
|
|
8764
|
+
/** Exterior roller shutter. HA `device_class: shutter`; Homematic BROLL. */
|
|
8765
|
+
DeviceRole["CoverShutter"] = "cover-shutter";
|
|
8766
|
+
/** Exterior awning. HA `device_class: awning`. */
|
|
8767
|
+
DeviceRole["CoverAwning"] = "cover-awning";
|
|
8768
|
+
/** Curtain / drape. HA `device_class: curtain`. */
|
|
8769
|
+
DeviceRole["CoverCurtain"] = "cover-curtain";
|
|
8770
|
+
/** Garage door. HA `device_class: garage`. A security actuator: exports gate it. */
|
|
8771
|
+
DeviceRole["CoverGarage"] = "cover-garage";
|
|
8772
|
+
/** Gate. HA `device_class: gate`. A security actuator: exports gate it. */
|
|
8773
|
+
DeviceRole["CoverGate"] = "cover-gate";
|
|
8774
|
+
/** Door. HA `device_class: door`. A security actuator: exports gate it. */
|
|
8775
|
+
DeviceRole["CoverDoor"] = "cover-door";
|
|
8776
|
+
/** Window. HA `device_class: window`. */
|
|
8777
|
+
DeviceRole["CoverWindow"] = "cover-window";
|
|
8742
8778
|
/** Virtual HA toggle (input_boolean.*) — distinguishable from a
|
|
8743
8779
|
* real Switch device for UI rendering / export adapters. */
|
|
8744
8780
|
DeviceRole["BinaryHelper"] = "binary-helper";
|
|
@@ -8819,7 +8855,7 @@ function errMsg(err) {
|
|
|
8819
8855
|
return String(err);
|
|
8820
8856
|
}
|
|
8821
8857
|
//#endregion
|
|
8822
|
-
//#region ../types/dist/composition-
|
|
8858
|
+
//#region ../types/dist/composition-EQ9Ok0Ee.mjs
|
|
8823
8859
|
var AUDIO_ENCODER_BY_CODEC = {
|
|
8824
8860
|
opus: "libopus",
|
|
8825
8861
|
aac: "aac",
|
|
@@ -12377,20 +12413,20 @@ var SURVIVING_TRIGGER_KEYS = [
|
|
|
12377
12413
|
"objectClasses",
|
|
12378
12414
|
"sensorDeviceIds"
|
|
12379
12415
|
];
|
|
12380
|
-
function isRecord$
|
|
12416
|
+
function isRecord$2(value) {
|
|
12381
12417
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12382
12418
|
}
|
|
12383
12419
|
function listensToLegacySignal(band) {
|
|
12384
|
-
return isRecord$
|
|
12420
|
+
return isRecord$2(band) && isRecord$2(band.triggers) && band.triggers.deviceSignal === true;
|
|
12385
12421
|
}
|
|
12386
12422
|
function hasSurvivingTrigger(band) {
|
|
12387
12423
|
const triggers = band.triggers;
|
|
12388
|
-
if (!isRecord$
|
|
12424
|
+
if (!isRecord$2(triggers)) return false;
|
|
12389
12425
|
return SURVIVING_TRIGGER_KEYS.some((key) => triggers[key] !== void 0);
|
|
12390
12426
|
}
|
|
12391
12427
|
function withoutLegacySignal(band) {
|
|
12392
12428
|
const triggers = band.triggers;
|
|
12393
|
-
if (!isRecord$
|
|
12429
|
+
if (!isRecord$2(triggers)) return band;
|
|
12394
12430
|
const { deviceSignal: _retired, ...rest } = triggers;
|
|
12395
12431
|
return {
|
|
12396
12432
|
...band,
|
|
@@ -12420,11 +12456,11 @@ function migrateLegacyDeviceSignalConfig(raw) {
|
|
|
12420
12456
|
migrated: false,
|
|
12421
12457
|
strippedOnly: false
|
|
12422
12458
|
};
|
|
12423
|
-
if (!isRecord$
|
|
12459
|
+
if (!isRecord$2(raw) || !Array.isArray(raw.bands)) return unchanged;
|
|
12424
12460
|
if (!raw.bands.some(listensToLegacySignal)) return unchanged;
|
|
12425
12461
|
const kept = [];
|
|
12426
12462
|
for (const band of raw.bands) {
|
|
12427
|
-
if (!listensToLegacySignal(band) || !isRecord$
|
|
12463
|
+
if (!listensToLegacySignal(band) || !isRecord$2(band)) {
|
|
12428
12464
|
kept.push(band);
|
|
12429
12465
|
continue;
|
|
12430
12466
|
}
|
|
@@ -14652,6 +14688,14 @@ var ConvertResultSchema = object({
|
|
|
14652
14688
|
files: array(string()).readonly()
|
|
14653
14689
|
})).readonly()
|
|
14654
14690
|
});
|
|
14691
|
+
_enum(["new-session", "step-up"]);
|
|
14692
|
+
/** The languages the hub's app landing pages are written in (D858). */
|
|
14693
|
+
var AppPageLangSchema = _enum(["en", "it"]);
|
|
14694
|
+
/** How a native app starts one login method (D858), as `auth.listLoginMethods` reports it. */
|
|
14695
|
+
var AppLoginPathSchema = discriminatedUnion("kind", [object({ kind: literal("native") }), object({
|
|
14696
|
+
kind: literal("browser"),
|
|
14697
|
+
startPath: string().startsWith("/")
|
|
14698
|
+
})]);
|
|
14655
14699
|
/**
|
|
14656
14700
|
* Device certificates (D855) — the wire contract shared by the hub, the admin
|
|
14657
14701
|
* UI and the native viewer.
|
|
@@ -14811,7 +14855,9 @@ object({
|
|
|
14811
14855
|
signature: literal(DEVICE_CERT_SIGNATURE),
|
|
14812
14856
|
messageVersion: literal(DEVICE_SIGNATURE_MESSAGE_VERSION),
|
|
14813
14857
|
/** Which clients can execute it: a native app silently, a browser with a non-extractable WebCrypto key. */
|
|
14814
|
-
clients: array(_enum(["native", "web"]))
|
|
14858
|
+
clients: array(_enum(["native", "web"])),
|
|
14859
|
+
/** The app executes it itself, silently (D858). */
|
|
14860
|
+
app: AppLoginPathSchema.nullable()
|
|
14815
14861
|
});
|
|
14816
14862
|
var ExpressionBindingSourceSchema = union([
|
|
14817
14863
|
object({
|
|
@@ -15141,7 +15187,9 @@ var ConfigTabDeclarationSchema = object({
|
|
|
15141
15187
|
var ConfigSectionWithValuesSchema = object({
|
|
15142
15188
|
id: string(),
|
|
15143
15189
|
title: string(),
|
|
15190
|
+
titleKey: string().optional(),
|
|
15144
15191
|
description: string().optional(),
|
|
15192
|
+
descriptionKey: string().optional(),
|
|
15145
15193
|
style: _enum(["card", "accordion"]).optional(),
|
|
15146
15194
|
defaultCollapsed: boolean().optional(),
|
|
15147
15195
|
columns: union([
|
|
@@ -18839,6 +18887,9 @@ method(object({
|
|
|
18839
18887
|
}), method(object({ refs: RefListSchema }), KeychainResolveResultSchema, { auth: "admin" }), method(object({ refs: RefListSchema }), object({ deleted: number().int() }), {
|
|
18840
18888
|
kind: "mutation",
|
|
18841
18889
|
auth: "admin"
|
|
18890
|
+
}), method(object({ deviceId: number().int() }), object({ refs: array(string()).readonly() }), {
|
|
18891
|
+
kind: "mutation",
|
|
18892
|
+
auth: "admin"
|
|
18842
18893
|
}), method(object({}), array(KeychainSecretMetaSchema).readonly(), { auth: "admin" }), method(object({}), KeychainStateSchema, { auth: "admin" });
|
|
18843
18894
|
/**
|
|
18844
18895
|
* device-history — the ONE mechanism for numeric history (D850).
|
|
@@ -40273,6 +40324,42 @@ var DeviceRegisterPayloadSchema = object({
|
|
|
40273
40324
|
* omits it and the keyword backstop applies. */
|
|
40274
40325
|
secretConfigPaths: array(string()).optional()
|
|
40275
40326
|
});
|
|
40327
|
+
/** One deleted device, kept by device-manager so an addon that missed the
|
|
40328
|
+
* deletion can still learn of it (D865). Written by the delete path ONLY. */
|
|
40329
|
+
var DeviceTombstoneSchema = object({
|
|
40330
|
+
deviceId: number().int().positive(),
|
|
40331
|
+
/** Epoch ms the device was deleted. */
|
|
40332
|
+
deletedAt: number(),
|
|
40333
|
+
/** The addon that owned the device when it was deleted. */
|
|
40334
|
+
providerAddonId: string()
|
|
40335
|
+
});
|
|
40336
|
+
/** How long a tombstone stays readable. Past it, a device that was deleted
|
|
40337
|
+
* and never cleaned is only reachable by the admin "clean data of deleted
|
|
40338
|
+
* devices" action. */
|
|
40339
|
+
var DEVICE_TOMBSTONE_RETENTION_MS = 2160 * 60 * 60 * 1e3;
|
|
40340
|
+
/** Data held for one device that device-manager no longer knows. */
|
|
40341
|
+
var OrphanDeviceDataSchema = object({
|
|
40342
|
+
deviceId: number().int().positive(),
|
|
40343
|
+
/** Rows/files per store (`<addonId>:<store>`). */
|
|
40344
|
+
stores: record(string(), number().int().nonnegative())
|
|
40345
|
+
});
|
|
40346
|
+
var CleanupDeletedDevicesResultSchema = object({
|
|
40347
|
+
/**
|
|
40348
|
+
* `skipped` — the absence check could not be trusted (a device-list read
|
|
40349
|
+
* failed or the two reads disagreed); nothing was listed or deleted.
|
|
40350
|
+
* `dry-run` — `devices` is what a confirmed run would delete.
|
|
40351
|
+
* `cleaned` — `devices` is what was deleted.
|
|
40352
|
+
*/
|
|
40353
|
+
status: _enum([
|
|
40354
|
+
"skipped",
|
|
40355
|
+
"dry-run",
|
|
40356
|
+
"cleaned"
|
|
40357
|
+
]),
|
|
40358
|
+
reason: string().nullable(),
|
|
40359
|
+
devices: array(OrphanDeviceDataSchema),
|
|
40360
|
+
/** Implementers that could not be asked (their stores are not in `devices`). */
|
|
40361
|
+
unreachable: array(string())
|
|
40362
|
+
});
|
|
40276
40363
|
var DeviceRemovePayloadSchema = object({ deviceId: number() });
|
|
40277
40364
|
var DevicePersistConfigPayloadSchema = object({
|
|
40278
40365
|
deviceId: number(),
|
|
@@ -40511,6 +40598,9 @@ method(object({
|
|
|
40511
40598
|
}), method(object({ deviceId: number() }), object({ success: literal(true) }), {
|
|
40512
40599
|
kind: "mutation",
|
|
40513
40600
|
auth: "admin"
|
|
40601
|
+
}), method(object({ sinceMs: number() }), array(DeviceTombstoneSchema).readonly(), { auth: "admin" }), method(object({ confirm: boolean() }), CleanupDeletedDevicesResultSchema, {
|
|
40602
|
+
kind: "mutation",
|
|
40603
|
+
auth: "admin"
|
|
40514
40604
|
}), method(object({ integrationId: string() }), object({ removed: number() }), {
|
|
40515
40605
|
kind: "mutation",
|
|
40516
40606
|
auth: "admin"
|
|
@@ -40973,6 +41063,85 @@ method(object({
|
|
|
40973
41063
|
auth: "admin"
|
|
40974
41064
|
});
|
|
40975
41065
|
/**
|
|
41066
|
+
* `device-removal-hook` — the reliable way an addon learns a device was DELETED,
|
|
41067
|
+
* so it can delete what it keeps for that device (D865).
|
|
41068
|
+
*
|
|
41069
|
+
* ## Why an event was not enough
|
|
41070
|
+
*
|
|
41071
|
+
* `DeviceUnregistered` is telemetry and may be dropped (D8, D11). An addon that
|
|
41072
|
+
* hung its per-device clean-up on it left durable garbage whenever the event was
|
|
41073
|
+
* lost, the addon was down, or it was restarting at that moment — footage,
|
|
41074
|
+
* analytics rows and settings of device 4483 outlived the device. Loss of this
|
|
41075
|
+
* signal corrupts durable state, so it travels by RPC with a recorded fact
|
|
41076
|
+
* behind it (D8: "if loss would corrupt durable state, use RPC plus a reconcile").
|
|
41077
|
+
*
|
|
41078
|
+
* ## The three pieces
|
|
41079
|
+
*
|
|
41080
|
+
* 1. device-manager records a TOMBSTONE per deleted device
|
|
41081
|
+
* (`deviceManager.listDeletedSince`). The tombstone is written by the delete
|
|
41082
|
+
* path only — a device that is unregistered, offline or whose provider is
|
|
41083
|
+
* restarting is NOT deleted and gets none.
|
|
41084
|
+
* 2. After a delete, device-manager calls `onDeviceRemoved` on EVERY provider of
|
|
41085
|
+
* this collection, one by one, with bounded retries, logged.
|
|
41086
|
+
* 3. An implementer that was down asks `deviceManager.listDeletedSince` at start
|
|
41087
|
+
* (and periodically) and runs its own `onDeviceRemoved` for each tombstone it
|
|
41088
|
+
* may have missed. Reconcile is driven by tombstones, never by "the device is
|
|
41089
|
+
* not in the current list": a failed or partial list read must not destroy data.
|
|
41090
|
+
*
|
|
41091
|
+
* ## Contract for an implementer
|
|
41092
|
+
*
|
|
41093
|
+
* - **Idempotent.** It is called again by a retry, by a reconcile and by the
|
|
41094
|
+
* admin cleanup of data that predates tombstones. A device with nothing left
|
|
41095
|
+
* answers zero counts.
|
|
41096
|
+
* - **One key per store** in `counts`, deleted rows/files per store, so the log
|
|
41097
|
+
* line and the admin dry run can say where the data was.
|
|
41098
|
+
* - **Training datasets are NOT device data** and are never deleted by a hook.
|
|
41099
|
+
* - **Per-device SETTINGS are not hooked.** Configuration lives in the standard
|
|
41100
|
+
* per-device store (`ctx.settings.*DeviceStore`), which device-manager clears
|
|
41101
|
+
* for every addon centrally at delete time. This hook is for device DATA
|
|
41102
|
+
* that is not settings: footage, event media, analytics rows, history.
|
|
41103
|
+
* - A provider that cannot tell is allowed to throw; the caller retries it.
|
|
41104
|
+
*
|
|
41105
|
+
* `listDeviceData` is the read side of the admin "Clean data of deleted devices"
|
|
41106
|
+
* action: which device ids this addon holds data for, and how much per store. It
|
|
41107
|
+
* never deletes. device-manager decides which of those ids are absent from the
|
|
41108
|
+
* fleet, from TWO consistent reads of the device list (D49).
|
|
41109
|
+
*/
|
|
41110
|
+
/** What a hook is told about the deletion. */
|
|
41111
|
+
var DeviceRemovedInputSchema = object({
|
|
41112
|
+
deviceId: number().int().positive(),
|
|
41113
|
+
/** Epoch ms the device was deleted (the tombstone's `deletedAt`). */
|
|
41114
|
+
deletedAt: number(),
|
|
41115
|
+
/** The addon that owned the device, as device-manager last knew it. */
|
|
41116
|
+
providerAddonId: string()
|
|
41117
|
+
});
|
|
41118
|
+
/** Rows/files/refs deleted, per store this implementer owns. */
|
|
41119
|
+
var DeviceRemovedResultSchema = object({ counts: record(string(), number().int().nonnegative()) });
|
|
41120
|
+
/** One (store, device) pair an implementer holds data for. */
|
|
41121
|
+
var DeviceDataEntrySchema = object({
|
|
41122
|
+
store: string(),
|
|
41123
|
+
deviceId: number().int().positive(),
|
|
41124
|
+
/** Rows (or files) held for the device in the store. */
|
|
41125
|
+
count: number().int().nonnegative()
|
|
41126
|
+
});
|
|
41127
|
+
var deviceRemovalHookCapability = {
|
|
41128
|
+
name: "device-removal-hook",
|
|
41129
|
+
scope: "system",
|
|
41130
|
+
mode: "collection",
|
|
41131
|
+
internal: true,
|
|
41132
|
+
methods: {
|
|
41133
|
+
/** Delete everything this addon keeps for the deleted device. Idempotent. */
|
|
41134
|
+
onDeviceRemoved: method(DeviceRemovedInputSchema, DeviceRemovedResultSchema, {
|
|
41135
|
+
kind: "mutation",
|
|
41136
|
+
auth: "admin"
|
|
41137
|
+
}),
|
|
41138
|
+
/** Which devices this addon holds data for, per store. Reads only. */
|
|
41139
|
+
listDeviceData: method(_void(), array(DeviceDataEntrySchema).readonly(), { auth: "admin" })
|
|
41140
|
+
},
|
|
41141
|
+
/** In-process only — enumerated through `addons.listCapabilityProviders`. */
|
|
41142
|
+
mount: { kind: "skip" }
|
|
41143
|
+
};
|
|
41144
|
+
/**
|
|
40976
41145
|
* `failure-contribution` — the capability an addon reports its OWN losses
|
|
40977
41146
|
* through, per camera, with the denominator attached. It stores nothing.
|
|
40978
41147
|
*
|
|
@@ -41994,7 +42163,13 @@ var LoginMethodContributionSchema = discriminatedUnion("kind", [
|
|
|
41994
42163
|
* `beginExternalLink` offer exactly the redirect methods that set this,
|
|
41995
42164
|
* whatever their id. Absent / false — a login button only.
|
|
41996
42165
|
*/
|
|
41997
|
-
linkable: boolean().optional()
|
|
42166
|
+
linkable: boolean().optional(),
|
|
42167
|
+
/**
|
|
42168
|
+
* How a NATIVE app starts this method (D858): `{ kind: 'browser', startPath }`
|
|
42169
|
+
* when the route understands the app flow query (`app=1&code_challenge=…`),
|
|
42170
|
+
* `null`/absent when there is no app path - the app hides the method.
|
|
42171
|
+
*/
|
|
42172
|
+
app: AppLoginPathSchema.nullable().optional()
|
|
41998
42173
|
}),
|
|
41999
42174
|
object({
|
|
42000
42175
|
kind: literal("widget"),
|
|
@@ -42006,7 +42181,9 @@ var LoginMethodContributionSchema = discriminatedUnion("kind", [
|
|
|
42006
42181
|
bundle: string(),
|
|
42007
42182
|
/** MF remote descriptor — `{ remoteName, exposedModule, componentKey }`. */
|
|
42008
42183
|
remote: WidgetRemoteSchema,
|
|
42009
|
-
stage: LoginStageEnum
|
|
42184
|
+
stage: LoginStageEnum,
|
|
42185
|
+
/** Widgets are web ceremonies: no native app path (D858). Absent reads as `null`. */
|
|
42186
|
+
app: AppLoginPathSchema.nullable().optional()
|
|
42010
42187
|
}),
|
|
42011
42188
|
object({
|
|
42012
42189
|
kind: literal("passkey"),
|
|
@@ -42018,7 +42195,9 @@ var LoginMethodContributionSchema = discriminatedUnion("kind", [
|
|
|
42018
42195
|
/** Effective WebAuthn RP ID (`resolveRpID()`) — the shell gates visibility on it. */
|
|
42019
42196
|
rpId: string(),
|
|
42020
42197
|
/** Effective expected origin (`resolveOrigin()`), null when unconfigured. */
|
|
42021
|
-
origin: string().nullable()
|
|
42198
|
+
origin: string().nullable(),
|
|
42199
|
+
/** Set by the hub for the primary arm; a second-factor passkey has no app path (D858). */
|
|
42200
|
+
app: AppLoginPathSchema.nullable().optional()
|
|
42022
42201
|
})
|
|
42023
42202
|
]);
|
|
42024
42203
|
method(_void(), array(LoginMethodContributionSchema).readonly());
|
|
@@ -42545,7 +42724,21 @@ var NetworkEndpointSchema = object({
|
|
|
42545
42724
|
url: string(),
|
|
42546
42725
|
hostname: string(),
|
|
42547
42726
|
port: number(),
|
|
42548
|
-
protocol: _enum(["http", "https"])
|
|
42727
|
+
protocol: _enum(["http", "https"]),
|
|
42728
|
+
/**
|
|
42729
|
+
* Whether this address survives a restart of its provider. `false` = it is
|
|
42730
|
+
* re-issued every time (a Quick tunnel's random `*.trycloudflare.com`); the
|
|
42731
|
+
* hub never selects such an address AUTOMATICALLY for a role (D860), though
|
|
42732
|
+
* it stays visible and an operator may still flag it. Absent = stable: every
|
|
42733
|
+
* provider except a Quick tunnel owns a name that does not change.
|
|
42734
|
+
*/
|
|
42735
|
+
stable: boolean().optional()
|
|
42736
|
+
});
|
|
42737
|
+
object({
|
|
42738
|
+
url: string(),
|
|
42739
|
+
/** Mirrors {@link NetworkEndpointSchema} `stable`; absent = stable. */
|
|
42740
|
+
stable: boolean().optional(),
|
|
42741
|
+
updated: boolean().optional()
|
|
42549
42742
|
});
|
|
42550
42743
|
var NetworkAccessStatusSchema = object({
|
|
42551
42744
|
connected: boolean(),
|
|
@@ -53349,7 +53542,22 @@ var SsoBridgeClaimsSchema = object({
|
|
|
53349
53542
|
* request to present the matching cookie — a login bridge is useless in
|
|
53350
53543
|
* any other browser.
|
|
53351
53544
|
*/
|
|
53352
|
-
browserBinding: string().optional()
|
|
53545
|
+
browserBinding: string().optional(),
|
|
53546
|
+
/**
|
|
53547
|
+
* The native app that started this sign-in (D858): its PKCE challenge,
|
|
53548
|
+
* `state`, purpose and allow-listed return URL, copied from the server-side
|
|
53549
|
+
* pending OIDC state. A bridge carrying it is finished ONLY at
|
|
53550
|
+
* `/api/auth/sso/finish-app` (which mints a handoff code, never a web
|
|
53551
|
+
* session); `/api/auth/sso/finish` refuses it.
|
|
53552
|
+
*/
|
|
53553
|
+
app: object({
|
|
53554
|
+
codeChallenge: string(),
|
|
53555
|
+
state: string(),
|
|
53556
|
+
purpose: _enum(["new-session", "step-up"]),
|
|
53557
|
+
redirect: string(),
|
|
53558
|
+
/** The page language the app asked for (D858); the confirm page speaks it. */
|
|
53559
|
+
lang: _enum(["en", "it"]).optional()
|
|
53560
|
+
}).optional()
|
|
53353
53561
|
});
|
|
53354
53562
|
method(object({
|
|
53355
53563
|
claims: SsoBridgeClaimsSchema,
|
|
@@ -55969,7 +56177,12 @@ var SearchResultSchema = object({
|
|
|
55969
56177
|
publishedAt: string(),
|
|
55970
56178
|
author: string(),
|
|
55971
56179
|
installed: boolean(),
|
|
55972
|
-
installedVersion: string().optional()
|
|
56180
|
+
installedVersion: string().optional(),
|
|
56181
|
+
/**
|
|
56182
|
+
* Capability names the package's addons declare (from its published
|
|
56183
|
+
* manifest). `null` = the registry lookup failed — unknown, never `[]` (D393).
|
|
56184
|
+
*/
|
|
56185
|
+
capabilities: array(string()).readonly().nullable()
|
|
55973
56186
|
});
|
|
55974
56187
|
var AutoUpdateSettingsSchema = object({
|
|
55975
56188
|
channel: ChannelSchema,
|
|
@@ -56131,7 +56344,11 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56131
56344
|
}), method(object({ packageName: string().optional() }), PackageInstallationsSchema, { auth: "admin" }), method(_void(), ReloadPackagesResultSchema, {
|
|
56132
56345
|
kind: "mutation",
|
|
56133
56346
|
auth: "admin"
|
|
56134
|
-
}), method(object({
|
|
56347
|
+
}), method(object({
|
|
56348
|
+
query: string().optional(),
|
|
56349
|
+
/** Only packages whose addons declare this capability (unknown ones excluded). */
|
|
56350
|
+
capability: string().optional()
|
|
56351
|
+
}), array(SearchResultSchema)), method(object({ nodeId: string().optional() }), array(PackageUpdateSchema).readonly(), { auth: "admin" }), method(object({
|
|
56135
56352
|
name: string().min(1),
|
|
56136
56353
|
version: string().optional(),
|
|
56137
56354
|
nodeId: string().optional()
|
|
@@ -58628,7 +58845,13 @@ var ConnectionEndpointSchema = object({
|
|
|
58628
58845
|
* calls so the client can sort even if the cap returns a new
|
|
58629
58846
|
* ordering between polls.
|
|
58630
58847
|
*/
|
|
58631
|
-
priority: number()
|
|
58848
|
+
priority: number(),
|
|
58849
|
+
/**
|
|
58850
|
+
* `false` = the address changes on its own (a Quick tunnel, re-issued on
|
|
58851
|
+
* every respawn). Automatic role resolution skips it (D860); an explicit
|
|
58852
|
+
* operator flag still honours it. Absent = stable.
|
|
58853
|
+
*/
|
|
58854
|
+
stable: boolean().optional()
|
|
58632
58855
|
});
|
|
58633
58856
|
/**
|
|
58634
58857
|
* Where the advertised local port came from. Ordered most → least
|
|
@@ -63724,6 +63947,21 @@ DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
|
|
|
63724
63947
|
on: boolean(),
|
|
63725
63948
|
lastChangedAt: number()
|
|
63726
63949
|
});
|
|
63950
|
+
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
63951
|
+
function hasControlCharacter(value) {
|
|
63952
|
+
for (const char of value) {
|
|
63953
|
+
const code = char.codePointAt(0) ?? 0;
|
|
63954
|
+
if (code <= 31 || code >= 127 && code <= 159) return true;
|
|
63955
|
+
}
|
|
63956
|
+
return false;
|
|
63957
|
+
}
|
|
63958
|
+
string().transform((value) => value.trim()).pipe(string().min(1, "The server name cannot be empty").max(48, `The server name is at most 48 characters`).refine((value) => !hasControlCharacter(value), { message: "The server name cannot contain control characters" }));
|
|
63959
|
+
/** What every reader gets: the name to show, and whether the hub chose it itself. */
|
|
63960
|
+
var ServerNameInfoSchema = object({
|
|
63961
|
+
name: string(),
|
|
63962
|
+
/** `true` when nobody named the hub: `name` is the machine hostname. */
|
|
63963
|
+
isDefault: boolean()
|
|
63964
|
+
});
|
|
63727
63965
|
/**
|
|
63728
63966
|
* system — system-scoped singleton capability exposing hub-level
|
|
63729
63967
|
* health, feature flags, network interface enumeration, and the
|
|
@@ -63753,6 +63991,12 @@ var FeatureManifestSchema = object({
|
|
|
63753
63991
|
backup: boolean(),
|
|
63754
63992
|
repl: boolean()
|
|
63755
63993
|
});
|
|
63994
|
+
/**
|
|
63995
|
+
* `system.info`: the feature flags plus the hub's human name (D861). The name is
|
|
63996
|
+
* `{ name, isDefault }` — `isDefault: true` means nobody named the hub and `name`
|
|
63997
|
+
* is the machine hostname.
|
|
63998
|
+
*/
|
|
63999
|
+
var SystemInfoSchema = FeatureManifestSchema.extend({ serverName: ServerNameInfoSchema });
|
|
63756
64000
|
var HealthStatusSchema = object({
|
|
63757
64001
|
status: literal("ok"),
|
|
63758
64002
|
uptime: number()
|
|
@@ -64225,7 +64469,7 @@ var LoggingSettingsStateSchema = object({
|
|
|
64225
64469
|
opsLogRetentionDays: number().int().min(0),
|
|
64226
64470
|
persisted: boolean()
|
|
64227
64471
|
});
|
|
64228
|
-
method(_void(),
|
|
64472
|
+
method(_void(), SystemInfoSchema), method(_void(), HealthStatusSchema), method(_void(), FeatureManifestSchema), method(_void(), array(NetworkAddressSchema).readonly()), method(_void(), unknown().nullable(), { auth: "admin" }), method(record(string(), unknown()), _null(), {
|
|
64229
64473
|
kind: "mutation",
|
|
64230
64474
|
auth: "admin"
|
|
64231
64475
|
}), method(_void(), _void(), {
|
|
@@ -67294,6 +67538,12 @@ Object.freeze({
|
|
|
67294
67538
|
addonId: null,
|
|
67295
67539
|
access: "create"
|
|
67296
67540
|
},
|
|
67541
|
+
"deviceManager.cleanupDeletedDevicesData": {
|
|
67542
|
+
capName: "device-manager",
|
|
67543
|
+
capScope: "system",
|
|
67544
|
+
addonId: null,
|
|
67545
|
+
access: "create"
|
|
67546
|
+
},
|
|
67297
67547
|
"deviceManager.createDevice": {
|
|
67298
67548
|
capName: "device-manager",
|
|
67299
67549
|
capScope: "system",
|
|
@@ -67474,6 +67724,12 @@ Object.freeze({
|
|
|
67474
67724
|
addonId: null,
|
|
67475
67725
|
access: "view"
|
|
67476
67726
|
},
|
|
67727
|
+
"deviceManager.listDeletedSince": {
|
|
67728
|
+
capName: "device-manager",
|
|
67729
|
+
capScope: "system",
|
|
67730
|
+
addonId: null,
|
|
67731
|
+
access: "view"
|
|
67732
|
+
},
|
|
67477
67733
|
"deviceManager.listDeviceIdsByCaps": {
|
|
67478
67734
|
capName: "device-manager",
|
|
67479
67735
|
capScope: "system",
|
|
@@ -67882,6 +68138,18 @@ Object.freeze({
|
|
|
67882
68138
|
addonId: null,
|
|
67883
68139
|
access: "create"
|
|
67884
68140
|
},
|
|
68141
|
+
"deviceRemovalHook.listDeviceData": {
|
|
68142
|
+
capName: "device-removal-hook",
|
|
68143
|
+
capScope: "system",
|
|
68144
|
+
addonId: null,
|
|
68145
|
+
access: "view"
|
|
68146
|
+
},
|
|
68147
|
+
"deviceRemovalHook.onDeviceRemoved": {
|
|
68148
|
+
capName: "device-removal-hook",
|
|
68149
|
+
capScope: "system",
|
|
68150
|
+
addonId: null,
|
|
68151
|
+
access: "create"
|
|
68152
|
+
},
|
|
67885
68153
|
"deviceState.claimFields": {
|
|
67886
68154
|
capName: "device-state",
|
|
67887
68155
|
capScope: "system",
|
|
@@ -68314,6 +68582,12 @@ Object.freeze({
|
|
|
68314
68582
|
addonId: null,
|
|
68315
68583
|
access: "delete"
|
|
68316
68584
|
},
|
|
68585
|
+
"keychain.deleteDeviceScope": {
|
|
68586
|
+
capName: "keychain",
|
|
68587
|
+
capScope: "system",
|
|
68588
|
+
addonId: null,
|
|
68589
|
+
access: "delete"
|
|
68590
|
+
},
|
|
68317
68591
|
"keychain.getState": {
|
|
68318
68592
|
capName: "keychain",
|
|
68319
68593
|
capScope: "system",
|
|
@@ -74326,6 +74600,11 @@ Object.freeze({
|
|
|
74326
74600
|
form: "single",
|
|
74327
74601
|
optional: false
|
|
74328
74602
|
}],
|
|
74603
|
+
"deviceRemovalHook.onDeviceRemoved": [{
|
|
74604
|
+
name: "deviceId",
|
|
74605
|
+
form: "single",
|
|
74606
|
+
optional: false
|
|
74607
|
+
}],
|
|
74329
74608
|
"deviceState.claimFields": [{
|
|
74330
74609
|
name: "deviceId",
|
|
74331
74610
|
form: "single",
|
|
@@ -74515,6 +74794,11 @@ Object.freeze({
|
|
|
74515
74794
|
form: "single",
|
|
74516
74795
|
optional: false
|
|
74517
74796
|
}],
|
|
74797
|
+
"keychain.deleteDeviceScope": [{
|
|
74798
|
+
name: "deviceId",
|
|
74799
|
+
form: "single",
|
|
74800
|
+
optional: false
|
|
74801
|
+
}],
|
|
74518
74802
|
"lawnMowerControl.dock": [{
|
|
74519
74803
|
name: "deviceId",
|
|
74520
74804
|
form: "single",
|
|
@@ -76913,6 +77197,8 @@ new Set([
|
|
|
76913
77197
|
"audio-tools",
|
|
76914
77198
|
"audio-silence"
|
|
76915
77199
|
]);
|
|
77200
|
+
AppPageLangSchema.options;
|
|
77201
|
+
record(string().min(1), string());
|
|
76916
77202
|
/**
|
|
76917
77203
|
* TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
|
|
76918
77204
|
*
|
|
@@ -78478,6 +78764,76 @@ function enumerateInferenceDevices(hw) {
|
|
|
78478
78764
|
}
|
|
78479
78765
|
return out;
|
|
78480
78766
|
}
|
|
78767
|
+
/** How often an implementer re-asks for tombstones after its start-up pass. */
|
|
78768
|
+
var REMOVAL_RECONCILE_INTERVAL_MS = 360 * 60 * 1e3;
|
|
78769
|
+
/** One reconcile pass over every tombstone inside the retention window. */
|
|
78770
|
+
async function reconcileRemovedDevices(opts) {
|
|
78771
|
+
const now = opts.now ?? (() => Date.now());
|
|
78772
|
+
const api = opts.api;
|
|
78773
|
+
if (api === void 0) {
|
|
78774
|
+
opts.logger.warn("device removal reconcile skipped — no device-manager api");
|
|
78775
|
+
return {
|
|
78776
|
+
read: false,
|
|
78777
|
+
applied: 0,
|
|
78778
|
+
failed: 0
|
|
78779
|
+
};
|
|
78780
|
+
}
|
|
78781
|
+
let tombstones;
|
|
78782
|
+
try {
|
|
78783
|
+
tombstones = await api.deviceManager.listDeletedSince.query({ sinceMs: now() - DEVICE_TOMBSTONE_RETENTION_MS });
|
|
78784
|
+
} catch (err) {
|
|
78785
|
+
opts.logger.warn("device removal reconcile skipped — tombstones unreadable, nothing deleted", { meta: { error: errMsg(err) } });
|
|
78786
|
+
return {
|
|
78787
|
+
read: false,
|
|
78788
|
+
applied: 0,
|
|
78789
|
+
failed: 0
|
|
78790
|
+
};
|
|
78791
|
+
}
|
|
78792
|
+
let applied = 0;
|
|
78793
|
+
let failed = 0;
|
|
78794
|
+
for (const tombstone of tombstones) try {
|
|
78795
|
+
const result = await opts.remove(tombstone);
|
|
78796
|
+
applied += 1;
|
|
78797
|
+
if (Object.values(result.counts).reduce((sum, n) => sum + n, 0) > 0) opts.logger.info("device removal reconcile cleaned a missed deletion", {
|
|
78798
|
+
tags: { deviceId: tombstone.deviceId },
|
|
78799
|
+
meta: {
|
|
78800
|
+
counts: result.counts,
|
|
78801
|
+
deletedAt: tombstone.deletedAt
|
|
78802
|
+
}
|
|
78803
|
+
});
|
|
78804
|
+
} catch (err) {
|
|
78805
|
+
failed += 1;
|
|
78806
|
+
opts.logger.warn("device removal reconcile failed for a device — retried next pass", {
|
|
78807
|
+
tags: { deviceId: tombstone.deviceId },
|
|
78808
|
+
meta: { error: errMsg(err) }
|
|
78809
|
+
});
|
|
78810
|
+
}
|
|
78811
|
+
return {
|
|
78812
|
+
read: true,
|
|
78813
|
+
applied,
|
|
78814
|
+
failed
|
|
78815
|
+
};
|
|
78816
|
+
}
|
|
78817
|
+
/**
|
|
78818
|
+
* Run the reconcile now and then periodically. Returns the disposer. The timer
|
|
78819
|
+
* is unref'd and a pass never overlaps the previous one.
|
|
78820
|
+
*/
|
|
78821
|
+
function armRemovalReconcile(opts) {
|
|
78822
|
+
let running = false;
|
|
78823
|
+
const pass = () => {
|
|
78824
|
+
if (running) return;
|
|
78825
|
+
running = true;
|
|
78826
|
+
reconcileRemovedDevices(opts).catch((err) => {
|
|
78827
|
+
opts.logger.warn("device removal reconcile pass crashed", { meta: { error: errMsg(err) } });
|
|
78828
|
+
}).finally(() => {
|
|
78829
|
+
running = false;
|
|
78830
|
+
});
|
|
78831
|
+
};
|
|
78832
|
+
pass();
|
|
78833
|
+
const timer = setInterval(pass, REMOVAL_RECONCILE_INTERVAL_MS);
|
|
78834
|
+
timer.unref?.();
|
|
78835
|
+
return () => clearInterval(timer);
|
|
78836
|
+
}
|
|
78481
78837
|
//#endregion
|
|
78482
78838
|
Object.defineProperty(exports, "APPEARANCE_BLOCKS", {
|
|
78483
78839
|
enumerable: true,
|
|
@@ -78857,6 +79213,12 @@ Object.defineProperty(exports, "applyModelBoundSettings", {
|
|
|
78857
79213
|
return applyModelBoundSettings;
|
|
78858
79214
|
}
|
|
78859
79215
|
});
|
|
79216
|
+
Object.defineProperty(exports, "armRemovalReconcile", {
|
|
79217
|
+
enumerable: true,
|
|
79218
|
+
get: function() {
|
|
79219
|
+
return armRemovalReconcile;
|
|
79220
|
+
}
|
|
79221
|
+
});
|
|
78860
79222
|
Object.defineProperty(exports, "array", {
|
|
78861
79223
|
enumerable: true,
|
|
78862
79224
|
get: function() {
|
|
@@ -79019,6 +79381,12 @@ Object.defineProperty(exports, "detectionPipelineCapability", {
|
|
|
79019
79381
|
return detectionPipelineCapability;
|
|
79020
79382
|
}
|
|
79021
79383
|
});
|
|
79384
|
+
Object.defineProperty(exports, "deviceRemovalHookCapability", {
|
|
79385
|
+
enumerable: true,
|
|
79386
|
+
get: function() {
|
|
79387
|
+
return deviceRemovalHookCapability;
|
|
79388
|
+
}
|
|
79389
|
+
});
|
|
79022
79390
|
Object.defineProperty(exports, "discriminatedUnion", {
|
|
79023
79391
|
enumerable: true,
|
|
79024
79392
|
get: function() {
|
|
@@ -79487,6 +79855,12 @@ Object.defineProperty(exports, "union", {
|
|
|
79487
79855
|
return union;
|
|
79488
79856
|
}
|
|
79489
79857
|
});
|
|
79858
|
+
Object.defineProperty(exports, "userError", {
|
|
79859
|
+
enumerable: true,
|
|
79860
|
+
get: function() {
|
|
79861
|
+
return userError;
|
|
79862
|
+
}
|
|
79863
|
+
});
|
|
79490
79864
|
Object.defineProperty(exports, "videoclipsCapability", {
|
|
79491
79865
|
enumerable: true,
|
|
79492
79866
|
get: function() {
|