@camstack/addon-pipeline-orchestrator 1.2.601 → 1.2.603
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/_stub.js +2 -2
- package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_orchestrator_widgets-BnncRMgV.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_orchestrator_widgets-Bg5karC8.mjs} +3 -3
- package/dist/_virtual_mf___mfe_internal__addon_pipeline_orchestrator_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BLLm0SDo.mjs +26 -0
- package/dist/_virtual_mf___mfe_internal__addon_pipeline_orchestrator_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DaLsVu7q.mjs +26 -0
- package/dist/{hostInit-DJAZHqmT.mjs → hostInit-BvlQyOZn.mjs} +3 -3
- package/dist/index.js +526 -415
- package/dist/index.mjs +526 -415
- package/dist/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/_virtual_mf___mfe_internal__addon_pipeline_orchestrator_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-1u_S2C2B.mjs +0 -26
- package/dist/_virtual_mf___mfe_internal__addon_pipeline_orchestrator_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-B0SJpNzs.mjs +0 -26
package/dist/index.js
CHANGED
|
@@ -5569,7 +5569,7 @@ var ZodIssueCode = {
|
|
|
5569
5569
|
var ZodFirstPartyTypeKind;
|
|
5570
5570
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5571
5571
|
//#endregion
|
|
5572
|
-
//#region ../types/dist/sleep-
|
|
5572
|
+
//#region ../types/dist/sleep-BegKjwUu.mjs
|
|
5573
5573
|
/**
|
|
5574
5574
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5575
5575
|
* window to float samples (D455).
|
|
@@ -6389,7 +6389,7 @@ async function writeMembers(ctx, children, incoming, stored, pathOf) {
|
|
|
6389
6389
|
for (const [member, node] of children) applyMember(out, member, await writeNode(ctx, node, incoming[member], stored[member], pathOf(member)), stored);
|
|
6390
6390
|
return out;
|
|
6391
6391
|
}
|
|
6392
|
-
function rowId
|
|
6392
|
+
function rowId(row, idKey) {
|
|
6393
6393
|
const raw = row[idKey];
|
|
6394
6394
|
if (typeof raw === "string" && raw.length > 0) return raw;
|
|
6395
6395
|
if (typeof raw === "number" && Number.isFinite(raw)) return String(raw);
|
|
@@ -6406,7 +6406,7 @@ async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
|
6406
6406
|
}
|
|
6407
6407
|
const storedById = /* @__PURE__ */ new Map();
|
|
6408
6408
|
for (const row of storedRows) {
|
|
6409
|
-
const id = rowId
|
|
6409
|
+
const id = rowId(row, node.idKey);
|
|
6410
6410
|
if (id !== null) storedById.set(id, row);
|
|
6411
6411
|
}
|
|
6412
6412
|
const kept = /* @__PURE__ */ new Set();
|
|
@@ -6416,13 +6416,13 @@ async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
|
6416
6416
|
rows.push(row);
|
|
6417
6417
|
continue;
|
|
6418
6418
|
}
|
|
6419
|
-
const id = rowId
|
|
6419
|
+
const id = rowId(row, node.idKey) ?? ctx.mintId();
|
|
6420
6420
|
kept.add(id);
|
|
6421
6421
|
const withId = {
|
|
6422
6422
|
...row,
|
|
6423
6423
|
[node.idKey]: row[node.idKey] ?? id
|
|
6424
6424
|
};
|
|
6425
|
-
if (rowId
|
|
6425
|
+
if (rowId(withId, node.idKey) === null) withId[node.idKey] = id;
|
|
6426
6426
|
const storedRow = storedById.get(id) ?? {};
|
|
6427
6427
|
rows.push(await writeMembers(ctx, node.item, withId, storedRow, (member) => arrayItemFieldPath(fieldPath, id, member)));
|
|
6428
6428
|
}
|
|
@@ -9327,7 +9327,7 @@ function sleep(ms) {
|
|
|
9327
9327
|
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
9328
9328
|
}
|
|
9329
9329
|
//#endregion
|
|
9330
|
-
//#region ../types/dist/err-msg
|
|
9330
|
+
//#region ../types/dist/err-msg-BXKzRBwg.mjs
|
|
9331
9331
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
9332
9332
|
DeviceType["Camera"] = "camera";
|
|
9333
9333
|
DeviceType["Hub"] = "hub";
|
|
@@ -9419,6 +9419,10 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
9419
9419
|
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
9420
9420
|
* integrations sharing the same food/desiccant/hopper surface. */
|
|
9421
9421
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
9422
|
+
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
9423
|
+
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
9424
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations. */
|
|
9425
|
+
DeviceType["Dishwasher"] = "dishwasher";
|
|
9422
9426
|
return DeviceType;
|
|
9423
9427
|
}({});
|
|
9424
9428
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -9676,7 +9680,7 @@ function errMsg$2(err) {
|
|
|
9676
9680
|
return String(err);
|
|
9677
9681
|
}
|
|
9678
9682
|
//#endregion
|
|
9679
|
-
//#region ../types/dist/composition-
|
|
9683
|
+
//#region ../types/dist/composition-CB6PMT9p.mjs
|
|
9680
9684
|
/**
|
|
9681
9685
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
9682
9686
|
*
|
|
@@ -14542,8 +14546,13 @@ var AlertSeveritySchema = _enum([
|
|
|
14542
14546
|
"info",
|
|
14543
14547
|
"success",
|
|
14544
14548
|
"warning",
|
|
14545
|
-
"error"
|
|
14549
|
+
"error",
|
|
14550
|
+
"critical"
|
|
14546
14551
|
]);
|
|
14552
|
+
var AlertActionSchema = object({
|
|
14553
|
+
label: string(),
|
|
14554
|
+
href: string().optional()
|
|
14555
|
+
});
|
|
14547
14556
|
var AlertStatusSchema = _enum([
|
|
14548
14557
|
"active",
|
|
14549
14558
|
"in-progress",
|
|
@@ -14561,6 +14570,7 @@ var AlertSchema = object({
|
|
|
14561
14570
|
severity: AlertSeveritySchema,
|
|
14562
14571
|
title: string(),
|
|
14563
14572
|
message: string(),
|
|
14573
|
+
action: AlertActionSchema.optional(),
|
|
14564
14574
|
status: AlertStatusSchema,
|
|
14565
14575
|
progress: number().optional(),
|
|
14566
14576
|
read: boolean(),
|
|
@@ -18743,7 +18753,11 @@ DeviceType.Hub, DeviceDiscoveryStatusSchema.extend({ lastFetchedAt: number().int
|
|
|
18743
18753
|
});
|
|
18744
18754
|
/**
|
|
18745
18755
|
* `device-adoption` — generic discovery + adoption surface,
|
|
18746
|
-
* system-scoped
|
|
18756
|
+
* system-scoped collection (one provider per integration addon), routed
|
|
18757
|
+
* by explicit `{ addonId }` on direct `deviceAdoption.*` calls — the same
|
|
18758
|
+
* pin model as `connection-test`. The admin UI keeps using
|
|
18759
|
+
* `deviceManager.adoption*` (which already threads `addonId`). The de-HA-ified
|
|
18760
|
+
* successor to `ha-discovery`:
|
|
18747
18761
|
* keyed by `integrationId` (the addon resolves integrationId → broker
|
|
18748
18762
|
* internally) rather than a connection-specific `brokerId`, and it
|
|
18749
18763
|
* REUSES the shared `DiscoveredChildDevice` candidate type from
|
|
@@ -55483,7 +55497,7 @@ var BatteryStatusSchema = object({
|
|
|
55483
55497
|
*/
|
|
55484
55498
|
binary: boolean().optional()
|
|
55485
55499
|
});
|
|
55486
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, method(object({
|
|
55500
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, method(object({
|
|
55487
55501
|
deviceId: number(),
|
|
55488
55502
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
55489
55503
|
timeoutMs: number().int().min(500).max(3e4).default(8e3)
|
|
@@ -56359,6 +56373,130 @@ object({
|
|
|
56359
56373
|
deviceId: number(),
|
|
56360
56374
|
status: DeviceStatusSchema
|
|
56361
56375
|
});
|
|
56376
|
+
/**
|
|
56377
|
+
* Smart-dishwasher cap — program lifecycle, door / remote-start gates,
|
|
56378
|
+
* consumable levels (salt, rinse aid) and common program options.
|
|
56379
|
+
*
|
|
56380
|
+
* Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
|
|
56381
|
+
* by any integration that exposes the same program / option surface.
|
|
56382
|
+
*
|
|
56383
|
+
* `kind: 'poll'` — cloud REST APIs typically have no push channel; the
|
|
56384
|
+
* provider refreshes the slice on an interval and eagerly after commands.
|
|
56385
|
+
*/
|
|
56386
|
+
var DishwasherStateSchema = _enum([
|
|
56387
|
+
"idle",
|
|
56388
|
+
"running",
|
|
56389
|
+
"paused",
|
|
56390
|
+
"finished",
|
|
56391
|
+
"error",
|
|
56392
|
+
"unavailable"
|
|
56393
|
+
]);
|
|
56394
|
+
var DishwasherConsumableLevelSchema = _enum([
|
|
56395
|
+
"ok",
|
|
56396
|
+
"low",
|
|
56397
|
+
"empty"
|
|
56398
|
+
]);
|
|
56399
|
+
object({
|
|
56400
|
+
state: DishwasherStateSchema,
|
|
56401
|
+
/** Active program id/name, or null when none selected / unknown. */
|
|
56402
|
+
program: string().nullable(),
|
|
56403
|
+
/** Program tokens the hardware accepts — drives the UI selector. */
|
|
56404
|
+
availablePrograms: array(string()),
|
|
56405
|
+
/** Minutes remaining on the active cycle, or null when not running. */
|
|
56406
|
+
remainingMinutes: number().int().nonnegative().nullable(),
|
|
56407
|
+
/** Cycle completion 0..100, or null when not applicable. */
|
|
56408
|
+
progressPercent: number().min(0).max(100).nullable(),
|
|
56409
|
+
/** True when the door is reported open. */
|
|
56410
|
+
doorOpen: boolean(),
|
|
56411
|
+
/** True when remote start is allowed (door closed, power on, etc.). */
|
|
56412
|
+
remoteStartAllowed: boolean(),
|
|
56413
|
+
/** Main power / switched-on state. */
|
|
56414
|
+
powerOn: boolean(),
|
|
56415
|
+
saltLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
56416
|
+
rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
56417
|
+
halfLoad: boolean(),
|
|
56418
|
+
hygienePlus: boolean(),
|
|
56419
|
+
/** Extra dry option when the appliance exposes it. */
|
|
56420
|
+
extraDry: boolean(),
|
|
56421
|
+
/** Intensive zone (lower basket) when the appliance exposes it. */
|
|
56422
|
+
intensiveZone: boolean(),
|
|
56423
|
+
/** VarioSpeed / VarioSpeed+ when the appliance exposes it. */
|
|
56424
|
+
varioSpeedPlus: boolean(),
|
|
56425
|
+
/** Child lock (controls disabled on the appliance). */
|
|
56426
|
+
childLock: boolean(),
|
|
56427
|
+
errorCode: number().nullable(),
|
|
56428
|
+
errorLabel: string().nullable(),
|
|
56429
|
+
lastFetchedAt: number()
|
|
56430
|
+
});
|
|
56431
|
+
DeviceType.Dishwasher, method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
56432
|
+
kind: "mutation",
|
|
56433
|
+
auth: "protected"
|
|
56434
|
+
}), method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
56435
|
+
kind: "mutation",
|
|
56436
|
+
auth: "protected"
|
|
56437
|
+
}), method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
56438
|
+
kind: "mutation",
|
|
56439
|
+
auth: "protected"
|
|
56440
|
+
}), method(object({
|
|
56441
|
+
deviceId: number().int().nonnegative(),
|
|
56442
|
+
program: string().min(1)
|
|
56443
|
+
}), _void(), {
|
|
56444
|
+
kind: "mutation",
|
|
56445
|
+
auth: "protected"
|
|
56446
|
+
}), method(object({
|
|
56447
|
+
deviceId: number().int().nonnegative(),
|
|
56448
|
+
on: boolean()
|
|
56449
|
+
}), _void(), {
|
|
56450
|
+
kind: "mutation",
|
|
56451
|
+
auth: "protected"
|
|
56452
|
+
}), method(object({
|
|
56453
|
+
deviceId: number().int().nonnegative(),
|
|
56454
|
+
on: boolean()
|
|
56455
|
+
}), _void(), {
|
|
56456
|
+
kind: "mutation",
|
|
56457
|
+
auth: "protected"
|
|
56458
|
+
}), method(object({
|
|
56459
|
+
deviceId: number().int().nonnegative(),
|
|
56460
|
+
on: boolean()
|
|
56461
|
+
}), _void(), {
|
|
56462
|
+
kind: "mutation",
|
|
56463
|
+
auth: "protected"
|
|
56464
|
+
}), method(object({
|
|
56465
|
+
deviceId: number().int().nonnegative(),
|
|
56466
|
+
on: boolean()
|
|
56467
|
+
}), _void(), {
|
|
56468
|
+
kind: "mutation",
|
|
56469
|
+
auth: "protected"
|
|
56470
|
+
}), method(object({
|
|
56471
|
+
deviceId: number().int().nonnegative(),
|
|
56472
|
+
on: boolean()
|
|
56473
|
+
}), _void(), {
|
|
56474
|
+
kind: "mutation",
|
|
56475
|
+
auth: "protected"
|
|
56476
|
+
}), method(object({
|
|
56477
|
+
deviceId: number().int().nonnegative(),
|
|
56478
|
+
on: boolean()
|
|
56479
|
+
}), _void(), {
|
|
56480
|
+
kind: "mutation",
|
|
56481
|
+
auth: "protected"
|
|
56482
|
+
}), method(object({
|
|
56483
|
+
deviceId: number().int().nonnegative(),
|
|
56484
|
+
on: boolean()
|
|
56485
|
+
}), _void(), {
|
|
56486
|
+
kind: "mutation",
|
|
56487
|
+
auth: "protected"
|
|
56488
|
+
}), method(object({
|
|
56489
|
+
deviceId: number().int().nonnegative(),
|
|
56490
|
+
key: string().min(1),
|
|
56491
|
+
value: union([
|
|
56492
|
+
boolean(),
|
|
56493
|
+
string(),
|
|
56494
|
+
number()
|
|
56495
|
+
])
|
|
56496
|
+
}), _void(), {
|
|
56497
|
+
kind: "mutation",
|
|
56498
|
+
auth: "protected"
|
|
56499
|
+
});
|
|
56362
56500
|
object({
|
|
56363
56501
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
56364
56502
|
lastPressedAt: number().nullable(),
|
|
@@ -56924,6 +57062,13 @@ object({
|
|
|
56924
57062
|
lastChangedAt: number()
|
|
56925
57063
|
});
|
|
56926
57064
|
DeviceType.Sensor;
|
|
57065
|
+
object({
|
|
57066
|
+
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
57067
|
+
position: number().min(0).max(100).nullable(),
|
|
57068
|
+
/** Ms epoch when the slice was last updated (push or poll). */
|
|
57069
|
+
lastFetchedAt: number()
|
|
57070
|
+
});
|
|
57071
|
+
DeviceType.Thermostat;
|
|
56927
57072
|
object({
|
|
56928
57073
|
/** Whether the humidifier is currently on. */
|
|
56929
57074
|
on: boolean(),
|
|
@@ -64109,7 +64254,7 @@ var AccessoryKind = {
|
|
|
64109
64254
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
64110
64255
|
};
|
|
64111
64256
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
64112
|
-
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
|
|
64257
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
64113
64258
|
new Set(Object.values(DeviceType));
|
|
64114
64259
|
Object.freeze({
|
|
64115
64260
|
"accessories.getStatus": {
|
|
@@ -66530,6 +66675,84 @@ Object.freeze({
|
|
|
66530
66675
|
addonId: null,
|
|
66531
66676
|
access: "view"
|
|
66532
66677
|
},
|
|
66678
|
+
"dishwasher.getStatus": {
|
|
66679
|
+
capName: "dishwasher",
|
|
66680
|
+
capScope: "device",
|
|
66681
|
+
addonId: null,
|
|
66682
|
+
access: "view"
|
|
66683
|
+
},
|
|
66684
|
+
"dishwasher.pause": {
|
|
66685
|
+
capName: "dishwasher",
|
|
66686
|
+
capScope: "device",
|
|
66687
|
+
addonId: null,
|
|
66688
|
+
access: "create"
|
|
66689
|
+
},
|
|
66690
|
+
"dishwasher.setChildLock": {
|
|
66691
|
+
capName: "dishwasher",
|
|
66692
|
+
capScope: "device",
|
|
66693
|
+
addonId: null,
|
|
66694
|
+
access: "create"
|
|
66695
|
+
},
|
|
66696
|
+
"dishwasher.setExtraDry": {
|
|
66697
|
+
capName: "dishwasher",
|
|
66698
|
+
capScope: "device",
|
|
66699
|
+
addonId: null,
|
|
66700
|
+
access: "create"
|
|
66701
|
+
},
|
|
66702
|
+
"dishwasher.setHalfLoad": {
|
|
66703
|
+
capName: "dishwasher",
|
|
66704
|
+
capScope: "device",
|
|
66705
|
+
addonId: null,
|
|
66706
|
+
access: "create"
|
|
66707
|
+
},
|
|
66708
|
+
"dishwasher.setHygienePlus": {
|
|
66709
|
+
capName: "dishwasher",
|
|
66710
|
+
capScope: "device",
|
|
66711
|
+
addonId: null,
|
|
66712
|
+
access: "create"
|
|
66713
|
+
},
|
|
66714
|
+
"dishwasher.setIntensiveZone": {
|
|
66715
|
+
capName: "dishwasher",
|
|
66716
|
+
capScope: "device",
|
|
66717
|
+
addonId: null,
|
|
66718
|
+
access: "create"
|
|
66719
|
+
},
|
|
66720
|
+
"dishwasher.setOption": {
|
|
66721
|
+
capName: "dishwasher",
|
|
66722
|
+
capScope: "device",
|
|
66723
|
+
addonId: null,
|
|
66724
|
+
access: "create"
|
|
66725
|
+
},
|
|
66726
|
+
"dishwasher.setPower": {
|
|
66727
|
+
capName: "dishwasher",
|
|
66728
|
+
capScope: "device",
|
|
66729
|
+
addonId: null,
|
|
66730
|
+
access: "create"
|
|
66731
|
+
},
|
|
66732
|
+
"dishwasher.setProgram": {
|
|
66733
|
+
capName: "dishwasher",
|
|
66734
|
+
capScope: "device",
|
|
66735
|
+
addonId: null,
|
|
66736
|
+
access: "create"
|
|
66737
|
+
},
|
|
66738
|
+
"dishwasher.setVarioSpeedPlus": {
|
|
66739
|
+
capName: "dishwasher",
|
|
66740
|
+
capScope: "device",
|
|
66741
|
+
addonId: null,
|
|
66742
|
+
access: "create"
|
|
66743
|
+
},
|
|
66744
|
+
"dishwasher.start": {
|
|
66745
|
+
capName: "dishwasher",
|
|
66746
|
+
capScope: "device",
|
|
66747
|
+
addonId: null,
|
|
66748
|
+
access: "create"
|
|
66749
|
+
},
|
|
66750
|
+
"dishwasher.stop": {
|
|
66751
|
+
capName: "dishwasher",
|
|
66752
|
+
capScope: "device",
|
|
66753
|
+
addonId: null,
|
|
66754
|
+
access: "create"
|
|
66755
|
+
},
|
|
66533
66756
|
"doorbell.getStatus": {
|
|
66534
66757
|
capName: "doorbell",
|
|
66535
66758
|
capScope: "device",
|
|
@@ -66740,6 +66963,12 @@ Object.freeze({
|
|
|
66740
66963
|
addonId: null,
|
|
66741
66964
|
access: "view"
|
|
66742
66965
|
},
|
|
66966
|
+
"heatingValve.getStatus": {
|
|
66967
|
+
capName: "heating-valve",
|
|
66968
|
+
capScope: "device",
|
|
66969
|
+
addonId: null,
|
|
66970
|
+
access: "view"
|
|
66971
|
+
},
|
|
66743
66972
|
"humidifier.getStatus": {
|
|
66744
66973
|
capName: "humidifier",
|
|
66745
66974
|
capScope: "device",
|
|
@@ -72327,7 +72556,7 @@ Object.freeze({
|
|
|
72327
72556
|
access: "create"
|
|
72328
72557
|
}
|
|
72329
72558
|
});
|
|
72330
|
-
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
|
|
72559
|
+
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
72331
72560
|
/**
|
|
72332
72561
|
* Heuristic check — `device.features?.includes(profile.when.hasFeature)`.
|
|
72333
72562
|
*/
|
|
@@ -73179,6 +73408,71 @@ Object.freeze({
|
|
|
73179
73408
|
form: "single",
|
|
73180
73409
|
optional: false
|
|
73181
73410
|
}],
|
|
73411
|
+
"dishwasher.getStatus": [{
|
|
73412
|
+
name: "deviceId",
|
|
73413
|
+
form: "single",
|
|
73414
|
+
optional: false
|
|
73415
|
+
}],
|
|
73416
|
+
"dishwasher.pause": [{
|
|
73417
|
+
name: "deviceId",
|
|
73418
|
+
form: "single",
|
|
73419
|
+
optional: false
|
|
73420
|
+
}],
|
|
73421
|
+
"dishwasher.setChildLock": [{
|
|
73422
|
+
name: "deviceId",
|
|
73423
|
+
form: "single",
|
|
73424
|
+
optional: false
|
|
73425
|
+
}],
|
|
73426
|
+
"dishwasher.setExtraDry": [{
|
|
73427
|
+
name: "deviceId",
|
|
73428
|
+
form: "single",
|
|
73429
|
+
optional: false
|
|
73430
|
+
}],
|
|
73431
|
+
"dishwasher.setHalfLoad": [{
|
|
73432
|
+
name: "deviceId",
|
|
73433
|
+
form: "single",
|
|
73434
|
+
optional: false
|
|
73435
|
+
}],
|
|
73436
|
+
"dishwasher.setHygienePlus": [{
|
|
73437
|
+
name: "deviceId",
|
|
73438
|
+
form: "single",
|
|
73439
|
+
optional: false
|
|
73440
|
+
}],
|
|
73441
|
+
"dishwasher.setIntensiveZone": [{
|
|
73442
|
+
name: "deviceId",
|
|
73443
|
+
form: "single",
|
|
73444
|
+
optional: false
|
|
73445
|
+
}],
|
|
73446
|
+
"dishwasher.setOption": [{
|
|
73447
|
+
name: "deviceId",
|
|
73448
|
+
form: "single",
|
|
73449
|
+
optional: false
|
|
73450
|
+
}],
|
|
73451
|
+
"dishwasher.setPower": [{
|
|
73452
|
+
name: "deviceId",
|
|
73453
|
+
form: "single",
|
|
73454
|
+
optional: false
|
|
73455
|
+
}],
|
|
73456
|
+
"dishwasher.setProgram": [{
|
|
73457
|
+
name: "deviceId",
|
|
73458
|
+
form: "single",
|
|
73459
|
+
optional: false
|
|
73460
|
+
}],
|
|
73461
|
+
"dishwasher.setVarioSpeedPlus": [{
|
|
73462
|
+
name: "deviceId",
|
|
73463
|
+
form: "single",
|
|
73464
|
+
optional: false
|
|
73465
|
+
}],
|
|
73466
|
+
"dishwasher.start": [{
|
|
73467
|
+
name: "deviceId",
|
|
73468
|
+
form: "single",
|
|
73469
|
+
optional: false
|
|
73470
|
+
}],
|
|
73471
|
+
"dishwasher.stop": [{
|
|
73472
|
+
name: "deviceId",
|
|
73473
|
+
form: "single",
|
|
73474
|
+
optional: false
|
|
73475
|
+
}],
|
|
73182
73476
|
"doorbell.getStatus": [{
|
|
73183
73477
|
name: "deviceId",
|
|
73184
73478
|
form: "single",
|
|
@@ -73248,6 +73542,11 @@ Object.freeze({
|
|
|
73248
73542
|
form: "single",
|
|
73249
73543
|
optional: false
|
|
73250
73544
|
}],
|
|
73545
|
+
"heatingValve.getStatus": [{
|
|
73546
|
+
name: "deviceId",
|
|
73547
|
+
form: "single",
|
|
73548
|
+
optional: false
|
|
73549
|
+
}],
|
|
73251
73550
|
"humidifier.getStatus": [{
|
|
73252
73551
|
name: "deviceId",
|
|
73253
73552
|
form: "single",
|
|
@@ -75071,6 +75370,103 @@ Object.freeze({
|
|
|
75071
75370
|
"network-access": "ingress",
|
|
75072
75371
|
"smtp-provider": "email"
|
|
75073
75372
|
});
|
|
75373
|
+
/** Width of a bucket the history store accepts. */
|
|
75374
|
+
var HISTORY_BUCKET_MS = 5 * 6e4;
|
|
75375
|
+
function bucketStartOf(at) {
|
|
75376
|
+
return Math.floor(at / HISTORY_BUCKET_MS) * HISTORY_BUCKET_MS;
|
|
75377
|
+
}
|
|
75378
|
+
function subjectId(subject) {
|
|
75379
|
+
return subject.kind === "device" ? `d:${subject.deviceId}` : `n:${subject.nodeId}`;
|
|
75380
|
+
}
|
|
75381
|
+
function seriesIdentity(key, subject, scope) {
|
|
75382
|
+
return `${key}\u0000${subjectId(subject)}\u0000${scope}`;
|
|
75383
|
+
}
|
|
75384
|
+
function toClosed(b) {
|
|
75385
|
+
return {
|
|
75386
|
+
key: b.key,
|
|
75387
|
+
subject: b.subject,
|
|
75388
|
+
scope: b.scope,
|
|
75389
|
+
bucketStart: b.bucketStart,
|
|
75390
|
+
samples: b.samples,
|
|
75391
|
+
sum: b.sum,
|
|
75392
|
+
min: b.min,
|
|
75393
|
+
max: b.max,
|
|
75394
|
+
last: b.last,
|
|
75395
|
+
lastTs: b.lastTs
|
|
75396
|
+
};
|
|
75397
|
+
}
|
|
75398
|
+
var BucketAccumulator = class {
|
|
75399
|
+
open = /* @__PURE__ */ new Map();
|
|
75400
|
+
requeued = /* @__PURE__ */ new Map();
|
|
75401
|
+
/** Add one observation. A non-finite value or timestamp is ignored (never counted as 0). */
|
|
75402
|
+
note(key, subject, scope, value, at) {
|
|
75403
|
+
if (!Number.isFinite(value) || !Number.isFinite(at)) return;
|
|
75404
|
+
const bucketStart = bucketStartOf(at);
|
|
75405
|
+
const id = `${seriesIdentity(key, subject, scope)}\u0000${bucketStart}`;
|
|
75406
|
+
const existing = this.open.get(id);
|
|
75407
|
+
if (existing === void 0) {
|
|
75408
|
+
this.open.set(id, {
|
|
75409
|
+
key,
|
|
75410
|
+
subject,
|
|
75411
|
+
scope,
|
|
75412
|
+
bucketStart,
|
|
75413
|
+
samples: 1,
|
|
75414
|
+
sum: value,
|
|
75415
|
+
min: value,
|
|
75416
|
+
max: value,
|
|
75417
|
+
last: value,
|
|
75418
|
+
lastTs: at
|
|
75419
|
+
});
|
|
75420
|
+
return;
|
|
75421
|
+
}
|
|
75422
|
+
existing.samples += 1;
|
|
75423
|
+
existing.sum += value;
|
|
75424
|
+
if (value < existing.min) existing.min = value;
|
|
75425
|
+
if (value > existing.max) existing.max = value;
|
|
75426
|
+
if (at >= existing.lastTs) {
|
|
75427
|
+
existing.last = value;
|
|
75428
|
+
existing.lastTs = at;
|
|
75429
|
+
}
|
|
75430
|
+
}
|
|
75431
|
+
/**
|
|
75432
|
+
* Buckets whose window ended at or before `now`, oldest first, requeued ones
|
|
75433
|
+
* included. They leave the accumulator: delivery is the caller's.
|
|
75434
|
+
*/
|
|
75435
|
+
takeClosed(now) {
|
|
75436
|
+
const out = [];
|
|
75437
|
+
for (const [id, bucket] of this.open) if (bucket.bucketStart + 3e5 <= now) {
|
|
75438
|
+
out.push(toClosed(bucket));
|
|
75439
|
+
this.open.delete(id);
|
|
75440
|
+
}
|
|
75441
|
+
for (const list of this.requeued.values()) out.push(...list);
|
|
75442
|
+
this.requeued.clear();
|
|
75443
|
+
return out.toSorted((a, b) => a.bucketStart - b.bucketStart);
|
|
75444
|
+
}
|
|
75445
|
+
/**
|
|
75446
|
+
* Put undelivered buckets back for the next `takeClosed`. Keeps the newest
|
|
75447
|
+
* {@link MAX_REQUEUED_BUCKETS_PER_SERIES} per series and returns the buckets
|
|
75448
|
+
* it dropped (empty when none).
|
|
75449
|
+
*/
|
|
75450
|
+
requeue(buckets) {
|
|
75451
|
+
const dropped = [];
|
|
75452
|
+
for (const bucket of buckets) {
|
|
75453
|
+
const id = seriesIdentity(bucket.key, bucket.subject, bucket.scope);
|
|
75454
|
+
const list = [...this.requeued.get(id) ?? [], bucket].toSorted((a, b) => a.bucketStart - b.bucketStart);
|
|
75455
|
+
while (list.length > 12) {
|
|
75456
|
+
const oldest = list.shift();
|
|
75457
|
+
if (oldest !== void 0) dropped.push(oldest);
|
|
75458
|
+
}
|
|
75459
|
+
this.requeued.set(id, list);
|
|
75460
|
+
}
|
|
75461
|
+
return dropped;
|
|
75462
|
+
}
|
|
75463
|
+
/** Buckets currently held (open plus requeued) — for a gauge in the producer's own status. */
|
|
75464
|
+
pendingBucketCount() {
|
|
75465
|
+
let n = this.open.size;
|
|
75466
|
+
for (const list of this.requeued.values()) n += list.length;
|
|
75467
|
+
return n;
|
|
75468
|
+
}
|
|
75469
|
+
};
|
|
75074
75470
|
DeviceType.Camera;
|
|
75075
75471
|
var G711_SCALE_CORRECTION_DB = {
|
|
75076
75472
|
PCMU: 20 * Math.log10(4),
|
|
@@ -88699,430 +89095,145 @@ var NodeStressController = class NodeStressController {
|
|
|
88699
89095
|
}
|
|
88700
89096
|
};
|
|
88701
89097
|
//#endregion
|
|
88702
|
-
//#region src/
|
|
88703
|
-
|
|
88704
|
-
|
|
88705
|
-
|
|
88706
|
-
|
|
88707
|
-
|
|
88708
|
-
|
|
88709
|
-
|
|
88710
|
-
|
|
88711
|
-
|
|
88712
|
-
|
|
88713
|
-
|
|
88714
|
-
|
|
88715
|
-
|
|
88716
|
-
|
|
88717
|
-
|
|
88718
|
-
|
|
88719
|
-
|
|
88720
|
-
|
|
88721
|
-
|
|
88722
|
-
|
|
88723
|
-
|
|
88724
|
-
];
|
|
88725
|
-
|
|
88726
|
-
|
|
88727
|
-
|
|
88728
|
-
|
|
88729
|
-
|
|
88730
|
-
|
|
88731
|
-
type: "TEXT"
|
|
88732
|
-
}),
|
|
88733
|
-
(
|
|
88734
|
-
/** Numeric mirror of `subject` for camera rows, so a per-camera question is
|
|
88735
|
-
* answered by an integer index — every log line and every query about a
|
|
88736
|
-
* device in this repo is keyed by the numeric id. `NULL` for node rows. */
|
|
88737
|
-
{
|
|
88738
|
-
name: "deviceId",
|
|
88739
|
-
type: "INTEGER"
|
|
88740
|
-
}),
|
|
88741
|
-
{
|
|
88742
|
-
name: "series",
|
|
88743
|
-
type: "TEXT"
|
|
88744
|
-
},
|
|
88745
|
-
(
|
|
88746
|
-
/** Sub-scope within a series: a zoneId for occupancy, `''` otherwise. */
|
|
88747
|
-
{
|
|
88748
|
-
name: "scope",
|
|
88749
|
-
type: "TEXT"
|
|
88750
|
-
}),
|
|
88751
|
-
(
|
|
88752
|
-
/** Bucket start, wall-clock aligned to {@link LTS_BUCKET_MS}. */
|
|
88753
|
-
{
|
|
88754
|
-
name: "bucketStart",
|
|
88755
|
-
type: "INTEGER"
|
|
88756
|
-
}),
|
|
89098
|
+
//#region src/node-stress-history-producer.ts
|
|
89099
|
+
var SERIES_KEYS = {
|
|
89100
|
+
"node-score": "addon:pipeline-orchestrator/node-score",
|
|
89101
|
+
"node-queue-pressure": "addon:pipeline-orchestrator/node-queue-pressure",
|
|
89102
|
+
"node-drop-ratio": "addon:pipeline-orchestrator/node-drop-ratio",
|
|
89103
|
+
"node-fps-deficit": "addon:pipeline-orchestrator/node-fps-deficit"
|
|
89104
|
+
};
|
|
89105
|
+
function nodeStressHistoryClient(api) {
|
|
89106
|
+
return {
|
|
89107
|
+
declareSeries: (input) => api.declareSeries.mutate(input),
|
|
89108
|
+
recordBuckets: (input) => api.recordBuckets.mutate({ buckets: [...input.buckets] }),
|
|
89109
|
+
queryNode: async (input) => {
|
|
89110
|
+
return { series: (await api.queryNode.query(input)).series.map((s) => ({
|
|
89111
|
+
scope: s.scope,
|
|
89112
|
+
points: s.points.flatMap((p) => {
|
|
89113
|
+
if (p.mean === null) return [];
|
|
89114
|
+
return [{
|
|
89115
|
+
t: p.t,
|
|
89116
|
+
samples: p.samples,
|
|
89117
|
+
sum: p.mean * p.samples,
|
|
89118
|
+
min: p.min,
|
|
89119
|
+
max: p.max
|
|
89120
|
+
}];
|
|
89121
|
+
})
|
|
89122
|
+
})) };
|
|
89123
|
+
}
|
|
89124
|
+
};
|
|
89125
|
+
}
|
|
89126
|
+
var SERIES_META = [
|
|
88757
89127
|
{
|
|
88758
|
-
name: "
|
|
88759
|
-
|
|
88760
|
-
notNull: true
|
|
89128
|
+
name: "node-score",
|
|
89129
|
+
displayName: "Node stress score"
|
|
88761
89130
|
},
|
|
88762
89131
|
{
|
|
88763
|
-
name: "
|
|
88764
|
-
|
|
88765
|
-
notNull: true
|
|
89132
|
+
name: "node-queue-pressure",
|
|
89133
|
+
displayName: "Node queue pressure"
|
|
88766
89134
|
},
|
|
88767
89135
|
{
|
|
88768
|
-
name: "
|
|
88769
|
-
|
|
88770
|
-
notNull: true
|
|
89136
|
+
name: "node-drop-ratio",
|
|
89137
|
+
displayName: "Node drop ratio"
|
|
88771
89138
|
},
|
|
88772
89139
|
{
|
|
88773
|
-
name: "
|
|
88774
|
-
|
|
88775
|
-
notNull: true
|
|
89140
|
+
name: "node-fps-deficit",
|
|
89141
|
+
displayName: "Node FPS deficit"
|
|
88776
89142
|
}
|
|
88777
89143
|
];
|
|
88778
|
-
|
|
88779
|
-
|
|
88780
|
-
|
|
88781
|
-
|
|
88782
|
-
|
|
88783
|
-
|
|
88784
|
-
|
|
88785
|
-
|
|
88786
|
-
columns: ["series", "bucketStart"]
|
|
88787
|
-
}];
|
|
88788
|
-
function ltsBucketStart(at, bucketMs = LTS_BUCKET_MS) {
|
|
88789
|
-
return Math.floor(at / bucketMs) * bucketMs;
|
|
88790
|
-
}
|
|
88791
|
-
var LtsAggregator = class {
|
|
88792
|
-
open = /* @__PURE__ */ new Map();
|
|
88793
|
-
/** Every (subject, series, scope) that has produced a row in this process —
|
|
88794
|
-
* the groups the cap sweep has any reason to look at. */
|
|
88795
|
-
groups = /* @__PURE__ */ new Set();
|
|
88796
|
-
lastCapSweepAt = 0;
|
|
88797
|
-
collection;
|
|
88798
|
-
store;
|
|
89144
|
+
function refusalCounts(result) {
|
|
89145
|
+
const counts = {};
|
|
89146
|
+
for (const r of result.refused) counts[r.reason] = (counts[r.reason] ?? 0) + r.count;
|
|
89147
|
+
return counts;
|
|
89148
|
+
}
|
|
89149
|
+
var NodeStressHistoryProducer = class {
|
|
89150
|
+
accum = new BucketAccumulator();
|
|
89151
|
+
deviceHistory;
|
|
88799
89152
|
logger;
|
|
88800
89153
|
nowFn;
|
|
88801
|
-
|
|
88802
|
-
maxRows;
|
|
89154
|
+
declared = false;
|
|
88803
89155
|
constructor(deps) {
|
|
88804
|
-
this.
|
|
88805
|
-
this.store = deps.store;
|
|
89156
|
+
this.deviceHistory = deps.deviceHistory;
|
|
88806
89157
|
this.logger = deps.logger;
|
|
88807
89158
|
this.nowFn = deps.now ?? (() => Date.now());
|
|
88808
|
-
this.bucketMs = deps.bucketMs ?? 3e5;
|
|
88809
|
-
this.maxRows = deps.maxRowsPerSeries ?? 105120;
|
|
88810
|
-
}
|
|
88811
|
-
static declare(store, collection) {
|
|
88812
|
-
return store.declareCollection.mutate({
|
|
88813
|
-
collection,
|
|
88814
|
-
columns: [...LTS_COLUMNS],
|
|
88815
|
-
primaryKey: [...LTS_KEY_COLUMNS],
|
|
88816
|
-
withoutRowid: true,
|
|
88817
|
-
indexes: [...LTS_INDEXES]
|
|
88818
|
-
});
|
|
88819
89159
|
}
|
|
88820
|
-
|
|
88821
|
-
|
|
88822
|
-
|
|
88823
|
-
|
|
88824
|
-
|
|
88825
|
-
|
|
88826
|
-
|
|
88827
|
-
|
|
88828
|
-
|
|
88829
|
-
|
|
88830
|
-
note(input) {
|
|
88831
|
-
if (!Number.isFinite(input.value)) return;
|
|
88832
|
-
const at = input.at ?? this.nowFn();
|
|
88833
|
-
const scope = input.scope ?? "";
|
|
88834
|
-
const bucketStart = ltsBucketStart(at, this.bucketMs);
|
|
88835
|
-
const key = rowId(input.subject, input.series, scope, bucketStart);
|
|
88836
|
-
const held = this.open.get(key);
|
|
88837
|
-
if (held === void 0) {
|
|
88838
|
-
this.open.set(key, {
|
|
88839
|
-
subject: input.subject,
|
|
88840
|
-
...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {},
|
|
88841
|
-
series: input.series,
|
|
88842
|
-
scope,
|
|
88843
|
-
bucketStart,
|
|
88844
|
-
samples: 1,
|
|
88845
|
-
sum: input.value,
|
|
88846
|
-
min: input.value,
|
|
88847
|
-
max: input.value
|
|
88848
|
-
});
|
|
88849
|
-
return;
|
|
88850
|
-
}
|
|
88851
|
-
held.samples += 1;
|
|
88852
|
-
held.sum += input.value;
|
|
88853
|
-
if (input.value < held.min) held.min = input.value;
|
|
88854
|
-
if (input.value > held.max) held.max = input.value;
|
|
88855
|
-
}
|
|
88856
|
-
/** Buckets currently accumulating — diagnostics, and what a flush would write. */
|
|
88857
|
-
openBuckets() {
|
|
88858
|
-
return [...this.open.values()].map(toRow);
|
|
88859
|
-
}
|
|
88860
|
-
/**
|
|
88861
|
-
* Write every bucket that has CLOSED (its window ended at or before `now`)
|
|
88862
|
-
* and drop it from RAM. Returns the number of rows written.
|
|
88863
|
-
*
|
|
88864
|
-
* The current bucket is deliberately left alone: writing it early would mean
|
|
88865
|
-
* rewriting it on the next tick, which turns one row into up to sixty and
|
|
88866
|
-
* offers every one of them to the checkpoint lottery (D96).
|
|
88867
|
-
*/
|
|
88868
|
-
async flushDue(now = this.nowFn()) {
|
|
88869
|
-
const currentBucket = ltsBucketStart(now, this.bucketMs);
|
|
88870
|
-
const due = [...this.open.values()].filter((b) => b.bucketStart < currentBucket);
|
|
88871
|
-
if (due.length === 0) {
|
|
88872
|
-
await this.maybeSweepCap(now);
|
|
88873
|
-
return 0;
|
|
88874
|
-
}
|
|
88875
|
-
let written = 0;
|
|
88876
|
-
for (const batch of chunk(due, FLUSH_BATCH)) {
|
|
88877
|
-
written += await this.writeBatch(batch);
|
|
88878
|
-
for (const bucket of batch) this.open.delete(rowId(bucket.subject, bucket.series, bucket.scope, bucket.bucketStart));
|
|
88879
|
-
}
|
|
88880
|
-
await this.maybeSweepCap(now);
|
|
88881
|
-
return written;
|
|
89160
|
+
async declare() {
|
|
89161
|
+
if (this.declared) return;
|
|
89162
|
+
for (const meta of SERIES_META) await this.deviceHistory.declareSeries({
|
|
89163
|
+
name: meta.name,
|
|
89164
|
+
subjectKind: "node",
|
|
89165
|
+
kind: "gauge",
|
|
89166
|
+
displayName: meta.displayName,
|
|
89167
|
+
ingest: "buckets"
|
|
89168
|
+
});
|
|
89169
|
+
this.declared = true;
|
|
88882
89170
|
}
|
|
88883
|
-
|
|
88884
|
-
|
|
88885
|
-
|
|
88886
|
-
|
|
88887
|
-
|
|
88888
|
-
|
|
89171
|
+
noteSignals(nodeId, signals, at) {
|
|
89172
|
+
const subject = {
|
|
89173
|
+
kind: "node",
|
|
89174
|
+
nodeId
|
|
89175
|
+
};
|
|
89176
|
+
this.accum.note(SERIES_KEYS["node-score"], subject, "", signals.score, at);
|
|
89177
|
+
this.accum.note(SERIES_KEYS["node-queue-pressure"], subject, "", signals.queuePressure, at);
|
|
89178
|
+
this.accum.note(SERIES_KEYS["node-drop-ratio"], subject, "", signals.dropRatio, at);
|
|
89179
|
+
this.accum.note(SERIES_KEYS["node-fps-deficit"], subject, "", signals.fpsDeficit, at);
|
|
89180
|
+
}
|
|
89181
|
+
async flushDue(now) {
|
|
89182
|
+
const closed = this.accum.takeClosed(now ?? this.nowFn());
|
|
89183
|
+
if (closed.length === 0) return 0;
|
|
88889
89184
|
try {
|
|
88890
|
-
await this.
|
|
88891
|
-
|
|
88892
|
-
|
|
88893
|
-
|
|
88894
|
-
|
|
88895
|
-
|
|
88896
|
-
for (const bucket of batch) written += await this.writeBatch([bucket]);
|
|
88897
|
-
return written;
|
|
88898
|
-
}
|
|
88899
|
-
const bucket = batch[0];
|
|
88900
|
-
this.logger.warn("lts bucket write failed — this interval will be missing", {
|
|
88901
|
-
...bucket?.deviceId !== void 0 ? { tags: { deviceId: bucket.deviceId } } : {},
|
|
88902
|
-
meta: {
|
|
88903
|
-
collection: this.collection,
|
|
88904
|
-
series: bucket?.series,
|
|
88905
|
-
subject: bucket?.subject,
|
|
88906
|
-
bucketStart: bucket?.bucketStart,
|
|
88907
|
-
error: String(err)
|
|
89185
|
+
await this.declare();
|
|
89186
|
+
const result = await this.deviceHistory.recordBuckets({ buckets: closed });
|
|
89187
|
+
if (result.refused.length > 0) {
|
|
89188
|
+
if (result.refused.some((r) => r.reason === "undeclared")) {
|
|
89189
|
+
this.declared = false;
|
|
89190
|
+
this.accum.requeue(closed);
|
|
88908
89191
|
}
|
|
88909
|
-
|
|
88910
|
-
|
|
88911
|
-
|
|
88912
|
-
|
|
88913
|
-
async upsert(batch) {
|
|
88914
|
-
await this.store.upsertMany.mutate({
|
|
88915
|
-
collection: this.collection,
|
|
88916
|
-
conflict: [...LTS_KEY_COLUMNS],
|
|
88917
|
-
records: batch.map((bucket) => ({ data: {
|
|
88918
|
-
subject: bucket.subject,
|
|
88919
|
-
deviceId: bucket.deviceId ?? null,
|
|
88920
|
-
series: bucket.series,
|
|
88921
|
-
scope: bucket.scope,
|
|
88922
|
-
bucketStart: bucket.bucketStart,
|
|
88923
|
-
samples: bucket.samples,
|
|
88924
|
-
sum: bucket.sum,
|
|
88925
|
-
min: bucket.min,
|
|
88926
|
-
max: bucket.max
|
|
88927
|
-
} }))
|
|
88928
|
-
});
|
|
88929
|
-
}
|
|
88930
|
-
/** Read closed buckets back. The read surface every chart will use. */
|
|
88931
|
-
async read(query = {}) {
|
|
88932
|
-
const where = {};
|
|
88933
|
-
if (query.series !== void 0) where["series"] = query.series;
|
|
88934
|
-
if (query.subject !== void 0) where["subject"] = query.subject;
|
|
88935
|
-
if (query.scope !== void 0) where["scope"] = query.scope;
|
|
88936
|
-
const records = await this.store.query.query({
|
|
88937
|
-
collection: this.collection,
|
|
88938
|
-
filter: {
|
|
88939
|
-
...Object.keys(where).length > 0 ? { where } : {},
|
|
88940
|
-
...query.from !== void 0 || query.to !== void 0 ? { whereBetween: { bucketStart: [query.from ?? 0, query.to ?? Number.MAX_SAFE_INTEGER] } } : {},
|
|
88941
|
-
orderBy: {
|
|
88942
|
-
field: "bucketStart",
|
|
88943
|
-
direction: "asc"
|
|
88944
|
-
},
|
|
88945
|
-
limit: query.limit ?? 5e3
|
|
88946
|
-
}
|
|
88947
|
-
});
|
|
88948
|
-
const rows = [];
|
|
88949
|
-
for (const record of records) {
|
|
88950
|
-
const row = recordToRow(record.data);
|
|
88951
|
-
if (row !== null) rows.push(row);
|
|
88952
|
-
}
|
|
88953
|
-
return rows;
|
|
88954
|
-
}
|
|
88955
|
-
/**
|
|
88956
|
-
* Enforce the per-(subject, series, scope) row cap, at most once every six
|
|
88957
|
-
* hours. Only groups this process has written to are examined: a group with
|
|
88958
|
-
* no new rows cannot have crossed a cap it was under.
|
|
88959
|
-
*/
|
|
88960
|
-
async maybeSweepCap(now) {
|
|
88961
|
-
if (now - this.lastCapSweepAt < CAP_SWEEP_INTERVAL_MS) return;
|
|
88962
|
-
this.lastCapSweepAt = now;
|
|
88963
|
-
for (const group of this.groups) {
|
|
88964
|
-
const [subject, series, scope] = group.split("\0");
|
|
88965
|
-
if (subject === void 0 || series === void 0 || scope === void 0) continue;
|
|
88966
|
-
const where = {
|
|
88967
|
-
subject,
|
|
88968
|
-
series,
|
|
88969
|
-
scope
|
|
88970
|
-
};
|
|
88971
|
-
try {
|
|
88972
|
-
const excess = await this.store.count.query({
|
|
88973
|
-
collection: this.collection,
|
|
88974
|
-
filter: { where }
|
|
88975
|
-
}) - this.maxRows;
|
|
88976
|
-
if (excess <= 0) continue;
|
|
88977
|
-
const cutoff = (await this.store.query.query({
|
|
88978
|
-
collection: this.collection,
|
|
88979
|
-
filter: {
|
|
88980
|
-
where,
|
|
88981
|
-
orderBy: {
|
|
88982
|
-
field: "bucketStart",
|
|
88983
|
-
direction: "asc"
|
|
88984
|
-
},
|
|
88985
|
-
limit: excess
|
|
88986
|
-
}
|
|
88987
|
-
})).at(-1)?.data["bucketStart"];
|
|
88988
|
-
if (typeof cutoff !== "number") continue;
|
|
88989
|
-
const { deleted } = await this.store.deleteWhere.mutate({
|
|
88990
|
-
collection: this.collection,
|
|
88991
|
-
filter: {
|
|
88992
|
-
where,
|
|
88993
|
-
whereBetween: { bucketStart: [0, cutoff] }
|
|
88994
|
-
}
|
|
88995
|
-
});
|
|
88996
|
-
this.logger.info("lts row cap enforced", { meta: {
|
|
88997
|
-
collection: this.collection,
|
|
88998
|
-
series,
|
|
88999
|
-
subject,
|
|
89000
|
-
deleted,
|
|
89001
|
-
cap: this.maxRows
|
|
89002
|
-
} });
|
|
89003
|
-
} catch (err) {
|
|
89004
|
-
this.logger.warn("lts row cap sweep failed — the series keeps growing this cycle", { meta: {
|
|
89005
|
-
collection: this.collection,
|
|
89006
|
-
series,
|
|
89007
|
-
subject,
|
|
89008
|
-
error: String(err)
|
|
89192
|
+
this.logger.warn("node-stress history buckets refused", { meta: {
|
|
89193
|
+
buckets: closed.length,
|
|
89194
|
+
accepted: result.accepted,
|
|
89195
|
+
refused: refusalCounts(result)
|
|
89009
89196
|
} });
|
|
89010
89197
|
}
|
|
89198
|
+
return result.accepted;
|
|
89199
|
+
} catch (err) {
|
|
89200
|
+
const dropped = this.accum.requeue(closed);
|
|
89201
|
+
this.logger.warn("node-stress history flush failed — requeued", { meta: {
|
|
89202
|
+
buckets: closed.length,
|
|
89203
|
+
dropped: dropped.length,
|
|
89204
|
+
error: err instanceof Error ? err.message : String(err)
|
|
89205
|
+
} });
|
|
89206
|
+
return 0;
|
|
89011
89207
|
}
|
|
89012
89208
|
}
|
|
89013
|
-
|
|
89014
|
-
|
|
89015
|
-
|
|
89016
|
-
|
|
89017
|
-
|
|
89018
|
-
|
|
89019
|
-
|
|
89020
|
-
|
|
89021
|
-
|
|
89022
|
-
|
|
89023
|
-
|
|
89024
|
-
}
|
|
89025
|
-
function toRow(bucket) {
|
|
89026
|
-
return {
|
|
89027
|
-
subject: bucket.subject,
|
|
89028
|
-
...bucket.deviceId !== void 0 ? { deviceId: bucket.deviceId } : {},
|
|
89029
|
-
series: bucket.series,
|
|
89030
|
-
scope: bucket.scope,
|
|
89031
|
-
bucketStart: bucket.bucketStart,
|
|
89032
|
-
samples: bucket.samples,
|
|
89033
|
-
sum: bucket.sum,
|
|
89034
|
-
min: bucket.min,
|
|
89035
|
-
max: bucket.max
|
|
89036
|
-
};
|
|
89037
|
-
}
|
|
89038
|
-
/** Structural validation on read. A malformed row is skipped, never charted. */
|
|
89039
|
-
function recordToRow(data) {
|
|
89040
|
-
const subject = data["subject"];
|
|
89041
|
-
const series = data["series"];
|
|
89042
|
-
const scope = data["scope"];
|
|
89043
|
-
if (typeof subject !== "string" || typeof series !== "string") return null;
|
|
89044
|
-
const bucketStart = Number(data["bucketStart"]);
|
|
89045
|
-
const samples = Number(data["samples"]);
|
|
89046
|
-
const sum = Number(data["sum"]);
|
|
89047
|
-
const min = Number(data["min"]);
|
|
89048
|
-
const max = Number(data["max"]);
|
|
89049
|
-
if (![
|
|
89050
|
-
bucketStart,
|
|
89051
|
-
samples,
|
|
89052
|
-
sum,
|
|
89053
|
-
min,
|
|
89054
|
-
max
|
|
89055
|
-
].every((n) => Number.isFinite(n))) return null;
|
|
89056
|
-
const rawDeviceId = data["deviceId"];
|
|
89057
|
-
const deviceId = typeof rawDeviceId === "number" && Number.isFinite(rawDeviceId) ? rawDeviceId : void 0;
|
|
89058
|
-
return {
|
|
89059
|
-
subject,
|
|
89060
|
-
...deviceId !== void 0 ? { deviceId } : {},
|
|
89061
|
-
series,
|
|
89062
|
-
scope: typeof scope === "string" ? scope : "",
|
|
89063
|
-
bucketStart,
|
|
89064
|
-
samples,
|
|
89065
|
-
sum,
|
|
89066
|
-
min,
|
|
89067
|
-
max
|
|
89068
|
-
};
|
|
89069
|
-
}
|
|
89070
|
-
//#endregion
|
|
89071
|
-
//#region src/node-stress-lts.ts
|
|
89072
|
-
/**
|
|
89073
|
-
* @durable class=ledger owner=pipeline-orchestrator
|
|
89074
|
-
* write="one row per (node, series, 5-min bucket), written ONCE when the bucket closes; a node reporting no samples writes nothing"
|
|
89075
|
-
* retention="row CAP per (subject, series, scope) — 105,120 rows ≈ one year of 5-minute buckets. Not an age sweep: an LTS row summarises an interval and has no owner to be orphaned from."
|
|
89076
|
-
*/
|
|
89077
|
-
var NODE_STRESS_LTS_COLLECTION = "pipeline-orchestrator:stats-5m-v2";
|
|
89078
|
-
var NodeStressLts = class {
|
|
89079
|
-
lts;
|
|
89080
|
-
constructor(deps) {
|
|
89081
|
-
this.lts = new LtsAggregator({
|
|
89082
|
-
collection: NODE_STRESS_LTS_COLLECTION,
|
|
89083
|
-
store: deps.store,
|
|
89084
|
-
logger: deps.logger,
|
|
89085
|
-
...deps.now !== void 0 ? { now: deps.now } : {}
|
|
89086
|
-
});
|
|
89087
|
-
}
|
|
89088
|
-
static declare(store) {
|
|
89089
|
-
return LtsAggregator.declare(store, NODE_STRESS_LTS_COLLECTION);
|
|
89090
|
-
}
|
|
89091
|
-
/** Fold one sweep's verdict for one node into the open buckets. */
|
|
89092
|
-
noteSignals(nodeId, signals, at) {
|
|
89093
|
-
this.lts.note({
|
|
89094
|
-
subject: nodeId,
|
|
89095
|
-
series: "node-score",
|
|
89096
|
-
value: signals.score,
|
|
89097
|
-
at
|
|
89098
|
-
});
|
|
89099
|
-
this.lts.note({
|
|
89100
|
-
subject: nodeId,
|
|
89101
|
-
series: "node-queue-pressure",
|
|
89102
|
-
value: signals.queuePressure,
|
|
89103
|
-
at
|
|
89104
|
-
});
|
|
89105
|
-
this.lts.note({
|
|
89106
|
-
subject: nodeId,
|
|
89107
|
-
series: "node-drop-ratio",
|
|
89108
|
-
value: signals.dropRatio,
|
|
89109
|
-
at
|
|
89209
|
+
async read(input) {
|
|
89210
|
+
const nodeId = input.subject;
|
|
89211
|
+
if (nodeId === void 0 || input.series === void 0) return [];
|
|
89212
|
+
const key = SERIES_KEYS[input.series];
|
|
89213
|
+
if (key === void 0) return [];
|
|
89214
|
+
const result = await this.deviceHistory.queryNode({
|
|
89215
|
+
nodeId,
|
|
89216
|
+
key,
|
|
89217
|
+
from: input.from ?? 0,
|
|
89218
|
+
to: input.to ?? Date.now(),
|
|
89219
|
+
resolution: "5m",
|
|
89220
|
+
...input.maxPoints !== void 0 ? { maxPoints: input.maxPoints } : {}
|
|
89110
89221
|
});
|
|
89111
|
-
|
|
89222
|
+
const rows = [];
|
|
89223
|
+
for (const s of result.series) for (const p of s.points) rows.push({
|
|
89112
89224
|
subject: nodeId,
|
|
89113
|
-
series:
|
|
89114
|
-
|
|
89115
|
-
|
|
89225
|
+
series: input.series,
|
|
89226
|
+
scope: s.scope,
|
|
89227
|
+
bucketStart: p.t,
|
|
89228
|
+
samples: p.samples,
|
|
89229
|
+
sum: p.sum,
|
|
89230
|
+
min: p.min,
|
|
89231
|
+
max: p.max
|
|
89116
89232
|
});
|
|
89117
|
-
|
|
89118
|
-
flushDue(now) {
|
|
89119
|
-
return this.lts.flushDue(now);
|
|
89120
|
-
}
|
|
89121
|
-
read(query) {
|
|
89122
|
-
return this.lts.read(query);
|
|
89233
|
+
return rows;
|
|
89123
89234
|
}
|
|
89124
89235
|
openBuckets() {
|
|
89125
|
-
return
|
|
89236
|
+
return [];
|
|
89126
89237
|
}
|
|
89127
89238
|
};
|
|
89128
89239
|
//#endregion
|
|
@@ -95073,9 +95184,9 @@ async function buildOrchestratorControllers(deps) {
|
|
|
95073
95184
|
kind: orchestratorRecords.kind(orchestratorRecordKinds["node-stress-moves"]),
|
|
95074
95185
|
logger: deps.ctx().logger.child("node-stress")
|
|
95075
95186
|
});
|
|
95076
|
-
const nodeStressLts = new
|
|
95077
|
-
|
|
95078
|
-
logger: deps.ctx().logger.child("node-stress-
|
|
95187
|
+
const nodeStressLts = new NodeStressHistoryProducer({
|
|
95188
|
+
deviceHistory: nodeStressHistoryClient(deps.ctx().api.deviceHistory),
|
|
95189
|
+
logger: deps.ctx().logger.child("node-stress-history")
|
|
95079
95190
|
});
|
|
95080
95191
|
const nodeStress = new NodeStressController({
|
|
95081
95192
|
ledger,
|
|
@@ -95093,7 +95204,7 @@ async function buildOrchestratorControllers(deps) {
|
|
|
95093
95204
|
await nodeStress.hydrate().catch((err) => {
|
|
95094
95205
|
deps.ctx().logger.warn("node-stress move history unavailable — this boot starts cold", { meta: { error: errMsg$2(err) } });
|
|
95095
95206
|
});
|
|
95096
|
-
await
|
|
95207
|
+
await nodeStressLts.declare().catch((err) => {
|
|
95097
95208
|
deps.ctx().logger.warn("node-stress statistics unavailable — no baseline this boot", { meta: { error: errMsg$2(err) } });
|
|
95098
95209
|
});
|
|
95099
95210
|
const nodeStressLtsTimer = setInterval(() => {
|
|
@@ -97804,7 +97915,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
97804
97915
|
/** Periodic auto-rebalance sweep timer (drift correction under hysteresis). */
|
|
97805
97916
|
autoRebalanceTimer = null;
|
|
97806
97917
|
/** Node-stress five-minute statistics + its flush timer (see
|
|
97807
|
-
* `node-stress-
|
|
97918
|
+
* `node-stress-history-producer.ts`). `observe` mode's first durable output. */
|
|
97808
97919
|
nodeStressLts = null;
|
|
97809
97920
|
nodeStressLtsTimer = null;
|
|
97810
97921
|
initTimestamp = 0;
|
|
@@ -99774,7 +99885,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
99774
99885
|
return this.isSessionCamera(deviceId) && !this.session.hasActiveSession(deviceId);
|
|
99775
99886
|
}
|
|
99776
99887
|
};
|
|
99777
|
-
/** The derived mean for one
|
|
99888
|
+
/** The derived mean for one closed bucket — see `node-stress-history-producer.ts`. */
|
|
99778
99889
|
function withStatsMean(row) {
|
|
99779
99890
|
return {
|
|
99780
99891
|
...row,
|