@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.mjs
CHANGED
|
@@ -5541,7 +5541,7 @@ var ZodIssueCode = {
|
|
|
5541
5541
|
var ZodFirstPartyTypeKind;
|
|
5542
5542
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5543
5543
|
//#endregion
|
|
5544
|
-
//#region ../types/dist/sleep-
|
|
5544
|
+
//#region ../types/dist/sleep-BegKjwUu.mjs
|
|
5545
5545
|
/**
|
|
5546
5546
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5547
5547
|
* window to float samples (D455).
|
|
@@ -6361,7 +6361,7 @@ async function writeMembers(ctx, children, incoming, stored, pathOf) {
|
|
|
6361
6361
|
for (const [member, node] of children) applyMember(out, member, await writeNode(ctx, node, incoming[member], stored[member], pathOf(member)), stored);
|
|
6362
6362
|
return out;
|
|
6363
6363
|
}
|
|
6364
|
-
function rowId
|
|
6364
|
+
function rowId(row, idKey) {
|
|
6365
6365
|
const raw = row[idKey];
|
|
6366
6366
|
if (typeof raw === "string" && raw.length > 0) return raw;
|
|
6367
6367
|
if (typeof raw === "number" && Number.isFinite(raw)) return String(raw);
|
|
@@ -6378,7 +6378,7 @@ async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
|
6378
6378
|
}
|
|
6379
6379
|
const storedById = /* @__PURE__ */ new Map();
|
|
6380
6380
|
for (const row of storedRows) {
|
|
6381
|
-
const id = rowId
|
|
6381
|
+
const id = rowId(row, node.idKey);
|
|
6382
6382
|
if (id !== null) storedById.set(id, row);
|
|
6383
6383
|
}
|
|
6384
6384
|
const kept = /* @__PURE__ */ new Set();
|
|
@@ -6388,13 +6388,13 @@ async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
|
6388
6388
|
rows.push(row);
|
|
6389
6389
|
continue;
|
|
6390
6390
|
}
|
|
6391
|
-
const id = rowId
|
|
6391
|
+
const id = rowId(row, node.idKey) ?? ctx.mintId();
|
|
6392
6392
|
kept.add(id);
|
|
6393
6393
|
const withId = {
|
|
6394
6394
|
...row,
|
|
6395
6395
|
[node.idKey]: row[node.idKey] ?? id
|
|
6396
6396
|
};
|
|
6397
|
-
if (rowId
|
|
6397
|
+
if (rowId(withId, node.idKey) === null) withId[node.idKey] = id;
|
|
6398
6398
|
const storedRow = storedById.get(id) ?? {};
|
|
6399
6399
|
rows.push(await writeMembers(ctx, node.item, withId, storedRow, (member) => arrayItemFieldPath(fieldPath, id, member)));
|
|
6400
6400
|
}
|
|
@@ -9299,7 +9299,7 @@ function sleep(ms) {
|
|
|
9299
9299
|
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
9300
9300
|
}
|
|
9301
9301
|
//#endregion
|
|
9302
|
-
//#region ../types/dist/err-msg
|
|
9302
|
+
//#region ../types/dist/err-msg-BXKzRBwg.mjs
|
|
9303
9303
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
9304
9304
|
DeviceType["Camera"] = "camera";
|
|
9305
9305
|
DeviceType["Hub"] = "hub";
|
|
@@ -9391,6 +9391,10 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
9391
9391
|
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
9392
9392
|
* integrations sharing the same food/desiccant/hopper surface. */
|
|
9393
9393
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
9394
|
+
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
9395
|
+
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
9396
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations. */
|
|
9397
|
+
DeviceType["Dishwasher"] = "dishwasher";
|
|
9394
9398
|
return DeviceType;
|
|
9395
9399
|
}({});
|
|
9396
9400
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -9648,7 +9652,7 @@ function errMsg$2(err) {
|
|
|
9648
9652
|
return String(err);
|
|
9649
9653
|
}
|
|
9650
9654
|
//#endregion
|
|
9651
|
-
//#region ../types/dist/composition-
|
|
9655
|
+
//#region ../types/dist/composition-CB6PMT9p.mjs
|
|
9652
9656
|
/**
|
|
9653
9657
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
9654
9658
|
*
|
|
@@ -14514,8 +14518,13 @@ var AlertSeveritySchema = _enum([
|
|
|
14514
14518
|
"info",
|
|
14515
14519
|
"success",
|
|
14516
14520
|
"warning",
|
|
14517
|
-
"error"
|
|
14521
|
+
"error",
|
|
14522
|
+
"critical"
|
|
14518
14523
|
]);
|
|
14524
|
+
var AlertActionSchema = object({
|
|
14525
|
+
label: string(),
|
|
14526
|
+
href: string().optional()
|
|
14527
|
+
});
|
|
14519
14528
|
var AlertStatusSchema = _enum([
|
|
14520
14529
|
"active",
|
|
14521
14530
|
"in-progress",
|
|
@@ -14533,6 +14542,7 @@ var AlertSchema = object({
|
|
|
14533
14542
|
severity: AlertSeveritySchema,
|
|
14534
14543
|
title: string(),
|
|
14535
14544
|
message: string(),
|
|
14545
|
+
action: AlertActionSchema.optional(),
|
|
14536
14546
|
status: AlertStatusSchema,
|
|
14537
14547
|
progress: number().optional(),
|
|
14538
14548
|
read: boolean(),
|
|
@@ -18715,7 +18725,11 @@ DeviceType.Hub, DeviceDiscoveryStatusSchema.extend({ lastFetchedAt: number().int
|
|
|
18715
18725
|
});
|
|
18716
18726
|
/**
|
|
18717
18727
|
* `device-adoption` — generic discovery + adoption surface,
|
|
18718
|
-
* system-scoped
|
|
18728
|
+
* system-scoped collection (one provider per integration addon), routed
|
|
18729
|
+
* by explicit `{ addonId }` on direct `deviceAdoption.*` calls — the same
|
|
18730
|
+
* pin model as `connection-test`. The admin UI keeps using
|
|
18731
|
+
* `deviceManager.adoption*` (which already threads `addonId`). The de-HA-ified
|
|
18732
|
+
* successor to `ha-discovery`:
|
|
18719
18733
|
* keyed by `integrationId` (the addon resolves integrationId → broker
|
|
18720
18734
|
* internally) rather than a connection-specific `brokerId`, and it
|
|
18721
18735
|
* REUSES the shared `DiscoveredChildDevice` candidate type from
|
|
@@ -55455,7 +55469,7 @@ var BatteryStatusSchema = object({
|
|
|
55455
55469
|
*/
|
|
55456
55470
|
binary: boolean().optional()
|
|
55457
55471
|
});
|
|
55458
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, method(object({
|
|
55472
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, method(object({
|
|
55459
55473
|
deviceId: number(),
|
|
55460
55474
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
55461
55475
|
timeoutMs: number().int().min(500).max(3e4).default(8e3)
|
|
@@ -56331,6 +56345,130 @@ object({
|
|
|
56331
56345
|
deviceId: number(),
|
|
56332
56346
|
status: DeviceStatusSchema
|
|
56333
56347
|
});
|
|
56348
|
+
/**
|
|
56349
|
+
* Smart-dishwasher cap — program lifecycle, door / remote-start gates,
|
|
56350
|
+
* consumable levels (salt, rinse aid) and common program options.
|
|
56351
|
+
*
|
|
56352
|
+
* Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
|
|
56353
|
+
* by any integration that exposes the same program / option surface.
|
|
56354
|
+
*
|
|
56355
|
+
* `kind: 'poll'` — cloud REST APIs typically have no push channel; the
|
|
56356
|
+
* provider refreshes the slice on an interval and eagerly after commands.
|
|
56357
|
+
*/
|
|
56358
|
+
var DishwasherStateSchema = _enum([
|
|
56359
|
+
"idle",
|
|
56360
|
+
"running",
|
|
56361
|
+
"paused",
|
|
56362
|
+
"finished",
|
|
56363
|
+
"error",
|
|
56364
|
+
"unavailable"
|
|
56365
|
+
]);
|
|
56366
|
+
var DishwasherConsumableLevelSchema = _enum([
|
|
56367
|
+
"ok",
|
|
56368
|
+
"low",
|
|
56369
|
+
"empty"
|
|
56370
|
+
]);
|
|
56371
|
+
object({
|
|
56372
|
+
state: DishwasherStateSchema,
|
|
56373
|
+
/** Active program id/name, or null when none selected / unknown. */
|
|
56374
|
+
program: string().nullable(),
|
|
56375
|
+
/** Program tokens the hardware accepts — drives the UI selector. */
|
|
56376
|
+
availablePrograms: array(string()),
|
|
56377
|
+
/** Minutes remaining on the active cycle, or null when not running. */
|
|
56378
|
+
remainingMinutes: number().int().nonnegative().nullable(),
|
|
56379
|
+
/** Cycle completion 0..100, or null when not applicable. */
|
|
56380
|
+
progressPercent: number().min(0).max(100).nullable(),
|
|
56381
|
+
/** True when the door is reported open. */
|
|
56382
|
+
doorOpen: boolean(),
|
|
56383
|
+
/** True when remote start is allowed (door closed, power on, etc.). */
|
|
56384
|
+
remoteStartAllowed: boolean(),
|
|
56385
|
+
/** Main power / switched-on state. */
|
|
56386
|
+
powerOn: boolean(),
|
|
56387
|
+
saltLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
56388
|
+
rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
56389
|
+
halfLoad: boolean(),
|
|
56390
|
+
hygienePlus: boolean(),
|
|
56391
|
+
/** Extra dry option when the appliance exposes it. */
|
|
56392
|
+
extraDry: boolean(),
|
|
56393
|
+
/** Intensive zone (lower basket) when the appliance exposes it. */
|
|
56394
|
+
intensiveZone: boolean(),
|
|
56395
|
+
/** VarioSpeed / VarioSpeed+ when the appliance exposes it. */
|
|
56396
|
+
varioSpeedPlus: boolean(),
|
|
56397
|
+
/** Child lock (controls disabled on the appliance). */
|
|
56398
|
+
childLock: boolean(),
|
|
56399
|
+
errorCode: number().nullable(),
|
|
56400
|
+
errorLabel: string().nullable(),
|
|
56401
|
+
lastFetchedAt: number()
|
|
56402
|
+
});
|
|
56403
|
+
DeviceType.Dishwasher, method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
56404
|
+
kind: "mutation",
|
|
56405
|
+
auth: "protected"
|
|
56406
|
+
}), method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
56407
|
+
kind: "mutation",
|
|
56408
|
+
auth: "protected"
|
|
56409
|
+
}), method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
56410
|
+
kind: "mutation",
|
|
56411
|
+
auth: "protected"
|
|
56412
|
+
}), method(object({
|
|
56413
|
+
deviceId: number().int().nonnegative(),
|
|
56414
|
+
program: string().min(1)
|
|
56415
|
+
}), _void(), {
|
|
56416
|
+
kind: "mutation",
|
|
56417
|
+
auth: "protected"
|
|
56418
|
+
}), method(object({
|
|
56419
|
+
deviceId: number().int().nonnegative(),
|
|
56420
|
+
on: boolean()
|
|
56421
|
+
}), _void(), {
|
|
56422
|
+
kind: "mutation",
|
|
56423
|
+
auth: "protected"
|
|
56424
|
+
}), method(object({
|
|
56425
|
+
deviceId: number().int().nonnegative(),
|
|
56426
|
+
on: boolean()
|
|
56427
|
+
}), _void(), {
|
|
56428
|
+
kind: "mutation",
|
|
56429
|
+
auth: "protected"
|
|
56430
|
+
}), method(object({
|
|
56431
|
+
deviceId: number().int().nonnegative(),
|
|
56432
|
+
on: boolean()
|
|
56433
|
+
}), _void(), {
|
|
56434
|
+
kind: "mutation",
|
|
56435
|
+
auth: "protected"
|
|
56436
|
+
}), method(object({
|
|
56437
|
+
deviceId: number().int().nonnegative(),
|
|
56438
|
+
on: boolean()
|
|
56439
|
+
}), _void(), {
|
|
56440
|
+
kind: "mutation",
|
|
56441
|
+
auth: "protected"
|
|
56442
|
+
}), method(object({
|
|
56443
|
+
deviceId: number().int().nonnegative(),
|
|
56444
|
+
on: boolean()
|
|
56445
|
+
}), _void(), {
|
|
56446
|
+
kind: "mutation",
|
|
56447
|
+
auth: "protected"
|
|
56448
|
+
}), method(object({
|
|
56449
|
+
deviceId: number().int().nonnegative(),
|
|
56450
|
+
on: boolean()
|
|
56451
|
+
}), _void(), {
|
|
56452
|
+
kind: "mutation",
|
|
56453
|
+
auth: "protected"
|
|
56454
|
+
}), method(object({
|
|
56455
|
+
deviceId: number().int().nonnegative(),
|
|
56456
|
+
on: boolean()
|
|
56457
|
+
}), _void(), {
|
|
56458
|
+
kind: "mutation",
|
|
56459
|
+
auth: "protected"
|
|
56460
|
+
}), method(object({
|
|
56461
|
+
deviceId: number().int().nonnegative(),
|
|
56462
|
+
key: string().min(1),
|
|
56463
|
+
value: union([
|
|
56464
|
+
boolean(),
|
|
56465
|
+
string(),
|
|
56466
|
+
number()
|
|
56467
|
+
])
|
|
56468
|
+
}), _void(), {
|
|
56469
|
+
kind: "mutation",
|
|
56470
|
+
auth: "protected"
|
|
56471
|
+
});
|
|
56334
56472
|
object({
|
|
56335
56473
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
56336
56474
|
lastPressedAt: number().nullable(),
|
|
@@ -56896,6 +57034,13 @@ object({
|
|
|
56896
57034
|
lastChangedAt: number()
|
|
56897
57035
|
});
|
|
56898
57036
|
DeviceType.Sensor;
|
|
57037
|
+
object({
|
|
57038
|
+
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
57039
|
+
position: number().min(0).max(100).nullable(),
|
|
57040
|
+
/** Ms epoch when the slice was last updated (push or poll). */
|
|
57041
|
+
lastFetchedAt: number()
|
|
57042
|
+
});
|
|
57043
|
+
DeviceType.Thermostat;
|
|
56899
57044
|
object({
|
|
56900
57045
|
/** Whether the humidifier is currently on. */
|
|
56901
57046
|
on: boolean(),
|
|
@@ -64081,7 +64226,7 @@ var AccessoryKind = {
|
|
|
64081
64226
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
64082
64227
|
};
|
|
64083
64228
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
64084
|
-
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;
|
|
64229
|
+
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;
|
|
64085
64230
|
new Set(Object.values(DeviceType));
|
|
64086
64231
|
Object.freeze({
|
|
64087
64232
|
"accessories.getStatus": {
|
|
@@ -66502,6 +66647,84 @@ Object.freeze({
|
|
|
66502
66647
|
addonId: null,
|
|
66503
66648
|
access: "view"
|
|
66504
66649
|
},
|
|
66650
|
+
"dishwasher.getStatus": {
|
|
66651
|
+
capName: "dishwasher",
|
|
66652
|
+
capScope: "device",
|
|
66653
|
+
addonId: null,
|
|
66654
|
+
access: "view"
|
|
66655
|
+
},
|
|
66656
|
+
"dishwasher.pause": {
|
|
66657
|
+
capName: "dishwasher",
|
|
66658
|
+
capScope: "device",
|
|
66659
|
+
addonId: null,
|
|
66660
|
+
access: "create"
|
|
66661
|
+
},
|
|
66662
|
+
"dishwasher.setChildLock": {
|
|
66663
|
+
capName: "dishwasher",
|
|
66664
|
+
capScope: "device",
|
|
66665
|
+
addonId: null,
|
|
66666
|
+
access: "create"
|
|
66667
|
+
},
|
|
66668
|
+
"dishwasher.setExtraDry": {
|
|
66669
|
+
capName: "dishwasher",
|
|
66670
|
+
capScope: "device",
|
|
66671
|
+
addonId: null,
|
|
66672
|
+
access: "create"
|
|
66673
|
+
},
|
|
66674
|
+
"dishwasher.setHalfLoad": {
|
|
66675
|
+
capName: "dishwasher",
|
|
66676
|
+
capScope: "device",
|
|
66677
|
+
addonId: null,
|
|
66678
|
+
access: "create"
|
|
66679
|
+
},
|
|
66680
|
+
"dishwasher.setHygienePlus": {
|
|
66681
|
+
capName: "dishwasher",
|
|
66682
|
+
capScope: "device",
|
|
66683
|
+
addonId: null,
|
|
66684
|
+
access: "create"
|
|
66685
|
+
},
|
|
66686
|
+
"dishwasher.setIntensiveZone": {
|
|
66687
|
+
capName: "dishwasher",
|
|
66688
|
+
capScope: "device",
|
|
66689
|
+
addonId: null,
|
|
66690
|
+
access: "create"
|
|
66691
|
+
},
|
|
66692
|
+
"dishwasher.setOption": {
|
|
66693
|
+
capName: "dishwasher",
|
|
66694
|
+
capScope: "device",
|
|
66695
|
+
addonId: null,
|
|
66696
|
+
access: "create"
|
|
66697
|
+
},
|
|
66698
|
+
"dishwasher.setPower": {
|
|
66699
|
+
capName: "dishwasher",
|
|
66700
|
+
capScope: "device",
|
|
66701
|
+
addonId: null,
|
|
66702
|
+
access: "create"
|
|
66703
|
+
},
|
|
66704
|
+
"dishwasher.setProgram": {
|
|
66705
|
+
capName: "dishwasher",
|
|
66706
|
+
capScope: "device",
|
|
66707
|
+
addonId: null,
|
|
66708
|
+
access: "create"
|
|
66709
|
+
},
|
|
66710
|
+
"dishwasher.setVarioSpeedPlus": {
|
|
66711
|
+
capName: "dishwasher",
|
|
66712
|
+
capScope: "device",
|
|
66713
|
+
addonId: null,
|
|
66714
|
+
access: "create"
|
|
66715
|
+
},
|
|
66716
|
+
"dishwasher.start": {
|
|
66717
|
+
capName: "dishwasher",
|
|
66718
|
+
capScope: "device",
|
|
66719
|
+
addonId: null,
|
|
66720
|
+
access: "create"
|
|
66721
|
+
},
|
|
66722
|
+
"dishwasher.stop": {
|
|
66723
|
+
capName: "dishwasher",
|
|
66724
|
+
capScope: "device",
|
|
66725
|
+
addonId: null,
|
|
66726
|
+
access: "create"
|
|
66727
|
+
},
|
|
66505
66728
|
"doorbell.getStatus": {
|
|
66506
66729
|
capName: "doorbell",
|
|
66507
66730
|
capScope: "device",
|
|
@@ -66712,6 +66935,12 @@ Object.freeze({
|
|
|
66712
66935
|
addonId: null,
|
|
66713
66936
|
access: "view"
|
|
66714
66937
|
},
|
|
66938
|
+
"heatingValve.getStatus": {
|
|
66939
|
+
capName: "heating-valve",
|
|
66940
|
+
capScope: "device",
|
|
66941
|
+
addonId: null,
|
|
66942
|
+
access: "view"
|
|
66943
|
+
},
|
|
66715
66944
|
"humidifier.getStatus": {
|
|
66716
66945
|
capName: "humidifier",
|
|
66717
66946
|
capScope: "device",
|
|
@@ -72299,7 +72528,7 @@ Object.freeze({
|
|
|
72299
72528
|
access: "create"
|
|
72300
72529
|
}
|
|
72301
72530
|
});
|
|
72302
|
-
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;
|
|
72531
|
+
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;
|
|
72303
72532
|
/**
|
|
72304
72533
|
* Heuristic check — `device.features?.includes(profile.when.hasFeature)`.
|
|
72305
72534
|
*/
|
|
@@ -73151,6 +73380,71 @@ Object.freeze({
|
|
|
73151
73380
|
form: "single",
|
|
73152
73381
|
optional: false
|
|
73153
73382
|
}],
|
|
73383
|
+
"dishwasher.getStatus": [{
|
|
73384
|
+
name: "deviceId",
|
|
73385
|
+
form: "single",
|
|
73386
|
+
optional: false
|
|
73387
|
+
}],
|
|
73388
|
+
"dishwasher.pause": [{
|
|
73389
|
+
name: "deviceId",
|
|
73390
|
+
form: "single",
|
|
73391
|
+
optional: false
|
|
73392
|
+
}],
|
|
73393
|
+
"dishwasher.setChildLock": [{
|
|
73394
|
+
name: "deviceId",
|
|
73395
|
+
form: "single",
|
|
73396
|
+
optional: false
|
|
73397
|
+
}],
|
|
73398
|
+
"dishwasher.setExtraDry": [{
|
|
73399
|
+
name: "deviceId",
|
|
73400
|
+
form: "single",
|
|
73401
|
+
optional: false
|
|
73402
|
+
}],
|
|
73403
|
+
"dishwasher.setHalfLoad": [{
|
|
73404
|
+
name: "deviceId",
|
|
73405
|
+
form: "single",
|
|
73406
|
+
optional: false
|
|
73407
|
+
}],
|
|
73408
|
+
"dishwasher.setHygienePlus": [{
|
|
73409
|
+
name: "deviceId",
|
|
73410
|
+
form: "single",
|
|
73411
|
+
optional: false
|
|
73412
|
+
}],
|
|
73413
|
+
"dishwasher.setIntensiveZone": [{
|
|
73414
|
+
name: "deviceId",
|
|
73415
|
+
form: "single",
|
|
73416
|
+
optional: false
|
|
73417
|
+
}],
|
|
73418
|
+
"dishwasher.setOption": [{
|
|
73419
|
+
name: "deviceId",
|
|
73420
|
+
form: "single",
|
|
73421
|
+
optional: false
|
|
73422
|
+
}],
|
|
73423
|
+
"dishwasher.setPower": [{
|
|
73424
|
+
name: "deviceId",
|
|
73425
|
+
form: "single",
|
|
73426
|
+
optional: false
|
|
73427
|
+
}],
|
|
73428
|
+
"dishwasher.setProgram": [{
|
|
73429
|
+
name: "deviceId",
|
|
73430
|
+
form: "single",
|
|
73431
|
+
optional: false
|
|
73432
|
+
}],
|
|
73433
|
+
"dishwasher.setVarioSpeedPlus": [{
|
|
73434
|
+
name: "deviceId",
|
|
73435
|
+
form: "single",
|
|
73436
|
+
optional: false
|
|
73437
|
+
}],
|
|
73438
|
+
"dishwasher.start": [{
|
|
73439
|
+
name: "deviceId",
|
|
73440
|
+
form: "single",
|
|
73441
|
+
optional: false
|
|
73442
|
+
}],
|
|
73443
|
+
"dishwasher.stop": [{
|
|
73444
|
+
name: "deviceId",
|
|
73445
|
+
form: "single",
|
|
73446
|
+
optional: false
|
|
73447
|
+
}],
|
|
73154
73448
|
"doorbell.getStatus": [{
|
|
73155
73449
|
name: "deviceId",
|
|
73156
73450
|
form: "single",
|
|
@@ -73220,6 +73514,11 @@ Object.freeze({
|
|
|
73220
73514
|
form: "single",
|
|
73221
73515
|
optional: false
|
|
73222
73516
|
}],
|
|
73517
|
+
"heatingValve.getStatus": [{
|
|
73518
|
+
name: "deviceId",
|
|
73519
|
+
form: "single",
|
|
73520
|
+
optional: false
|
|
73521
|
+
}],
|
|
73223
73522
|
"humidifier.getStatus": [{
|
|
73224
73523
|
name: "deviceId",
|
|
73225
73524
|
form: "single",
|
|
@@ -75043,6 +75342,103 @@ Object.freeze({
|
|
|
75043
75342
|
"network-access": "ingress",
|
|
75044
75343
|
"smtp-provider": "email"
|
|
75045
75344
|
});
|
|
75345
|
+
/** Width of a bucket the history store accepts. */
|
|
75346
|
+
var HISTORY_BUCKET_MS = 5 * 6e4;
|
|
75347
|
+
function bucketStartOf(at) {
|
|
75348
|
+
return Math.floor(at / HISTORY_BUCKET_MS) * HISTORY_BUCKET_MS;
|
|
75349
|
+
}
|
|
75350
|
+
function subjectId(subject) {
|
|
75351
|
+
return subject.kind === "device" ? `d:${subject.deviceId}` : `n:${subject.nodeId}`;
|
|
75352
|
+
}
|
|
75353
|
+
function seriesIdentity(key, subject, scope) {
|
|
75354
|
+
return `${key}\u0000${subjectId(subject)}\u0000${scope}`;
|
|
75355
|
+
}
|
|
75356
|
+
function toClosed(b) {
|
|
75357
|
+
return {
|
|
75358
|
+
key: b.key,
|
|
75359
|
+
subject: b.subject,
|
|
75360
|
+
scope: b.scope,
|
|
75361
|
+
bucketStart: b.bucketStart,
|
|
75362
|
+
samples: b.samples,
|
|
75363
|
+
sum: b.sum,
|
|
75364
|
+
min: b.min,
|
|
75365
|
+
max: b.max,
|
|
75366
|
+
last: b.last,
|
|
75367
|
+
lastTs: b.lastTs
|
|
75368
|
+
};
|
|
75369
|
+
}
|
|
75370
|
+
var BucketAccumulator = class {
|
|
75371
|
+
open = /* @__PURE__ */ new Map();
|
|
75372
|
+
requeued = /* @__PURE__ */ new Map();
|
|
75373
|
+
/** Add one observation. A non-finite value or timestamp is ignored (never counted as 0). */
|
|
75374
|
+
note(key, subject, scope, value, at) {
|
|
75375
|
+
if (!Number.isFinite(value) || !Number.isFinite(at)) return;
|
|
75376
|
+
const bucketStart = bucketStartOf(at);
|
|
75377
|
+
const id = `${seriesIdentity(key, subject, scope)}\u0000${bucketStart}`;
|
|
75378
|
+
const existing = this.open.get(id);
|
|
75379
|
+
if (existing === void 0) {
|
|
75380
|
+
this.open.set(id, {
|
|
75381
|
+
key,
|
|
75382
|
+
subject,
|
|
75383
|
+
scope,
|
|
75384
|
+
bucketStart,
|
|
75385
|
+
samples: 1,
|
|
75386
|
+
sum: value,
|
|
75387
|
+
min: value,
|
|
75388
|
+
max: value,
|
|
75389
|
+
last: value,
|
|
75390
|
+
lastTs: at
|
|
75391
|
+
});
|
|
75392
|
+
return;
|
|
75393
|
+
}
|
|
75394
|
+
existing.samples += 1;
|
|
75395
|
+
existing.sum += value;
|
|
75396
|
+
if (value < existing.min) existing.min = value;
|
|
75397
|
+
if (value > existing.max) existing.max = value;
|
|
75398
|
+
if (at >= existing.lastTs) {
|
|
75399
|
+
existing.last = value;
|
|
75400
|
+
existing.lastTs = at;
|
|
75401
|
+
}
|
|
75402
|
+
}
|
|
75403
|
+
/**
|
|
75404
|
+
* Buckets whose window ended at or before `now`, oldest first, requeued ones
|
|
75405
|
+
* included. They leave the accumulator: delivery is the caller's.
|
|
75406
|
+
*/
|
|
75407
|
+
takeClosed(now) {
|
|
75408
|
+
const out = [];
|
|
75409
|
+
for (const [id, bucket] of this.open) if (bucket.bucketStart + 3e5 <= now) {
|
|
75410
|
+
out.push(toClosed(bucket));
|
|
75411
|
+
this.open.delete(id);
|
|
75412
|
+
}
|
|
75413
|
+
for (const list of this.requeued.values()) out.push(...list);
|
|
75414
|
+
this.requeued.clear();
|
|
75415
|
+
return out.toSorted((a, b) => a.bucketStart - b.bucketStart);
|
|
75416
|
+
}
|
|
75417
|
+
/**
|
|
75418
|
+
* Put undelivered buckets back for the next `takeClosed`. Keeps the newest
|
|
75419
|
+
* {@link MAX_REQUEUED_BUCKETS_PER_SERIES} per series and returns the buckets
|
|
75420
|
+
* it dropped (empty when none).
|
|
75421
|
+
*/
|
|
75422
|
+
requeue(buckets) {
|
|
75423
|
+
const dropped = [];
|
|
75424
|
+
for (const bucket of buckets) {
|
|
75425
|
+
const id = seriesIdentity(bucket.key, bucket.subject, bucket.scope);
|
|
75426
|
+
const list = [...this.requeued.get(id) ?? [], bucket].toSorted((a, b) => a.bucketStart - b.bucketStart);
|
|
75427
|
+
while (list.length > 12) {
|
|
75428
|
+
const oldest = list.shift();
|
|
75429
|
+
if (oldest !== void 0) dropped.push(oldest);
|
|
75430
|
+
}
|
|
75431
|
+
this.requeued.set(id, list);
|
|
75432
|
+
}
|
|
75433
|
+
return dropped;
|
|
75434
|
+
}
|
|
75435
|
+
/** Buckets currently held (open plus requeued) — for a gauge in the producer's own status. */
|
|
75436
|
+
pendingBucketCount() {
|
|
75437
|
+
let n = this.open.size;
|
|
75438
|
+
for (const list of this.requeued.values()) n += list.length;
|
|
75439
|
+
return n;
|
|
75440
|
+
}
|
|
75441
|
+
};
|
|
75046
75442
|
DeviceType.Camera;
|
|
75047
75443
|
var G711_SCALE_CORRECTION_DB = {
|
|
75048
75444
|
PCMU: 20 * Math.log10(4),
|
|
@@ -88671,430 +89067,145 @@ var NodeStressController = class NodeStressController {
|
|
|
88671
89067
|
}
|
|
88672
89068
|
};
|
|
88673
89069
|
//#endregion
|
|
88674
|
-
//#region src/
|
|
88675
|
-
|
|
88676
|
-
|
|
88677
|
-
|
|
88678
|
-
|
|
88679
|
-
|
|
88680
|
-
|
|
88681
|
-
|
|
88682
|
-
|
|
88683
|
-
|
|
88684
|
-
|
|
88685
|
-
|
|
88686
|
-
|
|
88687
|
-
|
|
88688
|
-
|
|
88689
|
-
|
|
88690
|
-
|
|
88691
|
-
|
|
88692
|
-
|
|
88693
|
-
|
|
88694
|
-
|
|
88695
|
-
|
|
88696
|
-
];
|
|
88697
|
-
|
|
88698
|
-
|
|
88699
|
-
|
|
88700
|
-
|
|
88701
|
-
|
|
88702
|
-
|
|
88703
|
-
type: "TEXT"
|
|
88704
|
-
}),
|
|
88705
|
-
(
|
|
88706
|
-
/** Numeric mirror of `subject` for camera rows, so a per-camera question is
|
|
88707
|
-
* answered by an integer index — every log line and every query about a
|
|
88708
|
-
* device in this repo is keyed by the numeric id. `NULL` for node rows. */
|
|
88709
|
-
{
|
|
88710
|
-
name: "deviceId",
|
|
88711
|
-
type: "INTEGER"
|
|
88712
|
-
}),
|
|
88713
|
-
{
|
|
88714
|
-
name: "series",
|
|
88715
|
-
type: "TEXT"
|
|
88716
|
-
},
|
|
88717
|
-
(
|
|
88718
|
-
/** Sub-scope within a series: a zoneId for occupancy, `''` otherwise. */
|
|
88719
|
-
{
|
|
88720
|
-
name: "scope",
|
|
88721
|
-
type: "TEXT"
|
|
88722
|
-
}),
|
|
88723
|
-
(
|
|
88724
|
-
/** Bucket start, wall-clock aligned to {@link LTS_BUCKET_MS}. */
|
|
88725
|
-
{
|
|
88726
|
-
name: "bucketStart",
|
|
88727
|
-
type: "INTEGER"
|
|
88728
|
-
}),
|
|
89070
|
+
//#region src/node-stress-history-producer.ts
|
|
89071
|
+
var SERIES_KEYS = {
|
|
89072
|
+
"node-score": "addon:pipeline-orchestrator/node-score",
|
|
89073
|
+
"node-queue-pressure": "addon:pipeline-orchestrator/node-queue-pressure",
|
|
89074
|
+
"node-drop-ratio": "addon:pipeline-orchestrator/node-drop-ratio",
|
|
89075
|
+
"node-fps-deficit": "addon:pipeline-orchestrator/node-fps-deficit"
|
|
89076
|
+
};
|
|
89077
|
+
function nodeStressHistoryClient(api) {
|
|
89078
|
+
return {
|
|
89079
|
+
declareSeries: (input) => api.declareSeries.mutate(input),
|
|
89080
|
+
recordBuckets: (input) => api.recordBuckets.mutate({ buckets: [...input.buckets] }),
|
|
89081
|
+
queryNode: async (input) => {
|
|
89082
|
+
return { series: (await api.queryNode.query(input)).series.map((s) => ({
|
|
89083
|
+
scope: s.scope,
|
|
89084
|
+
points: s.points.flatMap((p) => {
|
|
89085
|
+
if (p.mean === null) return [];
|
|
89086
|
+
return [{
|
|
89087
|
+
t: p.t,
|
|
89088
|
+
samples: p.samples,
|
|
89089
|
+
sum: p.mean * p.samples,
|
|
89090
|
+
min: p.min,
|
|
89091
|
+
max: p.max
|
|
89092
|
+
}];
|
|
89093
|
+
})
|
|
89094
|
+
})) };
|
|
89095
|
+
}
|
|
89096
|
+
};
|
|
89097
|
+
}
|
|
89098
|
+
var SERIES_META = [
|
|
88729
89099
|
{
|
|
88730
|
-
name: "
|
|
88731
|
-
|
|
88732
|
-
notNull: true
|
|
89100
|
+
name: "node-score",
|
|
89101
|
+
displayName: "Node stress score"
|
|
88733
89102
|
},
|
|
88734
89103
|
{
|
|
88735
|
-
name: "
|
|
88736
|
-
|
|
88737
|
-
notNull: true
|
|
89104
|
+
name: "node-queue-pressure",
|
|
89105
|
+
displayName: "Node queue pressure"
|
|
88738
89106
|
},
|
|
88739
89107
|
{
|
|
88740
|
-
name: "
|
|
88741
|
-
|
|
88742
|
-
notNull: true
|
|
89108
|
+
name: "node-drop-ratio",
|
|
89109
|
+
displayName: "Node drop ratio"
|
|
88743
89110
|
},
|
|
88744
89111
|
{
|
|
88745
|
-
name: "
|
|
88746
|
-
|
|
88747
|
-
notNull: true
|
|
89112
|
+
name: "node-fps-deficit",
|
|
89113
|
+
displayName: "Node FPS deficit"
|
|
88748
89114
|
}
|
|
88749
89115
|
];
|
|
88750
|
-
|
|
88751
|
-
|
|
88752
|
-
|
|
88753
|
-
|
|
88754
|
-
|
|
88755
|
-
|
|
88756
|
-
|
|
88757
|
-
|
|
88758
|
-
columns: ["series", "bucketStart"]
|
|
88759
|
-
}];
|
|
88760
|
-
function ltsBucketStart(at, bucketMs = LTS_BUCKET_MS) {
|
|
88761
|
-
return Math.floor(at / bucketMs) * bucketMs;
|
|
88762
|
-
}
|
|
88763
|
-
var LtsAggregator = class {
|
|
88764
|
-
open = /* @__PURE__ */ new Map();
|
|
88765
|
-
/** Every (subject, series, scope) that has produced a row in this process —
|
|
88766
|
-
* the groups the cap sweep has any reason to look at. */
|
|
88767
|
-
groups = /* @__PURE__ */ new Set();
|
|
88768
|
-
lastCapSweepAt = 0;
|
|
88769
|
-
collection;
|
|
88770
|
-
store;
|
|
89116
|
+
function refusalCounts(result) {
|
|
89117
|
+
const counts = {};
|
|
89118
|
+
for (const r of result.refused) counts[r.reason] = (counts[r.reason] ?? 0) + r.count;
|
|
89119
|
+
return counts;
|
|
89120
|
+
}
|
|
89121
|
+
var NodeStressHistoryProducer = class {
|
|
89122
|
+
accum = new BucketAccumulator();
|
|
89123
|
+
deviceHistory;
|
|
88771
89124
|
logger;
|
|
88772
89125
|
nowFn;
|
|
88773
|
-
|
|
88774
|
-
maxRows;
|
|
89126
|
+
declared = false;
|
|
88775
89127
|
constructor(deps) {
|
|
88776
|
-
this.
|
|
88777
|
-
this.store = deps.store;
|
|
89128
|
+
this.deviceHistory = deps.deviceHistory;
|
|
88778
89129
|
this.logger = deps.logger;
|
|
88779
89130
|
this.nowFn = deps.now ?? (() => Date.now());
|
|
88780
|
-
this.bucketMs = deps.bucketMs ?? 3e5;
|
|
88781
|
-
this.maxRows = deps.maxRowsPerSeries ?? 105120;
|
|
88782
|
-
}
|
|
88783
|
-
static declare(store, collection) {
|
|
88784
|
-
return store.declareCollection.mutate({
|
|
88785
|
-
collection,
|
|
88786
|
-
columns: [...LTS_COLUMNS],
|
|
88787
|
-
primaryKey: [...LTS_KEY_COLUMNS],
|
|
88788
|
-
withoutRowid: true,
|
|
88789
|
-
indexes: [...LTS_INDEXES]
|
|
88790
|
-
});
|
|
88791
89131
|
}
|
|
88792
|
-
|
|
88793
|
-
|
|
88794
|
-
|
|
88795
|
-
|
|
88796
|
-
|
|
88797
|
-
|
|
88798
|
-
|
|
88799
|
-
|
|
88800
|
-
|
|
88801
|
-
|
|
88802
|
-
note(input) {
|
|
88803
|
-
if (!Number.isFinite(input.value)) return;
|
|
88804
|
-
const at = input.at ?? this.nowFn();
|
|
88805
|
-
const scope = input.scope ?? "";
|
|
88806
|
-
const bucketStart = ltsBucketStart(at, this.bucketMs);
|
|
88807
|
-
const key = rowId(input.subject, input.series, scope, bucketStart);
|
|
88808
|
-
const held = this.open.get(key);
|
|
88809
|
-
if (held === void 0) {
|
|
88810
|
-
this.open.set(key, {
|
|
88811
|
-
subject: input.subject,
|
|
88812
|
-
...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {},
|
|
88813
|
-
series: input.series,
|
|
88814
|
-
scope,
|
|
88815
|
-
bucketStart,
|
|
88816
|
-
samples: 1,
|
|
88817
|
-
sum: input.value,
|
|
88818
|
-
min: input.value,
|
|
88819
|
-
max: input.value
|
|
88820
|
-
});
|
|
88821
|
-
return;
|
|
88822
|
-
}
|
|
88823
|
-
held.samples += 1;
|
|
88824
|
-
held.sum += input.value;
|
|
88825
|
-
if (input.value < held.min) held.min = input.value;
|
|
88826
|
-
if (input.value > held.max) held.max = input.value;
|
|
88827
|
-
}
|
|
88828
|
-
/** Buckets currently accumulating — diagnostics, and what a flush would write. */
|
|
88829
|
-
openBuckets() {
|
|
88830
|
-
return [...this.open.values()].map(toRow);
|
|
88831
|
-
}
|
|
88832
|
-
/**
|
|
88833
|
-
* Write every bucket that has CLOSED (its window ended at or before `now`)
|
|
88834
|
-
* and drop it from RAM. Returns the number of rows written.
|
|
88835
|
-
*
|
|
88836
|
-
* The current bucket is deliberately left alone: writing it early would mean
|
|
88837
|
-
* rewriting it on the next tick, which turns one row into up to sixty and
|
|
88838
|
-
* offers every one of them to the checkpoint lottery (D96).
|
|
88839
|
-
*/
|
|
88840
|
-
async flushDue(now = this.nowFn()) {
|
|
88841
|
-
const currentBucket = ltsBucketStart(now, this.bucketMs);
|
|
88842
|
-
const due = [...this.open.values()].filter((b) => b.bucketStart < currentBucket);
|
|
88843
|
-
if (due.length === 0) {
|
|
88844
|
-
await this.maybeSweepCap(now);
|
|
88845
|
-
return 0;
|
|
88846
|
-
}
|
|
88847
|
-
let written = 0;
|
|
88848
|
-
for (const batch of chunk(due, FLUSH_BATCH)) {
|
|
88849
|
-
written += await this.writeBatch(batch);
|
|
88850
|
-
for (const bucket of batch) this.open.delete(rowId(bucket.subject, bucket.series, bucket.scope, bucket.bucketStart));
|
|
88851
|
-
}
|
|
88852
|
-
await this.maybeSweepCap(now);
|
|
88853
|
-
return written;
|
|
89132
|
+
async declare() {
|
|
89133
|
+
if (this.declared) return;
|
|
89134
|
+
for (const meta of SERIES_META) await this.deviceHistory.declareSeries({
|
|
89135
|
+
name: meta.name,
|
|
89136
|
+
subjectKind: "node",
|
|
89137
|
+
kind: "gauge",
|
|
89138
|
+
displayName: meta.displayName,
|
|
89139
|
+
ingest: "buckets"
|
|
89140
|
+
});
|
|
89141
|
+
this.declared = true;
|
|
88854
89142
|
}
|
|
88855
|
-
|
|
88856
|
-
|
|
88857
|
-
|
|
88858
|
-
|
|
88859
|
-
|
|
88860
|
-
|
|
89143
|
+
noteSignals(nodeId, signals, at) {
|
|
89144
|
+
const subject = {
|
|
89145
|
+
kind: "node",
|
|
89146
|
+
nodeId
|
|
89147
|
+
};
|
|
89148
|
+
this.accum.note(SERIES_KEYS["node-score"], subject, "", signals.score, at);
|
|
89149
|
+
this.accum.note(SERIES_KEYS["node-queue-pressure"], subject, "", signals.queuePressure, at);
|
|
89150
|
+
this.accum.note(SERIES_KEYS["node-drop-ratio"], subject, "", signals.dropRatio, at);
|
|
89151
|
+
this.accum.note(SERIES_KEYS["node-fps-deficit"], subject, "", signals.fpsDeficit, at);
|
|
89152
|
+
}
|
|
89153
|
+
async flushDue(now) {
|
|
89154
|
+
const closed = this.accum.takeClosed(now ?? this.nowFn());
|
|
89155
|
+
if (closed.length === 0) return 0;
|
|
88861
89156
|
try {
|
|
88862
|
-
await this.
|
|
88863
|
-
|
|
88864
|
-
|
|
88865
|
-
|
|
88866
|
-
|
|
88867
|
-
|
|
88868
|
-
for (const bucket of batch) written += await this.writeBatch([bucket]);
|
|
88869
|
-
return written;
|
|
88870
|
-
}
|
|
88871
|
-
const bucket = batch[0];
|
|
88872
|
-
this.logger.warn("lts bucket write failed — this interval will be missing", {
|
|
88873
|
-
...bucket?.deviceId !== void 0 ? { tags: { deviceId: bucket.deviceId } } : {},
|
|
88874
|
-
meta: {
|
|
88875
|
-
collection: this.collection,
|
|
88876
|
-
series: bucket?.series,
|
|
88877
|
-
subject: bucket?.subject,
|
|
88878
|
-
bucketStart: bucket?.bucketStart,
|
|
88879
|
-
error: String(err)
|
|
89157
|
+
await this.declare();
|
|
89158
|
+
const result = await this.deviceHistory.recordBuckets({ buckets: closed });
|
|
89159
|
+
if (result.refused.length > 0) {
|
|
89160
|
+
if (result.refused.some((r) => r.reason === "undeclared")) {
|
|
89161
|
+
this.declared = false;
|
|
89162
|
+
this.accum.requeue(closed);
|
|
88880
89163
|
}
|
|
88881
|
-
|
|
88882
|
-
|
|
88883
|
-
|
|
88884
|
-
|
|
88885
|
-
async upsert(batch) {
|
|
88886
|
-
await this.store.upsertMany.mutate({
|
|
88887
|
-
collection: this.collection,
|
|
88888
|
-
conflict: [...LTS_KEY_COLUMNS],
|
|
88889
|
-
records: batch.map((bucket) => ({ data: {
|
|
88890
|
-
subject: bucket.subject,
|
|
88891
|
-
deviceId: bucket.deviceId ?? null,
|
|
88892
|
-
series: bucket.series,
|
|
88893
|
-
scope: bucket.scope,
|
|
88894
|
-
bucketStart: bucket.bucketStart,
|
|
88895
|
-
samples: bucket.samples,
|
|
88896
|
-
sum: bucket.sum,
|
|
88897
|
-
min: bucket.min,
|
|
88898
|
-
max: bucket.max
|
|
88899
|
-
} }))
|
|
88900
|
-
});
|
|
88901
|
-
}
|
|
88902
|
-
/** Read closed buckets back. The read surface every chart will use. */
|
|
88903
|
-
async read(query = {}) {
|
|
88904
|
-
const where = {};
|
|
88905
|
-
if (query.series !== void 0) where["series"] = query.series;
|
|
88906
|
-
if (query.subject !== void 0) where["subject"] = query.subject;
|
|
88907
|
-
if (query.scope !== void 0) where["scope"] = query.scope;
|
|
88908
|
-
const records = await this.store.query.query({
|
|
88909
|
-
collection: this.collection,
|
|
88910
|
-
filter: {
|
|
88911
|
-
...Object.keys(where).length > 0 ? { where } : {},
|
|
88912
|
-
...query.from !== void 0 || query.to !== void 0 ? { whereBetween: { bucketStart: [query.from ?? 0, query.to ?? Number.MAX_SAFE_INTEGER] } } : {},
|
|
88913
|
-
orderBy: {
|
|
88914
|
-
field: "bucketStart",
|
|
88915
|
-
direction: "asc"
|
|
88916
|
-
},
|
|
88917
|
-
limit: query.limit ?? 5e3
|
|
88918
|
-
}
|
|
88919
|
-
});
|
|
88920
|
-
const rows = [];
|
|
88921
|
-
for (const record of records) {
|
|
88922
|
-
const row = recordToRow(record.data);
|
|
88923
|
-
if (row !== null) rows.push(row);
|
|
88924
|
-
}
|
|
88925
|
-
return rows;
|
|
88926
|
-
}
|
|
88927
|
-
/**
|
|
88928
|
-
* Enforce the per-(subject, series, scope) row cap, at most once every six
|
|
88929
|
-
* hours. Only groups this process has written to are examined: a group with
|
|
88930
|
-
* no new rows cannot have crossed a cap it was under.
|
|
88931
|
-
*/
|
|
88932
|
-
async maybeSweepCap(now) {
|
|
88933
|
-
if (now - this.lastCapSweepAt < CAP_SWEEP_INTERVAL_MS) return;
|
|
88934
|
-
this.lastCapSweepAt = now;
|
|
88935
|
-
for (const group of this.groups) {
|
|
88936
|
-
const [subject, series, scope] = group.split("\0");
|
|
88937
|
-
if (subject === void 0 || series === void 0 || scope === void 0) continue;
|
|
88938
|
-
const where = {
|
|
88939
|
-
subject,
|
|
88940
|
-
series,
|
|
88941
|
-
scope
|
|
88942
|
-
};
|
|
88943
|
-
try {
|
|
88944
|
-
const excess = await this.store.count.query({
|
|
88945
|
-
collection: this.collection,
|
|
88946
|
-
filter: { where }
|
|
88947
|
-
}) - this.maxRows;
|
|
88948
|
-
if (excess <= 0) continue;
|
|
88949
|
-
const cutoff = (await this.store.query.query({
|
|
88950
|
-
collection: this.collection,
|
|
88951
|
-
filter: {
|
|
88952
|
-
where,
|
|
88953
|
-
orderBy: {
|
|
88954
|
-
field: "bucketStart",
|
|
88955
|
-
direction: "asc"
|
|
88956
|
-
},
|
|
88957
|
-
limit: excess
|
|
88958
|
-
}
|
|
88959
|
-
})).at(-1)?.data["bucketStart"];
|
|
88960
|
-
if (typeof cutoff !== "number") continue;
|
|
88961
|
-
const { deleted } = await this.store.deleteWhere.mutate({
|
|
88962
|
-
collection: this.collection,
|
|
88963
|
-
filter: {
|
|
88964
|
-
where,
|
|
88965
|
-
whereBetween: { bucketStart: [0, cutoff] }
|
|
88966
|
-
}
|
|
88967
|
-
});
|
|
88968
|
-
this.logger.info("lts row cap enforced", { meta: {
|
|
88969
|
-
collection: this.collection,
|
|
88970
|
-
series,
|
|
88971
|
-
subject,
|
|
88972
|
-
deleted,
|
|
88973
|
-
cap: this.maxRows
|
|
88974
|
-
} });
|
|
88975
|
-
} catch (err) {
|
|
88976
|
-
this.logger.warn("lts row cap sweep failed — the series keeps growing this cycle", { meta: {
|
|
88977
|
-
collection: this.collection,
|
|
88978
|
-
series,
|
|
88979
|
-
subject,
|
|
88980
|
-
error: String(err)
|
|
89164
|
+
this.logger.warn("node-stress history buckets refused", { meta: {
|
|
89165
|
+
buckets: closed.length,
|
|
89166
|
+
accepted: result.accepted,
|
|
89167
|
+
refused: refusalCounts(result)
|
|
88981
89168
|
} });
|
|
88982
89169
|
}
|
|
89170
|
+
return result.accepted;
|
|
89171
|
+
} catch (err) {
|
|
89172
|
+
const dropped = this.accum.requeue(closed);
|
|
89173
|
+
this.logger.warn("node-stress history flush failed — requeued", { meta: {
|
|
89174
|
+
buckets: closed.length,
|
|
89175
|
+
dropped: dropped.length,
|
|
89176
|
+
error: err instanceof Error ? err.message : String(err)
|
|
89177
|
+
} });
|
|
89178
|
+
return 0;
|
|
88983
89179
|
}
|
|
88984
89180
|
}
|
|
88985
|
-
|
|
88986
|
-
|
|
88987
|
-
|
|
88988
|
-
|
|
88989
|
-
|
|
88990
|
-
|
|
88991
|
-
|
|
88992
|
-
|
|
88993
|
-
|
|
88994
|
-
|
|
88995
|
-
|
|
88996
|
-
}
|
|
88997
|
-
function toRow(bucket) {
|
|
88998
|
-
return {
|
|
88999
|
-
subject: bucket.subject,
|
|
89000
|
-
...bucket.deviceId !== void 0 ? { deviceId: bucket.deviceId } : {},
|
|
89001
|
-
series: bucket.series,
|
|
89002
|
-
scope: bucket.scope,
|
|
89003
|
-
bucketStart: bucket.bucketStart,
|
|
89004
|
-
samples: bucket.samples,
|
|
89005
|
-
sum: bucket.sum,
|
|
89006
|
-
min: bucket.min,
|
|
89007
|
-
max: bucket.max
|
|
89008
|
-
};
|
|
89009
|
-
}
|
|
89010
|
-
/** Structural validation on read. A malformed row is skipped, never charted. */
|
|
89011
|
-
function recordToRow(data) {
|
|
89012
|
-
const subject = data["subject"];
|
|
89013
|
-
const series = data["series"];
|
|
89014
|
-
const scope = data["scope"];
|
|
89015
|
-
if (typeof subject !== "string" || typeof series !== "string") return null;
|
|
89016
|
-
const bucketStart = Number(data["bucketStart"]);
|
|
89017
|
-
const samples = Number(data["samples"]);
|
|
89018
|
-
const sum = Number(data["sum"]);
|
|
89019
|
-
const min = Number(data["min"]);
|
|
89020
|
-
const max = Number(data["max"]);
|
|
89021
|
-
if (![
|
|
89022
|
-
bucketStart,
|
|
89023
|
-
samples,
|
|
89024
|
-
sum,
|
|
89025
|
-
min,
|
|
89026
|
-
max
|
|
89027
|
-
].every((n) => Number.isFinite(n))) return null;
|
|
89028
|
-
const rawDeviceId = data["deviceId"];
|
|
89029
|
-
const deviceId = typeof rawDeviceId === "number" && Number.isFinite(rawDeviceId) ? rawDeviceId : void 0;
|
|
89030
|
-
return {
|
|
89031
|
-
subject,
|
|
89032
|
-
...deviceId !== void 0 ? { deviceId } : {},
|
|
89033
|
-
series,
|
|
89034
|
-
scope: typeof scope === "string" ? scope : "",
|
|
89035
|
-
bucketStart,
|
|
89036
|
-
samples,
|
|
89037
|
-
sum,
|
|
89038
|
-
min,
|
|
89039
|
-
max
|
|
89040
|
-
};
|
|
89041
|
-
}
|
|
89042
|
-
//#endregion
|
|
89043
|
-
//#region src/node-stress-lts.ts
|
|
89044
|
-
/**
|
|
89045
|
-
* @durable class=ledger owner=pipeline-orchestrator
|
|
89046
|
-
* write="one row per (node, series, 5-min bucket), written ONCE when the bucket closes; a node reporting no samples writes nothing"
|
|
89047
|
-
* 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."
|
|
89048
|
-
*/
|
|
89049
|
-
var NODE_STRESS_LTS_COLLECTION = "pipeline-orchestrator:stats-5m-v2";
|
|
89050
|
-
var NodeStressLts = class {
|
|
89051
|
-
lts;
|
|
89052
|
-
constructor(deps) {
|
|
89053
|
-
this.lts = new LtsAggregator({
|
|
89054
|
-
collection: NODE_STRESS_LTS_COLLECTION,
|
|
89055
|
-
store: deps.store,
|
|
89056
|
-
logger: deps.logger,
|
|
89057
|
-
...deps.now !== void 0 ? { now: deps.now } : {}
|
|
89058
|
-
});
|
|
89059
|
-
}
|
|
89060
|
-
static declare(store) {
|
|
89061
|
-
return LtsAggregator.declare(store, NODE_STRESS_LTS_COLLECTION);
|
|
89062
|
-
}
|
|
89063
|
-
/** Fold one sweep's verdict for one node into the open buckets. */
|
|
89064
|
-
noteSignals(nodeId, signals, at) {
|
|
89065
|
-
this.lts.note({
|
|
89066
|
-
subject: nodeId,
|
|
89067
|
-
series: "node-score",
|
|
89068
|
-
value: signals.score,
|
|
89069
|
-
at
|
|
89070
|
-
});
|
|
89071
|
-
this.lts.note({
|
|
89072
|
-
subject: nodeId,
|
|
89073
|
-
series: "node-queue-pressure",
|
|
89074
|
-
value: signals.queuePressure,
|
|
89075
|
-
at
|
|
89076
|
-
});
|
|
89077
|
-
this.lts.note({
|
|
89078
|
-
subject: nodeId,
|
|
89079
|
-
series: "node-drop-ratio",
|
|
89080
|
-
value: signals.dropRatio,
|
|
89081
|
-
at
|
|
89181
|
+
async read(input) {
|
|
89182
|
+
const nodeId = input.subject;
|
|
89183
|
+
if (nodeId === void 0 || input.series === void 0) return [];
|
|
89184
|
+
const key = SERIES_KEYS[input.series];
|
|
89185
|
+
if (key === void 0) return [];
|
|
89186
|
+
const result = await this.deviceHistory.queryNode({
|
|
89187
|
+
nodeId,
|
|
89188
|
+
key,
|
|
89189
|
+
from: input.from ?? 0,
|
|
89190
|
+
to: input.to ?? Date.now(),
|
|
89191
|
+
resolution: "5m",
|
|
89192
|
+
...input.maxPoints !== void 0 ? { maxPoints: input.maxPoints } : {}
|
|
89082
89193
|
});
|
|
89083
|
-
|
|
89194
|
+
const rows = [];
|
|
89195
|
+
for (const s of result.series) for (const p of s.points) rows.push({
|
|
89084
89196
|
subject: nodeId,
|
|
89085
|
-
series:
|
|
89086
|
-
|
|
89087
|
-
|
|
89197
|
+
series: input.series,
|
|
89198
|
+
scope: s.scope,
|
|
89199
|
+
bucketStart: p.t,
|
|
89200
|
+
samples: p.samples,
|
|
89201
|
+
sum: p.sum,
|
|
89202
|
+
min: p.min,
|
|
89203
|
+
max: p.max
|
|
89088
89204
|
});
|
|
89089
|
-
|
|
89090
|
-
flushDue(now) {
|
|
89091
|
-
return this.lts.flushDue(now);
|
|
89092
|
-
}
|
|
89093
|
-
read(query) {
|
|
89094
|
-
return this.lts.read(query);
|
|
89205
|
+
return rows;
|
|
89095
89206
|
}
|
|
89096
89207
|
openBuckets() {
|
|
89097
|
-
return
|
|
89208
|
+
return [];
|
|
89098
89209
|
}
|
|
89099
89210
|
};
|
|
89100
89211
|
//#endregion
|
|
@@ -95045,9 +95156,9 @@ async function buildOrchestratorControllers(deps) {
|
|
|
95045
95156
|
kind: orchestratorRecords.kind(orchestratorRecordKinds["node-stress-moves"]),
|
|
95046
95157
|
logger: deps.ctx().logger.child("node-stress")
|
|
95047
95158
|
});
|
|
95048
|
-
const nodeStressLts = new
|
|
95049
|
-
|
|
95050
|
-
logger: deps.ctx().logger.child("node-stress-
|
|
95159
|
+
const nodeStressLts = new NodeStressHistoryProducer({
|
|
95160
|
+
deviceHistory: nodeStressHistoryClient(deps.ctx().api.deviceHistory),
|
|
95161
|
+
logger: deps.ctx().logger.child("node-stress-history")
|
|
95051
95162
|
});
|
|
95052
95163
|
const nodeStress = new NodeStressController({
|
|
95053
95164
|
ledger,
|
|
@@ -95065,7 +95176,7 @@ async function buildOrchestratorControllers(deps) {
|
|
|
95065
95176
|
await nodeStress.hydrate().catch((err) => {
|
|
95066
95177
|
deps.ctx().logger.warn("node-stress move history unavailable — this boot starts cold", { meta: { error: errMsg$2(err) } });
|
|
95067
95178
|
});
|
|
95068
|
-
await
|
|
95179
|
+
await nodeStressLts.declare().catch((err) => {
|
|
95069
95180
|
deps.ctx().logger.warn("node-stress statistics unavailable — no baseline this boot", { meta: { error: errMsg$2(err) } });
|
|
95070
95181
|
});
|
|
95071
95182
|
const nodeStressLtsTimer = setInterval(() => {
|
|
@@ -97776,7 +97887,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
97776
97887
|
/** Periodic auto-rebalance sweep timer (drift correction under hysteresis). */
|
|
97777
97888
|
autoRebalanceTimer = null;
|
|
97778
97889
|
/** Node-stress five-minute statistics + its flush timer (see
|
|
97779
|
-
* `node-stress-
|
|
97890
|
+
* `node-stress-history-producer.ts`). `observe` mode's first durable output. */
|
|
97780
97891
|
nodeStressLts = null;
|
|
97781
97892
|
nodeStressLtsTimer = null;
|
|
97782
97893
|
initTimestamp = 0;
|
|
@@ -99746,7 +99857,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
99746
99857
|
return this.isSessionCamera(deviceId) && !this.session.hasActiveSession(deviceId);
|
|
99747
99858
|
}
|
|
99748
99859
|
};
|
|
99749
|
-
/** The derived mean for one
|
|
99860
|
+
/** The derived mean for one closed bucket — see `node-stress-history-producer.ts`. */
|
|
99750
99861
|
function withStatsMean(row) {
|
|
99751
99862
|
return {
|
|
99752
99863
|
...row,
|