camstack 1.2.189 → 1.2.190
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/cli.js +283 -45
- package/dist/{launcher-LKHQ7I4L.js → launcher-ILGFB3AQ.js} +1530 -684
- package/package.json +1 -1
|
@@ -24024,9 +24024,9 @@ var require_zod = __commonJS({
|
|
|
24024
24024
|
}
|
|
24025
24025
|
});
|
|
24026
24026
|
|
|
24027
|
-
// ../system/dist/dist-
|
|
24028
|
-
var
|
|
24029
|
-
"../system/dist/dist-
|
|
24027
|
+
// ../system/dist/dist-Bi4Ioxop.js
|
|
24028
|
+
var require_dist_Bi4Ioxop = __commonJS({
|
|
24029
|
+
"../system/dist/dist-Bi4Ioxop.js"(exports) {
|
|
24030
24030
|
"use strict";
|
|
24031
24031
|
var zod = require_zod();
|
|
24032
24032
|
__require("crypto");
|
|
@@ -24049,6 +24049,7 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
24049
24049
|
EventCategory2["AddonRunnerRefused"] = "addon.runner-refused";
|
|
24050
24050
|
EventCategory2["ProcessStateChanged"] = "process.state-changed";
|
|
24051
24051
|
EventCategory2["SystemRunnerCheck"] = "system.runner-check";
|
|
24052
|
+
EventCategory2["AlertEpisode"] = "alert.episode";
|
|
24052
24053
|
EventCategory2["AddonError"] = "addon.error";
|
|
24053
24054
|
EventCategory2["AddonPageReady"] = "addon.page-ready";
|
|
24054
24055
|
EventCategory2["AddonWidgetReady"] = "addon.widget-ready";
|
|
@@ -32045,7 +32046,14 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
32045
32046
|
]);
|
|
32046
32047
|
var AlertActionSchema = zod.z.object({
|
|
32047
32048
|
label: zod.z.string(),
|
|
32048
|
-
href: zod.z.string().optional()
|
|
32049
|
+
href: zod.z.string().optional(),
|
|
32050
|
+
/**
|
|
32051
|
+
* How `href` is followed. Absent / `app`: an admin-ui route (client-side).
|
|
32052
|
+
* `server`: a route the HUB serves (an addon HTTP route such as an OAuth
|
|
32053
|
+
* start) — the browser must leave the SPA with a full navigation, because
|
|
32054
|
+
* the SPA has no such route and would bounce to the home page.
|
|
32055
|
+
*/
|
|
32056
|
+
navigation: zod.z.enum(["app", "server"]).optional()
|
|
32049
32057
|
});
|
|
32050
32058
|
var AlertStatusSchema = zod.z.enum([
|
|
32051
32059
|
"active",
|
|
@@ -62794,6 +62802,9 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
62794
62802
|
"server-updated",
|
|
62795
62803
|
"export-completed",
|
|
62796
62804
|
"backup-completed",
|
|
62805
|
+
"alert-critical",
|
|
62806
|
+
"alert-error",
|
|
62807
|
+
"alert-critical-resolved",
|
|
62797
62808
|
"camera-online",
|
|
62798
62809
|
"camera-offline",
|
|
62799
62810
|
"camera-disabled",
|
|
@@ -71992,6 +72003,18 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
71992
72003
|
*/
|
|
71993
72004
|
movers: method(zod.z.object({}), zod.z.array(StorageMigrationMoverSchema).readonly(), { auth: "admin" }),
|
|
71994
72005
|
/**
|
|
72006
|
+
* May a mover that touches these locations run NOW? One claim per physical
|
|
72007
|
+
* root is owned by the storage orchestrator: a single-location repoint holds
|
|
72008
|
+
* it while it carries its subtree, and a mover (`relocateMedia`,
|
|
72009
|
+
* `relocateFootage`, a migration move) asks here AFTER registering its job and
|
|
72010
|
+
* cancels itself on `clear: false`. The repoint, in turn, refuses while a
|
|
72011
|
+
* registered mover touches its root. Asked, never polled (D3).
|
|
72012
|
+
*/
|
|
72013
|
+
moverClearance: method(zod.z.object({ locationIds: zod.z.array(zod.z.string()).readonly() }), zod.z.object({
|
|
72014
|
+
clear: zod.z.boolean(),
|
|
72015
|
+
repointLocationId: zod.z.string().optional()
|
|
72016
|
+
}), { auth: "admin" }),
|
|
72017
|
+
/**
|
|
71995
72018
|
* What each class's SOURCE still holds, from the archive — never from the
|
|
71996
72019
|
* resident index (D295). Only classes with something left (or something
|
|
71997
72020
|
* unknown) are listed, so an empty list means there is nothing to drain and
|
|
@@ -76209,43 +76232,139 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
76209
76232
|
"error",
|
|
76210
76233
|
"unavailable"
|
|
76211
76234
|
]);
|
|
76235
|
+
var DishwasherOperationStateSchema = zod.z.enum([
|
|
76236
|
+
"Inactive",
|
|
76237
|
+
"Ready",
|
|
76238
|
+
"DelayedStart",
|
|
76239
|
+
"Run",
|
|
76240
|
+
"Pause",
|
|
76241
|
+
"ActionRequired",
|
|
76242
|
+
"Finished",
|
|
76243
|
+
"Error",
|
|
76244
|
+
"Aborting"
|
|
76245
|
+
]);
|
|
76246
|
+
var DishwasherAvailabilitySchema = zod.z.enum([
|
|
76247
|
+
"available",
|
|
76248
|
+
"offline",
|
|
76249
|
+
"description-missing"
|
|
76250
|
+
]);
|
|
76212
76251
|
var DishwasherConsumableLevelSchema = zod.z.enum([
|
|
76213
76252
|
"ok",
|
|
76214
76253
|
"low",
|
|
76215
76254
|
"empty"
|
|
76216
76255
|
]);
|
|
76217
76256
|
var DishwasherStatusSchema = zod.z.object({
|
|
76257
|
+
availability: DishwasherAvailabilitySchema,
|
|
76258
|
+
/** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
|
|
76218
76259
|
state: DishwasherStateSchema,
|
|
76219
|
-
/**
|
|
76260
|
+
/** The appliance's operation state as reported; null when not known. */
|
|
76261
|
+
operationState: DishwasherOperationStateSchema.nullable(),
|
|
76262
|
+
/** Feature key of the ACTIVE (running) program, or null when none runs / not known. */
|
|
76220
76263
|
program: zod.z.string().nullable(),
|
|
76221
|
-
/**
|
|
76264
|
+
/** Feature key of the SELECTED program (what Start would run), or null when none / not known. */
|
|
76265
|
+
selectedProgram: zod.z.string().nullable(),
|
|
76266
|
+
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
76222
76267
|
availablePrograms: zod.z.array(zod.z.string()),
|
|
76223
|
-
/**
|
|
76224
|
-
|
|
76268
|
+
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
76269
|
+
remainingSeconds: zod.z.number().int().nonnegative().nullable(),
|
|
76270
|
+
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
76271
|
+
delayedStartSeconds: zod.z.number().int().nonnegative().nullable(),
|
|
76225
76272
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
76226
76273
|
progressPercent: zod.z.number().min(0).max(100).nullable(),
|
|
76227
|
-
/** True when the door is reported open. */
|
|
76228
|
-
doorOpen: zod.z.boolean(),
|
|
76229
|
-
/** True when
|
|
76230
|
-
|
|
76231
|
-
/**
|
|
76232
|
-
|
|
76274
|
+
/** True when the door is reported open; null when the door state is not known. */
|
|
76275
|
+
doorOpen: zod.z.boolean().nullable(),
|
|
76276
|
+
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
76277
|
+
doorLocked: zod.z.boolean().nullable(),
|
|
76278
|
+
/** True when remote start is allowed (door closed, power on, etc.); null when not known. */
|
|
76279
|
+
remoteStartAllowed: zod.z.boolean().nullable(),
|
|
76280
|
+
/** True when the appliance accepts remote control now; null when not known. */
|
|
76281
|
+
remoteControlActive: zod.z.boolean().nullable(),
|
|
76282
|
+
/** True while somebody operates the appliance at its panel; null when not reported. */
|
|
76283
|
+
localControlActive: zod.z.boolean().nullable(),
|
|
76284
|
+
/** Main power / switched-on state; null when not known. */
|
|
76285
|
+
powerOn: zod.z.boolean().nullable(),
|
|
76286
|
+
/** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
|
|
76287
|
+
powerState: zod.z.string().nullable(),
|
|
76233
76288
|
saltLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
76234
76289
|
rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
76235
|
-
|
|
76236
|
-
|
|
76290
|
+
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
76291
|
+
halfLoad: zod.z.boolean().nullable(),
|
|
76292
|
+
hygienePlus: zod.z.boolean().nullable(),
|
|
76237
76293
|
/** Extra dry option when the appliance exposes it. */
|
|
76238
|
-
extraDry: zod.z.boolean(),
|
|
76294
|
+
extraDry: zod.z.boolean().nullable(),
|
|
76239
76295
|
/** Intensive zone (lower basket) when the appliance exposes it. */
|
|
76240
|
-
intensiveZone: zod.z.boolean(),
|
|
76296
|
+
intensiveZone: zod.z.boolean().nullable(),
|
|
76241
76297
|
/** VarioSpeed / VarioSpeed+ when the appliance exposes it. */
|
|
76242
|
-
varioSpeedPlus: zod.z.boolean(),
|
|
76243
|
-
/** Child lock (controls disabled on the appliance). */
|
|
76244
|
-
childLock: zod.z.boolean(),
|
|
76298
|
+
varioSpeedPlus: zod.z.boolean().nullable(),
|
|
76299
|
+
/** Child lock (controls disabled on the appliance); null when not known. */
|
|
76300
|
+
childLock: zod.z.boolean().nullable(),
|
|
76301
|
+
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
76302
|
+
activeEvents: zod.z.array(zod.z.string()),
|
|
76303
|
+
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
76245
76304
|
errorCode: zod.z.number().nullable(),
|
|
76305
|
+
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
76246
76306
|
errorLabel: zod.z.string().nullable(),
|
|
76307
|
+
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
76247
76308
|
lastFetchedAt: zod.z.number()
|
|
76248
76309
|
});
|
|
76310
|
+
var DeviceIdSchema = zod.z.number().int().nonnegative();
|
|
76311
|
+
var DishwasherValueSchema = zod.z.union([
|
|
76312
|
+
zod.z.boolean(),
|
|
76313
|
+
zod.z.string(),
|
|
76314
|
+
zod.z.number()
|
|
76315
|
+
]);
|
|
76316
|
+
var DishwasherAccessSchema = zod.z.enum([
|
|
76317
|
+
"none",
|
|
76318
|
+
"read",
|
|
76319
|
+
"readWrite",
|
|
76320
|
+
"writeOnly",
|
|
76321
|
+
"readStatic"
|
|
76322
|
+
]);
|
|
76323
|
+
var DishwasherOptionDescriptorSchema = zod.z.object({
|
|
76324
|
+
/** Feature key (`Dishcare.Dishwasher.Option.ExtraDry`). */
|
|
76325
|
+
key: zod.z.string(),
|
|
76326
|
+
/** Last segment of the key, for display. */
|
|
76327
|
+
name: zod.z.string(),
|
|
76328
|
+
type: zod.z.enum([
|
|
76329
|
+
"boolean",
|
|
76330
|
+
"number",
|
|
76331
|
+
"enum",
|
|
76332
|
+
"string"
|
|
76333
|
+
]),
|
|
76334
|
+
access: DishwasherAccessSchema,
|
|
76335
|
+
/** The appliance reports this entity as currently available. */
|
|
76336
|
+
available: zod.z.boolean(),
|
|
76337
|
+
/** Unit the description declares for a number; null when it declares none. */
|
|
76338
|
+
unit: zod.z.string().nullable(),
|
|
76339
|
+
min: zod.z.number().nullable(),
|
|
76340
|
+
max: zod.z.number().nullable(),
|
|
76341
|
+
step: zod.z.number().nullable(),
|
|
76342
|
+
/** Allowed members of an enum; null for other types. */
|
|
76343
|
+
enumValues: zod.z.array(zod.z.string()).nullable(),
|
|
76344
|
+
defaultValue: DishwasherValueSchema.nullable()
|
|
76345
|
+
});
|
|
76346
|
+
var DishwasherProgramSchema = zod.z.object({
|
|
76347
|
+
/** Feature key (`Dishcare.Dishwasher.Program.Eco50`) — what `setProgram` / `start` take. */
|
|
76348
|
+
key: zod.z.string(),
|
|
76349
|
+
name: zod.z.string(),
|
|
76350
|
+
/** The appliance currently offers this program. */
|
|
76351
|
+
available: zod.z.boolean(),
|
|
76352
|
+
/** The options this program lists, with the program-level access / availability / default. */
|
|
76353
|
+
options: zod.z.array(DishwasherOptionDescriptorSchema)
|
|
76354
|
+
});
|
|
76355
|
+
var DishwasherOptionsSchema = zod.z.object({
|
|
76356
|
+
availability: DishwasherAvailabilitySchema,
|
|
76357
|
+
/** What the appliance can be told to do, from the commands its description declares. */
|
|
76358
|
+
supportsStart: zod.z.boolean(),
|
|
76359
|
+
supportsPause: zod.z.boolean(),
|
|
76360
|
+
supportsResume: zod.z.boolean(),
|
|
76361
|
+
supportsStop: zod.z.boolean(),
|
|
76362
|
+
supportsPower: zod.z.boolean(),
|
|
76363
|
+
/** Every program the description lists, with its options. */
|
|
76364
|
+
programs: zod.z.array(DishwasherProgramSchema),
|
|
76365
|
+
/** Every option and setting entity the description lists (programs reference these by key). */
|
|
76366
|
+
options: zod.z.array(DishwasherOptionDescriptorSchema)
|
|
76367
|
+
});
|
|
76249
76368
|
var dishwasherCapability = {
|
|
76250
76369
|
name: "dishwasher",
|
|
76251
76370
|
scope: "device",
|
|
@@ -76253,86 +76372,102 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
76253
76372
|
mode: "singleton",
|
|
76254
76373
|
deviceTypes: [DeviceType.Dishwasher],
|
|
76255
76374
|
methods: {
|
|
76256
|
-
|
|
76375
|
+
/**
|
|
76376
|
+
* Start a program. Without `program` the selected one starts. `options` are
|
|
76377
|
+
* option feature keys; each is checked against the program's constraints.
|
|
76378
|
+
*/
|
|
76379
|
+
start: method(zod.z.object({
|
|
76380
|
+
deviceId: DeviceIdSchema,
|
|
76381
|
+
program: zod.z.string().min(1).optional(),
|
|
76382
|
+
options: zod.z.record(zod.z.string(), DishwasherValueSchema).optional()
|
|
76383
|
+
}), zod.z.void(), {
|
|
76257
76384
|
kind: "mutation",
|
|
76258
76385
|
auth: "protected"
|
|
76259
76386
|
}),
|
|
76260
|
-
pause: method(zod.z.object({ deviceId:
|
|
76387
|
+
pause: method(zod.z.object({ deviceId: DeviceIdSchema }), zod.z.void(), {
|
|
76261
76388
|
kind: "mutation",
|
|
76262
76389
|
auth: "protected"
|
|
76263
76390
|
}),
|
|
76264
|
-
|
|
76391
|
+
resume: method(zod.z.object({ deviceId: DeviceIdSchema }), zod.z.void(), {
|
|
76265
76392
|
kind: "mutation",
|
|
76266
76393
|
auth: "protected"
|
|
76267
76394
|
}),
|
|
76395
|
+
stop: method(zod.z.object({ deviceId: DeviceIdSchema }), zod.z.void(), {
|
|
76396
|
+
kind: "mutation",
|
|
76397
|
+
auth: "protected"
|
|
76398
|
+
}),
|
|
76399
|
+
/** Select (not start) a program; refused when the appliance does not offer it. */
|
|
76268
76400
|
setProgram: method(zod.z.object({
|
|
76269
|
-
deviceId:
|
|
76401
|
+
deviceId: DeviceIdSchema,
|
|
76270
76402
|
program: zod.z.string().min(1)
|
|
76271
76403
|
}), zod.z.void(), {
|
|
76272
76404
|
kind: "mutation",
|
|
76273
76405
|
auth: "protected"
|
|
76274
76406
|
}),
|
|
76275
76407
|
setPower: method(zod.z.object({
|
|
76276
|
-
deviceId:
|
|
76408
|
+
deviceId: DeviceIdSchema,
|
|
76277
76409
|
on: zod.z.boolean()
|
|
76278
76410
|
}), zod.z.void(), {
|
|
76279
76411
|
kind: "mutation",
|
|
76280
76412
|
auth: "protected"
|
|
76281
76413
|
}),
|
|
76282
76414
|
setHalfLoad: method(zod.z.object({
|
|
76283
|
-
deviceId:
|
|
76415
|
+
deviceId: DeviceIdSchema,
|
|
76284
76416
|
on: zod.z.boolean()
|
|
76285
76417
|
}), zod.z.void(), {
|
|
76286
76418
|
kind: "mutation",
|
|
76287
76419
|
auth: "protected"
|
|
76288
76420
|
}),
|
|
76289
76421
|
setHygienePlus: method(zod.z.object({
|
|
76290
|
-
deviceId:
|
|
76422
|
+
deviceId: DeviceIdSchema,
|
|
76291
76423
|
on: zod.z.boolean()
|
|
76292
76424
|
}), zod.z.void(), {
|
|
76293
76425
|
kind: "mutation",
|
|
76294
76426
|
auth: "protected"
|
|
76295
76427
|
}),
|
|
76296
76428
|
setExtraDry: method(zod.z.object({
|
|
76297
|
-
deviceId:
|
|
76429
|
+
deviceId: DeviceIdSchema,
|
|
76298
76430
|
on: zod.z.boolean()
|
|
76299
76431
|
}), zod.z.void(), {
|
|
76300
76432
|
kind: "mutation",
|
|
76301
76433
|
auth: "protected"
|
|
76302
76434
|
}),
|
|
76303
76435
|
setIntensiveZone: method(zod.z.object({
|
|
76304
|
-
deviceId:
|
|
76436
|
+
deviceId: DeviceIdSchema,
|
|
76305
76437
|
on: zod.z.boolean()
|
|
76306
76438
|
}), zod.z.void(), {
|
|
76307
76439
|
kind: "mutation",
|
|
76308
76440
|
auth: "protected"
|
|
76309
76441
|
}),
|
|
76310
76442
|
setVarioSpeedPlus: method(zod.z.object({
|
|
76311
|
-
deviceId:
|
|
76443
|
+
deviceId: DeviceIdSchema,
|
|
76312
76444
|
on: zod.z.boolean()
|
|
76313
76445
|
}), zod.z.void(), {
|
|
76314
76446
|
kind: "mutation",
|
|
76315
76447
|
auth: "protected"
|
|
76316
76448
|
}),
|
|
76317
76449
|
setChildLock: method(zod.z.object({
|
|
76318
|
-
deviceId:
|
|
76450
|
+
deviceId: DeviceIdSchema,
|
|
76319
76451
|
on: zod.z.boolean()
|
|
76320
76452
|
}), zod.z.void(), {
|
|
76321
76453
|
kind: "mutation",
|
|
76322
76454
|
auth: "protected"
|
|
76323
76455
|
}),
|
|
76456
|
+
/**
|
|
76457
|
+
* Write any option or setting by feature key. Refused when the description does
|
|
76458
|
+
* not list it, it is not writable or not available now, or the value is outside
|
|
76459
|
+
* its declared range / members.
|
|
76460
|
+
*/
|
|
76324
76461
|
setOption: method(zod.z.object({
|
|
76325
|
-
deviceId:
|
|
76462
|
+
deviceId: DeviceIdSchema,
|
|
76326
76463
|
key: zod.z.string().min(1),
|
|
76327
|
-
value:
|
|
76328
|
-
zod.z.boolean(),
|
|
76329
|
-
zod.z.string(),
|
|
76330
|
-
zod.z.number()
|
|
76331
|
-
])
|
|
76464
|
+
value: DishwasherValueSchema
|
|
76332
76465
|
}), zod.z.void(), {
|
|
76333
76466
|
kind: "mutation",
|
|
76334
76467
|
auth: "protected"
|
|
76335
|
-
})
|
|
76468
|
+
}),
|
|
76469
|
+
/** What this appliance can do, from its own description — the UI is derived from it. */
|
|
76470
|
+
getOptions: method(zod.z.object({ deviceId: DeviceIdSchema }), DishwasherOptionsSchema, { auth: "protected" })
|
|
76336
76471
|
},
|
|
76337
76472
|
status: {
|
|
76338
76473
|
schema: DishwasherStatusSchema,
|
|
@@ -89662,6 +89797,12 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
89662
89797
|
addonId: null,
|
|
89663
89798
|
access: "view"
|
|
89664
89799
|
},
|
|
89800
|
+
"dishwasher.getOptions": {
|
|
89801
|
+
capName: "dishwasher",
|
|
89802
|
+
capScope: "device",
|
|
89803
|
+
addonId: null,
|
|
89804
|
+
access: "view"
|
|
89805
|
+
},
|
|
89665
89806
|
"dishwasher.getStatus": {
|
|
89666
89807
|
capName: "dishwasher",
|
|
89667
89808
|
capScope: "device",
|
|
@@ -89674,6 +89815,12 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
89674
89815
|
addonId: null,
|
|
89675
89816
|
access: "create"
|
|
89676
89817
|
},
|
|
89818
|
+
"dishwasher.resume": {
|
|
89819
|
+
capName: "dishwasher",
|
|
89820
|
+
capScope: "device",
|
|
89821
|
+
addonId: null,
|
|
89822
|
+
access: "create"
|
|
89823
|
+
},
|
|
89677
89824
|
"dishwasher.setChildLock": {
|
|
89678
89825
|
capName: "dishwasher",
|
|
89679
89826
|
capScope: "device",
|
|
@@ -94174,6 +94321,12 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
94174
94321
|
addonId: null,
|
|
94175
94322
|
access: "view"
|
|
94176
94323
|
},
|
|
94324
|
+
"storageMigration.moverClearance": {
|
|
94325
|
+
capName: "storage-migration",
|
|
94326
|
+
capScope: "system",
|
|
94327
|
+
addonId: null,
|
|
94328
|
+
access: "view"
|
|
94329
|
+
},
|
|
94177
94330
|
"storageMigration.movers": {
|
|
94178
94331
|
capName: "storage-migration",
|
|
94179
94332
|
capScope: "system",
|
|
@@ -96624,6 +96777,11 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
96624
96777
|
form: "single",
|
|
96625
96778
|
optional: false
|
|
96626
96779
|
}],
|
|
96780
|
+
"dishwasher.getOptions": [{
|
|
96781
|
+
name: "deviceId",
|
|
96782
|
+
form: "single",
|
|
96783
|
+
optional: false
|
|
96784
|
+
}],
|
|
96627
96785
|
"dishwasher.getStatus": [{
|
|
96628
96786
|
name: "deviceId",
|
|
96629
96787
|
form: "single",
|
|
@@ -96634,6 +96792,11 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
96634
96792
|
form: "single",
|
|
96635
96793
|
optional: false
|
|
96636
96794
|
}],
|
|
96795
|
+
"dishwasher.resume": [{
|
|
96796
|
+
name: "deviceId",
|
|
96797
|
+
form: "single",
|
|
96798
|
+
optional: false
|
|
96799
|
+
}],
|
|
96637
96800
|
"dishwasher.setChildLock": [{
|
|
96638
96801
|
name: "deviceId",
|
|
96639
96802
|
form: "single",
|
|
@@ -99207,6 +99370,9 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
99207
99370
|
"wrapper-update-available": "system",
|
|
99208
99371
|
"backup-completed": "system",
|
|
99209
99372
|
"export-completed": "system",
|
|
99373
|
+
"alert-critical": "system",
|
|
99374
|
+
"alert-error": "system",
|
|
99375
|
+
"alert-critical-resolved": "system",
|
|
99210
99376
|
"storage-location-low": "system",
|
|
99211
99377
|
"storage-location-critical": "system",
|
|
99212
99378
|
"storage-location-ok": "system",
|
|
@@ -99331,6 +99497,16 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
99331
99497
|
"storage-location-ok"
|
|
99332
99498
|
]
|
|
99333
99499
|
},
|
|
99500
|
+
{
|
|
99501
|
+
id: "alerts",
|
|
99502
|
+
family: "system",
|
|
99503
|
+
label: "Alerts",
|
|
99504
|
+
kinds: [
|
|
99505
|
+
"alert-critical",
|
|
99506
|
+
"alert-error",
|
|
99507
|
+
"alert-critical-resolved"
|
|
99508
|
+
]
|
|
99509
|
+
},
|
|
99334
99510
|
{
|
|
99335
99511
|
id: "alarm",
|
|
99336
99512
|
family: "alarm",
|
|
@@ -99348,6 +99524,60 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
99348
99524
|
return [[descriptor.kind, field]];
|
|
99349
99525
|
})));
|
|
99350
99526
|
Object.freeze(Object.keys(NC_SENSOR_RAISED_FIELD_BY_KIND));
|
|
99527
|
+
zod.z.object({
|
|
99528
|
+
phase: zod.z.enum(["raised", "resolved"]),
|
|
99529
|
+
episodeId: zod.z.string().min(1),
|
|
99530
|
+
alertId: zod.z.string().min(1),
|
|
99531
|
+
severity: AlertSeveritySchema,
|
|
99532
|
+
category: zod.z.string(),
|
|
99533
|
+
title: zod.z.string(),
|
|
99534
|
+
message: zod.z.string(),
|
|
99535
|
+
sourceType: zod.z.string().optional(),
|
|
99536
|
+
sourceId: zod.z.string().optional(),
|
|
99537
|
+
nodeId: zod.z.string().optional(),
|
|
99538
|
+
/** The alert's own action link (where the operator acts on it), when it has one. */
|
|
99539
|
+
actionUrl: zod.z.string().optional(),
|
|
99540
|
+
at: zod.z.number()
|
|
99541
|
+
});
|
|
99542
|
+
function isAlertEpisodeOpen(status) {
|
|
99543
|
+
return status !== "completed" && status !== "dismissed";
|
|
99544
|
+
}
|
|
99545
|
+
function isAlertEpisodeSeverity(severity) {
|
|
99546
|
+
return severity === "critical" || severity === "error";
|
|
99547
|
+
}
|
|
99548
|
+
function alertEpisodeId(alert) {
|
|
99549
|
+
const minted = alert.metadata?.["episodeId"];
|
|
99550
|
+
return typeof minted === "string" && minted.length > 0 ? minted : `${alert.id}@${String(alert.createdAt)}`;
|
|
99551
|
+
}
|
|
99552
|
+
function alertNodeId(alert) {
|
|
99553
|
+
const direct = alert.metadata?.["nodeId"];
|
|
99554
|
+
if (typeof direct === "string") return direct;
|
|
99555
|
+
const runner = alert.metadata?.["runner"];
|
|
99556
|
+
if (typeof runner === "object" && runner !== null && "nodeId" in runner) {
|
|
99557
|
+
const id = runner.nodeId;
|
|
99558
|
+
if (typeof id === "string") return id;
|
|
99559
|
+
}
|
|
99560
|
+
return alert.source?.type === "node" ? alert.source.id : void 0;
|
|
99561
|
+
}
|
|
99562
|
+
function alertEpisodePayload(alert, phase, at) {
|
|
99563
|
+
const nodeId = alertNodeId(alert);
|
|
99564
|
+
return {
|
|
99565
|
+
phase,
|
|
99566
|
+
episodeId: alertEpisodeId(alert),
|
|
99567
|
+
alertId: alert.id,
|
|
99568
|
+
severity: alert.severity,
|
|
99569
|
+
category: alert.category,
|
|
99570
|
+
title: alert.title,
|
|
99571
|
+
message: alert.message,
|
|
99572
|
+
...alert.source !== void 0 ? {
|
|
99573
|
+
sourceType: alert.source.type,
|
|
99574
|
+
sourceId: alert.source.id
|
|
99575
|
+
} : {},
|
|
99576
|
+
...nodeId !== void 0 ? { nodeId } : {},
|
|
99577
|
+
...alert.action?.href !== void 0 ? { actionUrl: alert.action.href } : {},
|
|
99578
|
+
at
|
|
99579
|
+
};
|
|
99580
|
+
}
|
|
99351
99581
|
var RULE_BODY_ONLY = ["body"];
|
|
99352
99582
|
var RULE_TEXT = ["title", "body"];
|
|
99353
99583
|
var BATTERY = ["device-battery-low", "device-battery-normal"];
|
|
@@ -99357,6 +99587,11 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
99357
99587
|
"device-tank-full",
|
|
99358
99588
|
"device-tank-normal"
|
|
99359
99589
|
];
|
|
99590
|
+
var ALERT_EPISODE = [
|
|
99591
|
+
"alert-critical",
|
|
99592
|
+
"alert-error",
|
|
99593
|
+
"alert-critical-resolved"
|
|
99594
|
+
];
|
|
99360
99595
|
var UPDATES = [
|
|
99361
99596
|
"addon-update-available",
|
|
99362
99597
|
"server-update-available",
|
|
@@ -99546,14 +99781,14 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
99546
99781
|
([...RULE_TEXT], [...CONSUMABLE]),
|
|
99547
99782
|
([...RULE_TEXT], [...TANK]),
|
|
99548
99783
|
[...RULE_TEXT],
|
|
99549
|
-
([...RULE_TEXT], [...UPDATES]),
|
|
99550
|
-
([...RULE_TEXT], [...UPDATES]),
|
|
99551
|
-
[...RULE_TEXT],
|
|
99784
|
+
([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
|
|
99785
|
+
([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
|
|
99552
99786
|
[...RULE_TEXT],
|
|
99553
99787
|
[...RULE_TEXT],
|
|
99554
99788
|
[...RULE_TEXT],
|
|
99555
99789
|
[...RULE_TEXT],
|
|
99556
99790
|
[...RULE_TEXT],
|
|
99791
|
+
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
99557
99792
|
[...RULE_TEXT],
|
|
99558
99793
|
[...RULE_TEXT],
|
|
99559
99794
|
[...RULE_TEXT],
|
|
@@ -99571,7 +99806,11 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
99571
99806
|
[...RULE_TEXT],
|
|
99572
99807
|
[...RULE_TEXT],
|
|
99573
99808
|
[...RULE_TEXT],
|
|
99574
|
-
[...RULE_TEXT],
|
|
99809
|
+
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
99810
|
+
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
99811
|
+
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
99812
|
+
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
99813
|
+
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
99575
99814
|
[...RULE_TEXT],
|
|
99576
99815
|
[...RULE_TEXT],
|
|
99577
99816
|
[...RULE_TEXT],
|
|
@@ -100759,6 +100998,18 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
100759
100998
|
return addonWidgetsCapability;
|
|
100760
100999
|
}
|
|
100761
101000
|
});
|
|
101001
|
+
Object.defineProperty(exports, "alertEpisodeId", {
|
|
101002
|
+
enumerable: true,
|
|
101003
|
+
get: function() {
|
|
101004
|
+
return alertEpisodeId;
|
|
101005
|
+
}
|
|
101006
|
+
});
|
|
101007
|
+
Object.defineProperty(exports, "alertEpisodePayload", {
|
|
101008
|
+
enumerable: true,
|
|
101009
|
+
get: function() {
|
|
101010
|
+
return alertEpisodePayload;
|
|
101011
|
+
}
|
|
101012
|
+
});
|
|
100762
101013
|
Object.defineProperty(exports, "alertsCapability", {
|
|
100763
101014
|
enumerable: true,
|
|
100764
101015
|
get: function() {
|
|
@@ -101245,6 +101496,18 @@ var require_dist_DyjNaeIj = __commonJS({
|
|
|
101245
101496
|
return interpolate;
|
|
101246
101497
|
}
|
|
101247
101498
|
});
|
|
101499
|
+
Object.defineProperty(exports, "isAlertEpisodeOpen", {
|
|
101500
|
+
enumerable: true,
|
|
101501
|
+
get: function() {
|
|
101502
|
+
return isAlertEpisodeOpen;
|
|
101503
|
+
}
|
|
101504
|
+
});
|
|
101505
|
+
Object.defineProperty(exports, "isAlertEpisodeSeverity", {
|
|
101506
|
+
enumerable: true,
|
|
101507
|
+
get: function() {
|
|
101508
|
+
return isAlertEpisodeSeverity;
|
|
101509
|
+
}
|
|
101510
|
+
});
|
|
101248
101511
|
Object.defineProperty(exports, "isAppLinkBase", {
|
|
101249
101512
|
enumerable: true,
|
|
101250
101513
|
get: function() {
|
|
@@ -113359,11 +113622,11 @@ ${values.join("\n")}` : `${blockName} :`;
|
|
|
113359
113622
|
}
|
|
113360
113623
|
});
|
|
113361
113624
|
|
|
113362
|
-
// ../system/dist/device-ca-
|
|
113363
|
-
var
|
|
113364
|
-
"../system/dist/device-ca-
|
|
113625
|
+
// ../system/dist/device-ca-B3hUVfYk.js
|
|
113626
|
+
var require_device_ca_B3hUVfYk = __commonJS({
|
|
113627
|
+
"../system/dist/device-ca-B3hUVfYk.js"(exports) {
|
|
113365
113628
|
"use strict";
|
|
113366
|
-
var require_dist10 =
|
|
113629
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
113367
113630
|
var require_x509_es = require_x509_es_C4cOo48M();
|
|
113368
113631
|
var node_crypto = __require("crypto");
|
|
113369
113632
|
var SYSTEM_SECRET_OWNER = "system";
|
|
@@ -113778,11 +114041,11 @@ var require_device_ca_njpTMpJC = __commonJS({
|
|
|
113778
114041
|
}
|
|
113779
114042
|
});
|
|
113780
114043
|
|
|
113781
|
-
// ../system/dist/phase6-declare-gate-
|
|
113782
|
-
var
|
|
113783
|
-
"../system/dist/phase6-declare-gate-
|
|
114044
|
+
// ../system/dist/phase6-declare-gate-DwYAep7y.js
|
|
114045
|
+
var require_phase6_declare_gate_DwYAep7y = __commonJS({
|
|
114046
|
+
"../system/dist/phase6-declare-gate-DwYAep7y.js"(exports) {
|
|
113784
114047
|
"use strict";
|
|
113785
|
-
var require_dist10 =
|
|
114048
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
113786
114049
|
function legacyTableRowCountFromList(tables, collection) {
|
|
113787
114050
|
return tables.find((t) => t.name === collection)?.rows ?? 0;
|
|
113788
114051
|
}
|
|
@@ -113876,124 +114139,33 @@ var require_alerts_addon = __commonJS({
|
|
|
113876
114139
|
[Symbol.toStringTag]: { value: "Module" }
|
|
113877
114140
|
});
|
|
113878
114141
|
require_chunk_Cek0wNdY();
|
|
113879
|
-
var require_dist10 =
|
|
114142
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
113880
114143
|
var require_read_all_rows$1 = require_read_all_rows_CVoO1ONM();
|
|
113881
|
-
var require_phase6_declare_gate =
|
|
113882
|
-
|
|
113883
|
-
|
|
113884
|
-
|
|
113885
|
-
|
|
113886
|
-
|
|
113887
|
-
|
|
113888
|
-
return
|
|
113889
|
-
}
|
|
113890
|
-
function
|
|
113891
|
-
|
|
113892
|
-
const
|
|
113893
|
-
|
|
113894
|
-
|
|
113895
|
-
|
|
113896
|
-
|
|
113897
|
-
|
|
113898
|
-
|
|
113899
|
-
|
|
113900
|
-
|
|
113901
|
-
function composeDigest(items) {
|
|
113902
|
-
const first = items[0];
|
|
113903
|
-
if (items.length === 1 && first !== void 0) return {
|
|
113904
|
-
title: first.title,
|
|
113905
|
-
body: first.line
|
|
113906
|
-
};
|
|
113907
|
-
const shown = items.slice(0, MAX_DIGEST_LINES).map((i) => i.line);
|
|
113908
|
-
const more = items.length - shown.length;
|
|
113909
|
-
return {
|
|
113910
|
-
title: `${String(items.length)} addons need attention`,
|
|
113911
|
-
body: [...shown, ...more > 0 ? [`... and ${String(more)} more`] : []].join("\n")
|
|
113912
|
-
};
|
|
113913
|
-
}
|
|
113914
|
-
async function deliverDigest(input) {
|
|
113915
|
-
const out = /* @__PURE__ */ new Map();
|
|
113916
|
-
const work = input.items.filter((i) => !(i.previous !== null && i.previous.key === i.key && i.previous.state !== "pending"));
|
|
113917
|
-
if (work.length === 0) return out;
|
|
113918
|
-
const sameKey = (i) => i.previous !== null && i.previous.key === i.key ? i.previous : null;
|
|
113919
|
-
const attemptsOf = (i) => (sameKey(i)?.attempts ?? 0) + 1;
|
|
113920
|
-
const sentOf = (i) => sameKey(i)?.sentTo ?? [];
|
|
113921
|
-
if (!input.policy.enabled) {
|
|
113922
|
-
for (const i of work) out.set(i.alertId, {
|
|
113923
|
-
state: "disabled",
|
|
113924
|
-
key: i.key,
|
|
113925
|
-
attempts: attemptsOf(i)
|
|
113926
|
-
});
|
|
113927
|
-
return out;
|
|
113928
|
-
}
|
|
113929
|
-
const fail = (error) => {
|
|
113930
|
-
for (const i of work) out.set(i.alertId, {
|
|
113931
|
-
state: "pending",
|
|
113932
|
-
key: i.key,
|
|
113933
|
-
attempts: attemptsOf(i),
|
|
113934
|
-
lastError: error,
|
|
113935
|
-
...sentOf(i).length > 0 ? { sentTo: sentOf(i) } : {}
|
|
113936
|
-
});
|
|
113937
|
-
return out;
|
|
113938
|
-
};
|
|
113939
|
-
let targets;
|
|
113940
|
-
try {
|
|
113941
|
-
targets = selectPushTargets(await input.ports.listTargets(), input.policy);
|
|
113942
|
-
} catch (err) {
|
|
113943
|
-
return fail(`notifiers unavailable: ${err instanceof Error ? err.message : String(err)}`);
|
|
113944
|
-
}
|
|
113945
|
-
if (targets.length === 0) return fail("no eligible notifier target");
|
|
113946
|
-
const sent = new Map(work.map((i) => [i.alertId, [...sentOf(i)]]));
|
|
113947
|
-
const errors = new Map(work.map((i) => [i.alertId, []]));
|
|
113948
|
-
for (const target of targets) {
|
|
113949
|
-
const todo = work.filter((i) => !(sent.get(i.alertId) ?? []).includes(target.id));
|
|
113950
|
-
if (todo.length === 0) continue;
|
|
113951
|
-
let failure = null;
|
|
113952
|
-
try {
|
|
113953
|
-
const result = await input.ports.send(target, composeDigest(todo));
|
|
113954
|
-
if (!result.success) failure = `${target.id}: ${result.error ?? "send failed"}`;
|
|
113955
|
-
} catch (err) {
|
|
113956
|
-
failure = `${target.id}: ${err instanceof Error ? err.message : String(err)}`;
|
|
113957
|
-
}
|
|
113958
|
-
for (const i of todo) if (failure === null) sent.get(i.alertId)?.push(target.id);
|
|
113959
|
-
else errors.get(i.alertId)?.push(failure);
|
|
113960
|
-
}
|
|
113961
|
-
for (const i of work) {
|
|
113962
|
-
const sentTo = sent.get(i.alertId) ?? [];
|
|
113963
|
-
const complete = targets.every((t) => sentTo.includes(t.id));
|
|
113964
|
-
out.set(i.alertId, complete ? {
|
|
113965
|
-
state: "delivered",
|
|
113966
|
-
key: i.key,
|
|
113967
|
-
at: input.now,
|
|
113968
|
-
attempts: attemptsOf(i),
|
|
113969
|
-
sentTo
|
|
113970
|
-
} : {
|
|
113971
|
-
state: "pending",
|
|
113972
|
-
key: i.key,
|
|
113973
|
-
attempts: attemptsOf(i),
|
|
113974
|
-
lastError: (errors.get(i.alertId) ?? []).join("; "),
|
|
113975
|
-
...sentTo.length > 0 ? { sentTo } : {}
|
|
113976
|
-
});
|
|
113977
|
-
}
|
|
113978
|
-
return out;
|
|
114144
|
+
var require_phase6_declare_gate = require_phase6_declare_gate_DwYAep7y();
|
|
114145
|
+
function nextEpisodeId(input) {
|
|
114146
|
+
const { previous } = input;
|
|
114147
|
+
if (previous !== null && require_dist10.isAlertEpisodeOpen(previous.status)) {
|
|
114148
|
+
if (input.incomingKey === void 0 || input.incomingKey === previous.episodeKey) return previous.episodeId;
|
|
114149
|
+
}
|
|
114150
|
+
const minted = `${input.alertId}@${String(input.now)}`;
|
|
114151
|
+
return previous !== null && previous.episodeId === minted ? `${minted}+` : minted;
|
|
114152
|
+
}
|
|
114153
|
+
function episodeEdge(previous, next) {
|
|
114154
|
+
const nextOpen = require_dist10.isAlertEpisodeOpen(next.status);
|
|
114155
|
+
const continues = previous !== null && require_dist10.isAlertEpisodeOpen(previous.status) && previous.episodeId === next.episodeId;
|
|
114156
|
+
if (nextOpen) {
|
|
114157
|
+
if (!require_dist10.isAlertEpisodeSeverity(next.severity)) return null;
|
|
114158
|
+
if (!continues || previous === null) return "raised";
|
|
114159
|
+
if (!require_dist10.isAlertEpisodeSeverity(previous.severity)) return "raised";
|
|
114160
|
+
return previous.severity === "error" && next.severity === "critical" ? "raised" : null;
|
|
114161
|
+
}
|
|
114162
|
+
if (previous !== null && require_dist10.isAlertEpisodeOpen(previous.status) && require_dist10.isAlertEpisodeSeverity(previous.severity)) return "resolved";
|
|
114163
|
+
return null;
|
|
113979
114164
|
}
|
|
113980
114165
|
function episodeKeyFromMetadata(metadata) {
|
|
113981
114166
|
const key = metadata?.["episodeKey"];
|
|
113982
114167
|
return typeof key === "string" ? key : void 0;
|
|
113983
114168
|
}
|
|
113984
|
-
function shouldDropPriorPush(existingStatus) {
|
|
113985
|
-
return existingStatus === "completed";
|
|
113986
|
-
}
|
|
113987
|
-
function alertWithRetainedPush(toStore, existingPush, existingStatus) {
|
|
113988
|
-
if (existingPush === void 0 || shouldDropPriorPush(existingStatus)) return toStore;
|
|
113989
|
-
return {
|
|
113990
|
-
...toStore,
|
|
113991
|
-
metadata: {
|
|
113992
|
-
...toStore.metadata,
|
|
113993
|
-
push: existingPush
|
|
113994
|
-
}
|
|
113995
|
-
};
|
|
113996
|
-
}
|
|
113997
114169
|
function mergeEmitAlert(input) {
|
|
113998
114170
|
const incomingKey = episodeKeyFromMetadata(input.incoming.metadata);
|
|
113999
114171
|
const existingKey = input.existing?.episodeKey;
|
|
@@ -114001,26 +114173,11 @@ var require_alerts_addon = __commonJS({
|
|
|
114001
114173
|
const sameEpisode = incomingKey === void 0 || incomingKey === existingKey;
|
|
114002
114174
|
const priorCompleted = input.existing.status === "completed";
|
|
114003
114175
|
if (sameEpisode && !priorCompleted) return {
|
|
114004
|
-
|
|
114005
|
-
|
|
114006
|
-
read: true
|
|
114007
|
-
},
|
|
114008
|
-
queuePush: false
|
|
114176
|
+
...input.incoming,
|
|
114177
|
+
read: true
|
|
114009
114178
|
};
|
|
114010
114179
|
}
|
|
114011
|
-
|
|
114012
|
-
return {
|
|
114013
|
-
alert: input.incoming,
|
|
114014
|
-
queuePush
|
|
114015
|
-
};
|
|
114016
|
-
}
|
|
114017
|
-
function criticalPushPayload(alert) {
|
|
114018
|
-
const key = episodeKeyFromMetadata(alert.metadata) ?? alert.id;
|
|
114019
|
-
const pushLine = alert.metadata?.["pushLine"];
|
|
114020
|
-
return {
|
|
114021
|
-
key,
|
|
114022
|
-
line: typeof pushLine === "string" ? pushLine : alert.title
|
|
114023
|
-
};
|
|
114180
|
+
return input.incoming;
|
|
114024
114181
|
}
|
|
114025
114182
|
function deviceLabelFromEventData(data) {
|
|
114026
114183
|
const name = stringNonEmpty(data["name"]) ?? stringNonEmpty(data["deviceName"]);
|
|
@@ -114130,13 +114287,13 @@ var require_alerts_addon = __commonJS({
|
|
|
114130
114287
|
switch (record.state) {
|
|
114131
114288
|
case "refused":
|
|
114132
114289
|
return {
|
|
114133
|
-
severity: "
|
|
114290
|
+
severity: "critical",
|
|
114134
114291
|
title: "Addon refused to start",
|
|
114135
114292
|
message: `${where}: refused - ${record.reason ?? "no reason reported"}${record.remedy !== void 0 ? ` ${record.remedy}` : ""}`
|
|
114136
114293
|
};
|
|
114137
114294
|
case "failed":
|
|
114138
114295
|
return {
|
|
114139
|
-
severity: "
|
|
114296
|
+
severity: "critical",
|
|
114140
114297
|
title: "Addon crash loop",
|
|
114141
114298
|
message: `Runner "${where}" gave up${record.crashesInWindow !== void 0 ? ` after ${String(record.crashesInWindow)} crashes` : ""}${record.addonIds.length > 0 ? ` (addons: ${record.addonIds.join(", ")})` : ""} - ${String(record.count)} events`
|
|
114142
114299
|
};
|
|
@@ -114148,22 +114305,6 @@ var require_alerts_addon = __commonJS({
|
|
|
114148
114305
|
};
|
|
114149
114306
|
}
|
|
114150
114307
|
}
|
|
114151
|
-
function isTerminalRunnerState(state) {
|
|
114152
|
-
return state === "failed" || state === "refused";
|
|
114153
|
-
}
|
|
114154
|
-
function hash(text) {
|
|
114155
|
-
let h = 5381;
|
|
114156
|
-
for (let i = 0; i < text.length; i++) h = (h << 5) + h + text.charCodeAt(i) | 0;
|
|
114157
|
-
return (h >>> 0).toString(36);
|
|
114158
|
-
}
|
|
114159
|
-
function runnerPushKey(record) {
|
|
114160
|
-
const cause = record.state === "refused" ? hash(`${record.reason ?? ""}|${record.remedy ?? ""}`) : "breaker";
|
|
114161
|
-
return `runner:${record.state}:${String(record.since)}:${cause}`;
|
|
114162
|
-
}
|
|
114163
|
-
function runnerPushLine(record) {
|
|
114164
|
-
const where = record.nodeId === "hub" ? record.runnerId : `${record.runnerId} on ${record.nodeId}`;
|
|
114165
|
-
return record.state === "refused" ? `${where}: refused to start. ${record.remedy ?? "See the Addons page."}` : `${where}: stopped after repeated crashes. Restart it from the Addons page.`;
|
|
114166
|
-
}
|
|
114167
114308
|
var import_read_all_rows = require_read_all_rows$1.require_read_all_rows();
|
|
114168
114309
|
var ALERTS_COLLECTION = "alerts";
|
|
114169
114310
|
var AlertBodySchema = require_dist10.AlertSchema.omit({ id: true });
|
|
@@ -114455,7 +114596,6 @@ var require_alerts_addon = __commonJS({
|
|
|
114455
114596
|
}
|
|
114456
114597
|
};
|
|
114457
114598
|
var SILENT_TRACKED_CATEGORIES = [
|
|
114458
|
-
"addon.started",
|
|
114459
114599
|
"process.state-changed",
|
|
114460
114600
|
"addon.load-recovered",
|
|
114461
114601
|
"system.liveness-recovered",
|
|
@@ -114506,21 +114646,25 @@ var require_alerts_addon = __commonJS({
|
|
|
114506
114646
|
}
|
|
114507
114647
|
var DEFAULT_CONFIG = {
|
|
114508
114648
|
maxAlerts: 500,
|
|
114509
|
-
retentionDays: 30
|
|
114510
|
-
criticalPushEnabled: true,
|
|
114511
|
-
criticalPushTargetIds: []
|
|
114649
|
+
retentionDays: 30
|
|
114512
114650
|
};
|
|
114513
|
-
function normalizeCriticalPushTargetIds(raw) {
|
|
114514
|
-
if (Array.isArray(raw)) return raw.filter((id) => typeof id === "string" && id.trim().length > 0).map((id) => id.trim());
|
|
114515
|
-
if (typeof raw === "string" && raw.trim().length > 0) return raw.split(",").map((id) => id.trim()).filter((id) => id.length > 0);
|
|
114516
|
-
return [];
|
|
114517
|
-
}
|
|
114518
|
-
var PUSH_COALESCE_MS = 2e3;
|
|
114519
|
-
var PUSH_RECONCILE_ADDONS = /* @__PURE__ */ new Set(["notifiers", "notification-center"]);
|
|
114520
114651
|
var EVENT_SOURCE = {
|
|
114521
114652
|
type: "addon",
|
|
114522
114653
|
id: "alert-center"
|
|
114523
114654
|
};
|
|
114655
|
+
var ADDONS_PAGE_ACTION = {
|
|
114656
|
+
label: "Open Addons",
|
|
114657
|
+
href: "/system/addons"
|
|
114658
|
+
};
|
|
114659
|
+
function episodeViewOf(alert) {
|
|
114660
|
+
const key = episodeKeyFromMetadata(alert.metadata);
|
|
114661
|
+
return {
|
|
114662
|
+
status: alert.status,
|
|
114663
|
+
severity: alert.severity,
|
|
114664
|
+
episodeId: require_dist10.alertEpisodeId(alert),
|
|
114665
|
+
...key !== void 0 ? { episodeKey: key } : {}
|
|
114666
|
+
};
|
|
114667
|
+
}
|
|
114524
114668
|
function toPrunable(record) {
|
|
114525
114669
|
return {
|
|
114526
114670
|
id: record.id,
|
|
@@ -114531,11 +114675,8 @@ var require_alerts_addon = __commonJS({
|
|
|
114531
114675
|
var AlertCenterAddon = class extends require_dist10.BaseAddon {
|
|
114532
114676
|
alertStore = null;
|
|
114533
114677
|
unsubscribers = [];
|
|
114534
|
-
|
|
114535
|
-
pushCoalesceMs;
|
|
114536
|
-
constructor(options) {
|
|
114678
|
+
constructor() {
|
|
114537
114679
|
super({ ...DEFAULT_CONFIG });
|
|
114538
|
-
this.pushCoalesceMs = options?.pushCoalesceMs ?? PUSH_COALESCE_MS;
|
|
114539
114680
|
}
|
|
114540
114681
|
/**
|
|
114541
114682
|
* Per `(category, source.id)` counter used to rate-limit chatty
|
|
@@ -114566,9 +114707,7 @@ var require_alerts_addon = __commonJS({
|
|
|
114566
114707
|
unsubs.push(unsub);
|
|
114567
114708
|
}
|
|
114568
114709
|
this.unsubscribers = unsubs;
|
|
114569
|
-
this.reconcilePendingPushes();
|
|
114570
114710
|
this.dismissLegacyStreamCards(void 0);
|
|
114571
|
-
this.migrateCriticalPushTargetIds();
|
|
114572
114711
|
this.ctx.logger.info("Initialized", { meta: { trackedCategoriesCount: TRACKED_CATEGORIES.length } });
|
|
114573
114712
|
return [{
|
|
114574
114713
|
capability: require_dist10.alertsCapability,
|
|
@@ -114587,46 +114726,29 @@ var require_alerts_addon = __commonJS({
|
|
|
114587
114726
|
description: "Configure alert storage and retention.",
|
|
114588
114727
|
descriptionKey: "server:globalSettings.s_alerts.description",
|
|
114589
114728
|
columns: 1,
|
|
114590
|
-
fields: [
|
|
114591
|
-
|
|
114592
|
-
|
|
114593
|
-
|
|
114594
|
-
|
|
114595
|
-
|
|
114596
|
-
|
|
114597
|
-
|
|
114598
|
-
|
|
114599
|
-
|
|
114600
|
-
|
|
114601
|
-
|
|
114602
|
-
|
|
114603
|
-
|
|
114604
|
-
|
|
114605
|
-
|
|
114606
|
-
|
|
114607
|
-
|
|
114608
|
-
|
|
114609
|
-
|
|
114610
|
-
|
|
114611
|
-
|
|
114612
|
-
|
|
114613
|
-
default: 30
|
|
114614
|
-
}),
|
|
114615
|
-
this.field({
|
|
114616
|
-
type: "boolean",
|
|
114617
|
-
key: "criticalPushEnabled",
|
|
114618
|
-
label: "Push critical system alerts",
|
|
114619
|
-
description: "A runner that failed or refused to start, or a node whose runners are degraded, is pushed straight to the notifier targets \u2014 even when Notification Center is down. This path does not use notification rules.",
|
|
114620
|
-
default: true
|
|
114621
|
-
}),
|
|
114622
|
-
this.field({
|
|
114623
|
-
type: "notification-target-multiselect",
|
|
114624
|
-
key: "criticalPushTargetIds",
|
|
114625
|
-
label: "Critical push targets",
|
|
114626
|
-
description: "Notifier targets that receive critical system alerts. Empty = every enabled shared (not personal) target.",
|
|
114627
|
-
default: []
|
|
114628
|
-
})
|
|
114629
|
-
]
|
|
114729
|
+
fields: [this.field({
|
|
114730
|
+
type: "number",
|
|
114731
|
+
key: "maxAlerts",
|
|
114732
|
+
label: "Maximum stored alerts",
|
|
114733
|
+
labelKey: "server:globalSettings.s_alerts.maxAlerts.label",
|
|
114734
|
+
description: "Oldest read alerts are deleted when this limit is exceeded.",
|
|
114735
|
+
descriptionKey: "server:globalSettings.s_alerts.maxAlerts.description",
|
|
114736
|
+
min: 50,
|
|
114737
|
+
max: 5e3,
|
|
114738
|
+
step: 50,
|
|
114739
|
+
default: 500
|
|
114740
|
+
}), this.field({
|
|
114741
|
+
type: "number",
|
|
114742
|
+
key: "retentionDays",
|
|
114743
|
+
label: "Alert retention (days)",
|
|
114744
|
+
labelKey: "server:globalSettings.s_alerts.retentionDays.label",
|
|
114745
|
+
description: "Alerts older than this are automatically removed.",
|
|
114746
|
+
descriptionKey: "server:globalSettings.s_alerts.retentionDays.description",
|
|
114747
|
+
min: 1,
|
|
114748
|
+
max: 365,
|
|
114749
|
+
step: 1,
|
|
114750
|
+
default: 30
|
|
114751
|
+
})]
|
|
114630
114752
|
}] });
|
|
114631
114753
|
}
|
|
114632
114754
|
async listAlerts(filter) {
|
|
@@ -114665,7 +114787,17 @@ var require_alerts_addon = __commonJS({
|
|
|
114665
114787
|
updatedAt: Date.now()
|
|
114666
114788
|
});
|
|
114667
114789
|
}
|
|
114668
|
-
|
|
114790
|
+
/**
|
|
114791
|
+
* Events are handled one at a time: every handler is a read-modify-write of
|
|
114792
|
+
* an alert, and two concurrent events about one runner would both read "no
|
|
114793
|
+
* alert yet" and open two episodes for it.
|
|
114794
|
+
*/
|
|
114795
|
+
eventChain = Promise.resolve();
|
|
114796
|
+
handleEvent(category, event) {
|
|
114797
|
+
this.eventChain = this.eventChain.then(() => this.processEvent(category, event));
|
|
114798
|
+
return this.eventChain;
|
|
114799
|
+
}
|
|
114800
|
+
async processEvent(category, event) {
|
|
114669
114801
|
try {
|
|
114670
114802
|
if (category === "model.download.progress") {
|
|
114671
114803
|
await this.handleModelDownload(event);
|
|
@@ -114683,11 +114815,6 @@ var require_alerts_addon = __commonJS({
|
|
|
114683
114815
|
await this.handleRunnerCheck(event);
|
|
114684
114816
|
return;
|
|
114685
114817
|
}
|
|
114686
|
-
if (category === require_dist10.EventCategory.AddonStarted) {
|
|
114687
|
-
const addonId = event.data["addonId"];
|
|
114688
|
-
if (typeof addonId === "string" && PUSH_RECONCILE_ADDONS.has(addonId)) await this.reconcilePendingPushes();
|
|
114689
|
-
return;
|
|
114690
|
-
}
|
|
114691
114818
|
if (category === require_dist10.EventCategory.AddonLoadFailed) {
|
|
114692
114819
|
await this.handleAddonLoadFailed(event);
|
|
114693
114820
|
return;
|
|
@@ -114788,11 +114915,8 @@ var require_alerts_addon = __commonJS({
|
|
|
114788
114915
|
type: "runner",
|
|
114789
114916
|
id: record.runnerId
|
|
114790
114917
|
},
|
|
114791
|
-
|
|
114792
|
-
|
|
114793
|
-
pushLine: runnerPushLine(record),
|
|
114794
|
-
...existing?.push !== void 0 ? { push: existing.push } : {}
|
|
114795
|
-
}
|
|
114918
|
+
action: ADDONS_PAGE_ACTION,
|
|
114919
|
+
metadata: { runner: record }
|
|
114796
114920
|
};
|
|
114797
114921
|
await this.persistAlert(alert);
|
|
114798
114922
|
if (previous === null) this.emitAlertCreatedEvent(alert);
|
|
@@ -114801,17 +114925,11 @@ var require_alerts_addon = __commonJS({
|
|
|
114801
114925
|
title: alert.title
|
|
114802
114926
|
});
|
|
114803
114927
|
await this.enforceMaxAlerts();
|
|
114804
|
-
if (isTerminalRunnerState(record.state)) this.queuePush({
|
|
114805
|
-
alertId,
|
|
114806
|
-
key: runnerPushKey(record),
|
|
114807
|
-
title: rendered.title,
|
|
114808
|
-
line: runnerPushLine(record)
|
|
114809
|
-
});
|
|
114810
114928
|
}
|
|
114811
114929
|
/**
|
|
114812
114930
|
* A runner reached `running`: its episode is over. Close the runner alert so a
|
|
114813
|
-
* later failure opens a NEW episode
|
|
114814
|
-
*
|
|
114931
|
+
* later failure opens a NEW episode, instead of folding into a stale
|
|
114932
|
+
* `refused` record whose notification was already sent.
|
|
114815
114933
|
*/
|
|
114816
114934
|
async handleRunnerStateChanged(event) {
|
|
114817
114935
|
if (event.data["state"] !== "running") return;
|
|
@@ -114837,24 +114955,20 @@ var require_alerts_addon = __commonJS({
|
|
|
114837
114955
|
}) : [];
|
|
114838
114956
|
const failedIds = ids(event.data["failed"]);
|
|
114839
114957
|
const missingIds = ids(event.data["missing"]);
|
|
114840
|
-
const
|
|
114958
|
+
const parts = [
|
|
114841
114959
|
...failedIds.length > 0 ? [`failed: ${failedIds.join(", ")}`] : [],
|
|
114842
114960
|
...refusedIds.length > 0 ? [`refused: ${refusedIds.join(", ")}`] : [],
|
|
114843
114961
|
...missingIds.length > 0 ? [`missing: ${missingIds.join(", ")}`] : []
|
|
114844
|
-
]
|
|
114845
|
-
const pushKey = `check:${[
|
|
114846
|
-
...failedIds,
|
|
114847
|
-
...refusedIds,
|
|
114848
|
-
...missingIds
|
|
114849
|
-
].sort().join(",")}`;
|
|
114962
|
+
];
|
|
114850
114963
|
const now = Date.now();
|
|
114851
114964
|
const existing = await this.readAlertRaw(alertId);
|
|
114852
114965
|
const alert = {
|
|
114853
114966
|
id: alertId,
|
|
114854
114967
|
category: "system.runner-check",
|
|
114855
|
-
severity: "
|
|
114968
|
+
severity: "critical",
|
|
114856
114969
|
title: "Runners degraded",
|
|
114857
|
-
message: `${nodeId}: ${summary}`,
|
|
114970
|
+
message: `${nodeId}: ${summary}${parts.length > 0 ? ` (${parts.join("; ")})` : ""}`,
|
|
114971
|
+
action: ADDONS_PAGE_ACTION,
|
|
114858
114972
|
status: "active",
|
|
114859
114973
|
read: false,
|
|
114860
114974
|
createdAt: existing?.createdAt ?? now,
|
|
@@ -114867,19 +114981,11 @@ var require_alerts_addon = __commonJS({
|
|
|
114867
114981
|
nodeId,
|
|
114868
114982
|
failed: event.data["failed"],
|
|
114869
114983
|
refused: event.data["refused"],
|
|
114870
|
-
missing: event.data["missing"]
|
|
114871
|
-
pushLine,
|
|
114872
|
-
...existing?.push !== void 0 ? { push: existing.push } : {}
|
|
114984
|
+
missing: event.data["missing"]
|
|
114873
114985
|
}
|
|
114874
114986
|
};
|
|
114875
114987
|
await this.persistAlert(alert);
|
|
114876
114988
|
this.emitAlertCreatedEvent(alert);
|
|
114877
|
-
this.queuePush({
|
|
114878
|
-
alertId,
|
|
114879
|
-
key: pushKey,
|
|
114880
|
-
title: alert.title,
|
|
114881
|
-
line: pushLine
|
|
114882
|
-
});
|
|
114883
114989
|
}
|
|
114884
114990
|
async readAlertRaw(alertId) {
|
|
114885
114991
|
const store = this.alertStore;
|
|
@@ -114888,155 +114994,19 @@ var require_alerts_addon = __commonJS({
|
|
|
114888
114994
|
if (raw === null) return null;
|
|
114889
114995
|
const rec = Object.fromEntries(Object.entries(raw));
|
|
114890
114996
|
const meta = rec["metadata"];
|
|
114891
|
-
const push = typeof meta === "object" && meta !== null && !Array.isArray(meta) ? meta["push"] : void 0;
|
|
114892
114997
|
const metadata = typeof meta === "object" && meta !== null && !Array.isArray(meta) ? meta : void 0;
|
|
114998
|
+
const parsed = require_dist10.AlertSchema.safeParse({
|
|
114999
|
+
id: alertId,
|
|
115000
|
+
...rec
|
|
115001
|
+
});
|
|
114893
115002
|
return {
|
|
114894
115003
|
...typeof rec["createdAt"] === "number" ? { createdAt: rec["createdAt"] } : {},
|
|
114895
115004
|
...typeof rec["read"] === "boolean" ? { read: rec["read"] } : {},
|
|
114896
115005
|
...typeof rec["status"] === "string" ? { status: rec["status"] } : {},
|
|
114897
|
-
...
|
|
114898
|
-
...
|
|
114899
|
-
};
|
|
114900
|
-
}
|
|
114901
|
-
/** Pushes run one at a time so a burst can never send the same state twice. */
|
|
114902
|
-
pushChain = Promise.resolve();
|
|
114903
|
-
/** Findings waiting for the next digest, by alert id. */
|
|
114904
|
-
pushQueue = /* @__PURE__ */ new Map();
|
|
114905
|
-
pushTimer = null;
|
|
114906
|
-
pushPolicy() {
|
|
114907
|
-
return {
|
|
114908
|
-
enabled: this.config.criticalPushEnabled,
|
|
114909
|
-
targetIds: normalizeCriticalPushTargetIds(this.config.criticalPushTargetIds)
|
|
114910
|
-
};
|
|
114911
|
-
}
|
|
114912
|
-
/** Rewrite a legacy CSV `criticalPushTargetIds` string into `string[]`. */
|
|
114913
|
-
async migrateCriticalPushTargetIds() {
|
|
114914
|
-
const raw = this.config.criticalPushTargetIds;
|
|
114915
|
-
if (typeof raw !== "string") return;
|
|
114916
|
-
try {
|
|
114917
|
-
await this.updateGlobalSettings({ criticalPushTargetIds: normalizeCriticalPushTargetIds(raw) });
|
|
114918
|
-
} catch (err) {
|
|
114919
|
-
this.ctx.logger.warn("criticalPushTargetIds CSV migration failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
114920
|
-
}
|
|
114921
|
-
}
|
|
114922
|
-
pushPorts() {
|
|
114923
|
-
const api = this.ctx.api;
|
|
114924
|
-
return {
|
|
114925
|
-
listTargets: async () => {
|
|
114926
|
-
return (await api.notificationOutput.listTargets.query({})).map((t) => {
|
|
114927
|
-
const owner = t.config["ownerUserId"];
|
|
114928
|
-
return {
|
|
114929
|
-
id: t.id,
|
|
114930
|
-
addonId: t.addonId,
|
|
114931
|
-
enabled: t.enabled,
|
|
114932
|
-
...typeof owner === "string" && owner.length > 0 ? { ownerUserId: owner } : {}
|
|
114933
|
-
};
|
|
114934
|
-
});
|
|
114935
|
-
},
|
|
114936
|
-
send: async (target, message) => api.notificationOutput.send.mutate({
|
|
114937
|
-
addonId: target.addonId,
|
|
114938
|
-
targetId: target.id,
|
|
114939
|
-
notification: {
|
|
114940
|
-
title: message.title,
|
|
114941
|
-
body: message.body,
|
|
114942
|
-
format: "text",
|
|
114943
|
-
priority: 5
|
|
114944
|
-
}
|
|
114945
|
-
})
|
|
115006
|
+
...episodeKeyFromMetadata(metadata) !== void 0 ? { episodeKey: episodeKeyFromMetadata(metadata) } : {},
|
|
115007
|
+
...parsed.success ? { episode: episodeViewOf(parsed.data) } : {}
|
|
114946
115008
|
};
|
|
114947
115009
|
}
|
|
114948
|
-
/**
|
|
114949
|
-
* Queue a critical finding for the next digest. A burst (every runner of a boot)
|
|
114950
|
-
* arrives within the coalesce window and leaves as ONE message per target.
|
|
114951
|
-
*/
|
|
114952
|
-
queuePush(item) {
|
|
114953
|
-
this.pushQueue.set(item.alertId, item);
|
|
114954
|
-
if (this.pushTimer !== null) return;
|
|
114955
|
-
this.pushTimer = setTimeout(() => {
|
|
114956
|
-
this.pushTimer = null;
|
|
114957
|
-
this.flushPushes();
|
|
114958
|
-
}, this.pushCoalesceMs);
|
|
114959
|
-
this.pushTimer.unref?.();
|
|
114960
|
-
}
|
|
114961
|
-
/** Send the queued findings now (also the reconcile path). */
|
|
114962
|
-
flushPushes() {
|
|
114963
|
-
this.pushChain = this.pushChain.then(async () => {
|
|
114964
|
-
const queued = [...this.pushQueue.values()];
|
|
114965
|
-
this.pushQueue.clear();
|
|
114966
|
-
if (queued.length === 0) return;
|
|
114967
|
-
try {
|
|
114968
|
-
const items = [];
|
|
114969
|
-
for (const q of queued) {
|
|
114970
|
-
const existing = await this.readAlertRaw(q.alertId);
|
|
114971
|
-
items.push({
|
|
114972
|
-
...q,
|
|
114973
|
-
previous: existing?.push ?? null
|
|
114974
|
-
});
|
|
114975
|
-
}
|
|
114976
|
-
const states = await deliverDigest({
|
|
114977
|
-
items,
|
|
114978
|
-
policy: this.pushPolicy(),
|
|
114979
|
-
ports: this.pushPorts(),
|
|
114980
|
-
now: Date.now()
|
|
114981
|
-
});
|
|
114982
|
-
for (const [alertId, state] of states) {
|
|
114983
|
-
await this.storePushState(alertId, state);
|
|
114984
|
-
this.ctx.logger?.info("critical alert push", { meta: {
|
|
114985
|
-
alertId,
|
|
114986
|
-
state: state.state,
|
|
114987
|
-
attempts: state.attempts,
|
|
114988
|
-
error: state.lastError
|
|
114989
|
-
} });
|
|
114990
|
-
}
|
|
114991
|
-
} catch (err) {
|
|
114992
|
-
this.ctx.logger?.warn("critical alert push failed unexpectedly", { meta: { error: require_dist10.errMsg(err) } });
|
|
114993
|
-
}
|
|
114994
|
-
});
|
|
114995
|
-
return this.pushChain;
|
|
114996
|
-
}
|
|
114997
|
-
async storePushState(alertId, push) {
|
|
114998
|
-
const store = this.alertStore;
|
|
114999
|
-
if (store === null) return;
|
|
115000
|
-
const raw = await store.getData(alertId);
|
|
115001
|
-
if (raw === null) return;
|
|
115002
|
-
const meta = raw["metadata"];
|
|
115003
|
-
const metadata = typeof meta === "object" && meta !== null && !Array.isArray(meta) ? meta : {};
|
|
115004
|
-
await store.mergeUpdate(alertId, { metadata: {
|
|
115005
|
-
...metadata,
|
|
115006
|
-
push
|
|
115007
|
-
} });
|
|
115008
|
-
}
|
|
115009
|
-
/**
|
|
115010
|
-
* Retry every critical alert whose push is still pending - at boot and when
|
|
115011
|
-
* the notifiers or notification-center start. An alert whose state was already
|
|
115012
|
-
* delivered is skipped by its key, so reconciling never sends twice.
|
|
115013
|
-
*/
|
|
115014
|
-
async reconcilePendingPushes() {
|
|
115015
|
-
const store = this.alertStore;
|
|
115016
|
-
if (store === null) return;
|
|
115017
|
-
try {
|
|
115018
|
-
const rows = await store.listRecent(500);
|
|
115019
|
-
for (const row of rows) {
|
|
115020
|
-
const parsed = require_dist10.AlertSchema.safeParse({
|
|
115021
|
-
id: row.id,
|
|
115022
|
-
...row.data
|
|
115023
|
-
});
|
|
115024
|
-
if (!parsed.success || parsed.data.status !== "active") continue;
|
|
115025
|
-
if (!isCriticalPush(parsed.data)) continue;
|
|
115026
|
-
const push = parsed.data.metadata?.["push"];
|
|
115027
|
-
if (!isPushState(push) || push.state !== "pending") continue;
|
|
115028
|
-
this.pushQueue.set(parsed.data.id, {
|
|
115029
|
-
alertId: parsed.data.id,
|
|
115030
|
-
key: push.key,
|
|
115031
|
-
title: parsed.data.title,
|
|
115032
|
-
line: String(parsed.data.metadata?.["pushLine"] ?? parsed.data.title)
|
|
115033
|
-
});
|
|
115034
|
-
}
|
|
115035
|
-
await this.flushPushes();
|
|
115036
|
-
} catch (err) {
|
|
115037
|
-
this.ctx.logger?.warn("pending critical push reconcile failed", { meta: { error: require_dist10.errMsg(err) } });
|
|
115038
|
-
}
|
|
115039
|
-
}
|
|
115040
115010
|
async handleModelDownload(event) {
|
|
115041
115011
|
const data = event.data;
|
|
115042
115012
|
const modelId = data.modelId ?? "unknown";
|
|
@@ -115383,7 +115353,7 @@ var require_alerts_addon = __commonJS({
|
|
|
115383
115353
|
}
|
|
115384
115354
|
async emitAlert(alert) {
|
|
115385
115355
|
const existingRaw = await this.readAlertRaw(alert.id);
|
|
115386
|
-
const
|
|
115356
|
+
const toStore = mergeEmitAlert({
|
|
115387
115357
|
existing: existingRaw === null ? null : {
|
|
115388
115358
|
read: existingRaw.read,
|
|
115389
115359
|
episodeKey: existingRaw.episodeKey,
|
|
@@ -115391,20 +115361,10 @@ var require_alerts_addon = __commonJS({
|
|
|
115391
115361
|
},
|
|
115392
115362
|
incoming: alert
|
|
115393
115363
|
});
|
|
115394
|
-
const stored = alertWithRetainedPush(toStore, existingRaw?.push, existingRaw?.status);
|
|
115395
115364
|
const isNew = existingRaw === null;
|
|
115396
|
-
await this.persistAlert(
|
|
115365
|
+
const stored = await this.persistAlert(toStore);
|
|
115397
115366
|
if (isNew) this.emitAlertCreatedEvent(stored);
|
|
115398
115367
|
else this.emitAlertUpdatedEvent(alert.id, stored);
|
|
115399
|
-
if (queuePush) {
|
|
115400
|
-
const { key, line } = criticalPushPayload(stored);
|
|
115401
|
-
this.queuePush({
|
|
115402
|
-
alertId: stored.id,
|
|
115403
|
-
key,
|
|
115404
|
-
title: stored.title,
|
|
115405
|
-
line
|
|
115406
|
-
});
|
|
115407
|
-
}
|
|
115408
115368
|
await this.enforceMaxAlerts();
|
|
115409
115369
|
await this.enforceRetention();
|
|
115410
115370
|
}
|
|
@@ -115419,15 +115379,73 @@ var require_alerts_addon = __commonJS({
|
|
|
115419
115379
|
* Read-merge-write: SettingsBackend.update() replaces the entire `data` blob,
|
|
115420
115380
|
* so we must read the existing record, merge the patch, and write back.
|
|
115421
115381
|
*/
|
|
115422
|
-
|
|
115382
|
+
/** Alert writes (stamp + store + announce) from any caller, one at a time. */
|
|
115383
|
+
writeChain = Promise.resolve();
|
|
115384
|
+
serializedWrite(write) {
|
|
115385
|
+
const run = this.writeChain.then(write, write);
|
|
115386
|
+
this.writeChain = run.catch(() => void 0);
|
|
115387
|
+
return run;
|
|
115388
|
+
}
|
|
115389
|
+
mergeUpdate(id, patch) {
|
|
115390
|
+
return this.serializedWrite(() => this.mergeUpdateNow(id, patch));
|
|
115391
|
+
}
|
|
115392
|
+
async mergeUpdateNow(id, patch) {
|
|
115423
115393
|
const store = this.alertStore;
|
|
115424
115394
|
if (store === null) return;
|
|
115425
|
-
await
|
|
115395
|
+
const previous = (await this.readAlertRaw(id))?.episode ?? null;
|
|
115396
|
+
const metadata = patch["metadata"];
|
|
115397
|
+
const keepEpisode = previous !== null && typeof metadata === "object" && metadata !== null ? { metadata: {
|
|
115398
|
+
...metadata,
|
|
115399
|
+
episodeId: previous.episodeId
|
|
115400
|
+
} } : {};
|
|
115401
|
+
await store.mergeUpdate(id, {
|
|
115402
|
+
...patch,
|
|
115403
|
+
...keepEpisode
|
|
115404
|
+
});
|
|
115405
|
+
const after = await store.getData(id);
|
|
115406
|
+
const parsed = after === null ? null : require_dist10.AlertSchema.safeParse({
|
|
115407
|
+
id,
|
|
115408
|
+
...after
|
|
115409
|
+
});
|
|
115410
|
+
if (parsed?.success === true) this.announceEpisode(previous, parsed.data);
|
|
115411
|
+
}
|
|
115412
|
+
/**
|
|
115413
|
+
* Store an alert, stamping its episode identity. The stored alert is what a
|
|
115414
|
+
* caller must use afterwards, and the opening or closing of a critical/error
|
|
115415
|
+
* episode is announced here, in the one place every write passes through.
|
|
115416
|
+
*/
|
|
115417
|
+
persistAlert(alert) {
|
|
115418
|
+
return this.serializedWrite(() => this.persistAlertNow(alert));
|
|
115426
115419
|
}
|
|
115427
|
-
async
|
|
115420
|
+
async persistAlertNow(alert) {
|
|
115428
115421
|
const store = this.alertStore;
|
|
115429
|
-
if (store === null) return;
|
|
115430
|
-
await
|
|
115422
|
+
if (store === null) return alert;
|
|
115423
|
+
const previous = (await this.readAlertRaw(alert.id))?.episode ?? null;
|
|
115424
|
+
const episodeId = nextEpisodeId({
|
|
115425
|
+
alertId: alert.id,
|
|
115426
|
+
previous,
|
|
115427
|
+
incomingKey: episodeKeyFromMetadata(alert.metadata),
|
|
115428
|
+
now: Date.now()
|
|
115429
|
+
});
|
|
115430
|
+
const stamped = {
|
|
115431
|
+
...alert,
|
|
115432
|
+
metadata: {
|
|
115433
|
+
...alert.metadata,
|
|
115434
|
+
episodeId
|
|
115435
|
+
}
|
|
115436
|
+
};
|
|
115437
|
+
await store.persist(stamped);
|
|
115438
|
+
this.announceEpisode(previous, stamped);
|
|
115439
|
+
return stamped;
|
|
115440
|
+
}
|
|
115441
|
+
/**
|
|
115442
|
+
* Announce an episode edge on the bus. Telemetry, and it may be dropped
|
|
115443
|
+
* (D8): Notification Center reconciles from the alerts store (D11, D49).
|
|
115444
|
+
*/
|
|
115445
|
+
announceEpisode(previous, alert) {
|
|
115446
|
+
const edge = episodeEdge(previous, episodeViewOf(alert));
|
|
115447
|
+
if (edge === null) return;
|
|
115448
|
+
this.ctx.eventBus?.emit(require_dist10.createEvent(require_dist10.EventCategory.AlertEpisode, EVENT_SOURCE, require_dist10.alertEpisodePayload(alert, edge, Date.now())));
|
|
115431
115449
|
}
|
|
115432
115450
|
emitAlertCreatedEvent(alert) {
|
|
115433
115451
|
this.ctx.eventBus?.emit(require_dist10.createEvent("alert.created", EVENT_SOURCE, {
|
|
@@ -115528,7 +115546,7 @@ var require_calendars_addon = __commonJS({
|
|
|
115528
115546
|
[Symbol.toStringTag]: { value: "Module" }
|
|
115529
115547
|
});
|
|
115530
115548
|
require_chunk_Cek0wNdY();
|
|
115531
|
-
var require_dist10 =
|
|
115549
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
115532
115550
|
var require_settle_sources = require_settle_sources_Bhsy57y();
|
|
115533
115551
|
var zod = require_zod();
|
|
115534
115552
|
var CALENDAR_COLOR_PALETTE = [
|
|
@@ -115746,11 +115764,11 @@ var require_calendars = __commonJS({
|
|
|
115746
115764
|
}
|
|
115747
115765
|
});
|
|
115748
115766
|
|
|
115749
|
-
// ../system/dist/composition-sources-
|
|
115750
|
-
var
|
|
115751
|
-
"../system/dist/composition-sources-
|
|
115767
|
+
// ../system/dist/composition-sources-Cukc78eu.js
|
|
115768
|
+
var require_composition_sources_Cukc78eu = __commonJS({
|
|
115769
|
+
"../system/dist/composition-sources-Cukc78eu.js"(exports) {
|
|
115752
115770
|
"use strict";
|
|
115753
|
-
var require_dist10 =
|
|
115771
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
115754
115772
|
function normalizedNativeOwner(owner) {
|
|
115755
115773
|
const trimmed = owner?.trim();
|
|
115756
115774
|
return trimmed ? trimmed : null;
|
|
@@ -115865,8 +115883,8 @@ var require_composer_addon = __commonJS({
|
|
|
115865
115883
|
[Symbol.toStringTag]: { value: "Module" }
|
|
115866
115884
|
});
|
|
115867
115885
|
require_chunk_Cek0wNdY();
|
|
115868
|
-
var require_dist10 =
|
|
115869
|
-
var require_composition_sources =
|
|
115886
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
115887
|
+
var require_composition_sources = require_composition_sources_Cukc78eu();
|
|
115870
115888
|
var zod = require_zod();
|
|
115871
115889
|
function isRecord$2(value) {
|
|
115872
115890
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -119676,7 +119694,7 @@ var require_console_logging = __commonJS({
|
|
|
119676
119694
|
[Symbol.toStringTag]: { value: "Module" }
|
|
119677
119695
|
});
|
|
119678
119696
|
require_chunk_Cek0wNdY();
|
|
119679
|
-
var require_dist10 =
|
|
119697
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
119680
119698
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
119681
119699
|
var LEVEL_RANK = {
|
|
119682
119700
|
debug: 0,
|
|
@@ -124069,9 +124087,9 @@ var require_core_blocks_addon = __commonJS({
|
|
|
124069
124087
|
"use strict";
|
|
124070
124088
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
124071
124089
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
124072
|
-
var require_dist10 =
|
|
124090
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
124073
124091
|
var require_read_all_rows$1 = require_read_all_rows_CVoO1ONM();
|
|
124074
|
-
var require_composition_sources =
|
|
124092
|
+
var require_composition_sources = require_composition_sources_Cukc78eu();
|
|
124075
124093
|
var require_prefix_range = require_prefix_range_D_KueXbQ();
|
|
124076
124094
|
var require_prefix_walk = require_prefix_walk_Dv6MLZlM();
|
|
124077
124095
|
var zod = require_zod();
|
|
@@ -126271,9 +126289,9 @@ var require_core_blocks = __commonJS({
|
|
|
126271
126289
|
}
|
|
126272
126290
|
});
|
|
126273
126291
|
|
|
126274
|
-
// ../types/dist/event-category-
|
|
126275
|
-
var
|
|
126276
|
-
"../types/dist/event-category-
|
|
126292
|
+
// ../types/dist/event-category-eSqkye-K.js
|
|
126293
|
+
var require_event_category_eSqkye_K = __commonJS({
|
|
126294
|
+
"../types/dist/event-category-eSqkye-K.js"(exports) {
|
|
126277
126295
|
"use strict";
|
|
126278
126296
|
var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
|
|
126279
126297
|
EventCategory2["SystemBoot"] = "system.boot";
|
|
@@ -126294,6 +126312,7 @@ var require_event_category_Hoe_mqbd = __commonJS({
|
|
|
126294
126312
|
EventCategory2["AddonRunnerRefused"] = "addon.runner-refused";
|
|
126295
126313
|
EventCategory2["ProcessStateChanged"] = "process.state-changed";
|
|
126296
126314
|
EventCategory2["SystemRunnerCheck"] = "system.runner-check";
|
|
126315
|
+
EventCategory2["AlertEpisode"] = "alert.episode";
|
|
126297
126316
|
EventCategory2["AddonError"] = "addon.error";
|
|
126298
126317
|
EventCategory2["AddonPageReady"] = "addon.page-ready";
|
|
126299
126318
|
EventCategory2["AddonWidgetReady"] = "addon.widget-ready";
|
|
@@ -126475,11 +126494,11 @@ var require_event_category_Hoe_mqbd = __commonJS({
|
|
|
126475
126494
|
}
|
|
126476
126495
|
});
|
|
126477
126496
|
|
|
126478
|
-
// ../types/dist/sleep-
|
|
126479
|
-
var
|
|
126480
|
-
"../types/dist/sleep-
|
|
126497
|
+
// ../types/dist/sleep-BE7_6UnC.js
|
|
126498
|
+
var require_sleep_BE7_6UnC = __commonJS({
|
|
126499
|
+
"../types/dist/sleep-BE7_6UnC.js"(exports) {
|
|
126481
126500
|
"use strict";
|
|
126482
|
-
var require_event_category =
|
|
126501
|
+
var require_event_category = require_event_category_eSqkye_K();
|
|
126483
126502
|
var zod = require_zod();
|
|
126484
126503
|
var AUDIO_CHUNK_FORMATS = [
|
|
126485
126504
|
"f32le",
|
|
@@ -131733,6 +131752,7 @@ var require_sleep_REHQvLV6 = __commonJS({
|
|
|
131733
131752
|
const dishwasherInterface = {
|
|
131734
131753
|
start: (input) => dispatch("dishwasher", "dishwasher", "start", "mutation", input),
|
|
131735
131754
|
pause: (input) => dispatch("dishwasher", "dishwasher", "pause", "mutation", input),
|
|
131755
|
+
resume: (input) => dispatch("dishwasher", "dishwasher", "resume", "mutation", input),
|
|
131736
131756
|
stop: (input) => dispatch("dishwasher", "dishwasher", "stop", "mutation", input),
|
|
131737
131757
|
setProgram: (input) => dispatch("dishwasher", "dishwasher", "setProgram", "mutation", input),
|
|
131738
131758
|
setPower: (input) => dispatch("dishwasher", "dishwasher", "setPower", "mutation", input),
|
|
@@ -131743,6 +131763,7 @@ var require_sleep_REHQvLV6 = __commonJS({
|
|
|
131743
131763
|
setVarioSpeedPlus: (input) => dispatch("dishwasher", "dishwasher", "setVarioSpeedPlus", "mutation", input),
|
|
131744
131764
|
setChildLock: (input) => dispatch("dishwasher", "dishwasher", "setChildLock", "mutation", input),
|
|
131745
131765
|
setOption: (input) => dispatch("dishwasher", "dishwasher", "setOption", "mutation", input),
|
|
131766
|
+
getOptions: (input) => dispatch("dishwasher", "dishwasher", "getOptions", "query", input),
|
|
131746
131767
|
getStatus: (input) => dispatch("dishwasher", "dishwasher", "getStatus", "query", input)
|
|
131747
131768
|
};
|
|
131748
131769
|
const doorbellInterface = { getStatus: (input) => dispatch("doorbell", "doorbell", "getStatus", "query", input) };
|
|
@@ -134040,8 +134061,8 @@ var require_addon = __commonJS({
|
|
|
134040
134061
|
"../types/dist/addon.js"(exports) {
|
|
134041
134062
|
"use strict";
|
|
134042
134063
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
134043
|
-
var require_sleep =
|
|
134044
|
-
var require_event_category =
|
|
134064
|
+
var require_sleep = require_sleep_BE7_6UnC();
|
|
134065
|
+
var require_event_category = require_event_category_eSqkye_K();
|
|
134045
134066
|
var require_err_msg = require_err_msg_BhVbr0NX();
|
|
134046
134067
|
var CAP_INPUT_DEFAULTS = Object.freeze({
|
|
134047
134068
|
"addons": { "getLogs": { "limit": 100 } },
|
|
@@ -134945,6 +134966,15 @@ var require_addon = __commonJS({
|
|
|
134945
134966
|
"valueType": "boolean"
|
|
134946
134967
|
}],
|
|
134947
134968
|
"dishwasher": [
|
|
134969
|
+
{
|
|
134970
|
+
"path": "availability",
|
|
134971
|
+
"valueType": "enum",
|
|
134972
|
+
"enumValues": [
|
|
134973
|
+
"available",
|
|
134974
|
+
"offline",
|
|
134975
|
+
"description-missing"
|
|
134976
|
+
]
|
|
134977
|
+
},
|
|
134948
134978
|
{
|
|
134949
134979
|
"path": "state",
|
|
134950
134980
|
"valueType": "enum",
|
|
@@ -134957,12 +134987,35 @@ var require_addon = __commonJS({
|
|
|
134957
134987
|
"unavailable"
|
|
134958
134988
|
]
|
|
134959
134989
|
},
|
|
134990
|
+
{
|
|
134991
|
+
"path": "operationState",
|
|
134992
|
+
"valueType": "enum",
|
|
134993
|
+
"enumValues": [
|
|
134994
|
+
"Inactive",
|
|
134995
|
+
"Ready",
|
|
134996
|
+
"DelayedStart",
|
|
134997
|
+
"Run",
|
|
134998
|
+
"Pause",
|
|
134999
|
+
"ActionRequired",
|
|
135000
|
+
"Finished",
|
|
135001
|
+
"Error",
|
|
135002
|
+
"Aborting"
|
|
135003
|
+
]
|
|
135004
|
+
},
|
|
134960
135005
|
{
|
|
134961
135006
|
"path": "program",
|
|
134962
135007
|
"valueType": "string"
|
|
134963
135008
|
},
|
|
134964
135009
|
{
|
|
134965
|
-
"path": "
|
|
135010
|
+
"path": "selectedProgram",
|
|
135011
|
+
"valueType": "string"
|
|
135012
|
+
},
|
|
135013
|
+
{
|
|
135014
|
+
"path": "remainingSeconds",
|
|
135015
|
+
"valueType": "number"
|
|
135016
|
+
},
|
|
135017
|
+
{
|
|
135018
|
+
"path": "delayedStartSeconds",
|
|
134966
135019
|
"valueType": "number"
|
|
134967
135020
|
},
|
|
134968
135021
|
{
|
|
@@ -134973,14 +135026,30 @@ var require_addon = __commonJS({
|
|
|
134973
135026
|
"path": "doorOpen",
|
|
134974
135027
|
"valueType": "boolean"
|
|
134975
135028
|
},
|
|
135029
|
+
{
|
|
135030
|
+
"path": "doorLocked",
|
|
135031
|
+
"valueType": "boolean"
|
|
135032
|
+
},
|
|
134976
135033
|
{
|
|
134977
135034
|
"path": "remoteStartAllowed",
|
|
134978
135035
|
"valueType": "boolean"
|
|
134979
135036
|
},
|
|
135037
|
+
{
|
|
135038
|
+
"path": "remoteControlActive",
|
|
135039
|
+
"valueType": "boolean"
|
|
135040
|
+
},
|
|
135041
|
+
{
|
|
135042
|
+
"path": "localControlActive",
|
|
135043
|
+
"valueType": "boolean"
|
|
135044
|
+
},
|
|
134980
135045
|
{
|
|
134981
135046
|
"path": "powerOn",
|
|
134982
135047
|
"valueType": "boolean"
|
|
134983
135048
|
},
|
|
135049
|
+
{
|
|
135050
|
+
"path": "powerState",
|
|
135051
|
+
"valueType": "string"
|
|
135052
|
+
},
|
|
134984
135053
|
{
|
|
134985
135054
|
"path": "saltLevel",
|
|
134986
135055
|
"valueType": "enum",
|
|
@@ -136638,7 +136707,7 @@ var require_device_manager_addon = __commonJS({
|
|
|
136638
136707
|
[Symbol.toStringTag]: { value: "Module" }
|
|
136639
136708
|
});
|
|
136640
136709
|
require_chunk_Cek0wNdY();
|
|
136641
|
-
var require_dist10 =
|
|
136710
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
136642
136711
|
var require_read_all_rows$1 = require_read_all_rows_CVoO1ONM();
|
|
136643
136712
|
var require_prefix_range = require_prefix_range_D_KueXbQ();
|
|
136644
136713
|
var require_prefix_walk = require_prefix_walk_Dv6MLZlM();
|
|
@@ -145712,7 +145781,7 @@ var require_hub_forwarder = __commonJS({
|
|
|
145712
145781
|
[Symbol.toStringTag]: { value: "Module" }
|
|
145713
145782
|
});
|
|
145714
145783
|
require_chunk_Cek0wNdY();
|
|
145715
|
-
var require_dist10 =
|
|
145784
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
145716
145785
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
145717
145786
|
var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
|
|
145718
145787
|
var HubForwarderDestination = class {
|
|
@@ -145849,7 +145918,7 @@ var require_liveness_monitor_addon = __commonJS({
|
|
|
145849
145918
|
"use strict";
|
|
145850
145919
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
145851
145920
|
require_chunk_Cek0wNdY();
|
|
145852
|
-
var require_dist10 =
|
|
145921
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
145853
145922
|
var NO_DEVICES = "liveness:no-devices";
|
|
145854
145923
|
var ALL_OFFLINE = "liveness:all-devices-offline";
|
|
145855
145924
|
var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
|
|
@@ -146212,12 +146281,12 @@ var require_local_auth_addon = __commonJS({
|
|
|
146212
146281
|
[Symbol.toStringTag]: { value: "Module" }
|
|
146213
146282
|
});
|
|
146214
146283
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
146215
|
-
var require_dist10 =
|
|
146284
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
146216
146285
|
var require_read_all_rows$1 = require_read_all_rows_CVoO1ONM();
|
|
146217
146286
|
var require_safe_buffer$1 = require_safe_buffer_D3aoa_7X();
|
|
146218
146287
|
var require_ms$1 = require_ms_LB3giGoU();
|
|
146219
|
-
var require_device_ca =
|
|
146220
|
-
var require_phase6_declare_gate =
|
|
146288
|
+
var require_device_ca = require_device_ca_B3hUVfYk();
|
|
146289
|
+
var require_phase6_declare_gate = require_phase6_declare_gate_DwYAep7y();
|
|
146221
146290
|
var zod = require_zod();
|
|
146222
146291
|
var node_crypto = __require("crypto");
|
|
146223
146292
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
@@ -157012,7 +157081,7 @@ var require_loki_logging = __commonJS({
|
|
|
157012
157081
|
[Symbol.toStringTag]: { value: "Module" }
|
|
157013
157082
|
});
|
|
157014
157083
|
require_chunk_Cek0wNdY();
|
|
157015
|
-
var require_dist10 =
|
|
157084
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
157016
157085
|
function sanitizeLabelName(raw) {
|
|
157017
157086
|
const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
|
|
157018
157087
|
return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
|
|
@@ -157684,7 +157753,7 @@ var require_native_metrics_addon = __commonJS({
|
|
|
157684
157753
|
[Symbol.toStringTag]: { value: "Module" }
|
|
157685
157754
|
});
|
|
157686
157755
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
157687
|
-
var require_dist10 =
|
|
157756
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
157688
157757
|
var node_fs_promises = __require("fs/promises");
|
|
157689
157758
|
var node_util = __require("util");
|
|
157690
157759
|
var node_os = __require("os");
|
|
@@ -160078,7 +160147,7 @@ var require_device_history_addon = __commonJS({
|
|
|
160078
160147
|
[Symbol.toStringTag]: { value: "Module" }
|
|
160079
160148
|
});
|
|
160080
160149
|
require_chunk_Cek0wNdY();
|
|
160081
|
-
var require_dist10 =
|
|
160150
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
160082
160151
|
function subjectIdOf(subject) {
|
|
160083
160152
|
return subject.kind === "device" ? `d:${subject.deviceId}` : `n:${subject.nodeId}`;
|
|
160084
160153
|
}
|
|
@@ -162757,7 +162826,7 @@ var require_filesystem_storage_addon = __commonJS({
|
|
|
162757
162826
|
[Symbol.toStringTag]: { value: "Module" }
|
|
162758
162827
|
});
|
|
162759
162828
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
162760
|
-
var require_dist10 =
|
|
162829
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
162761
162830
|
var node_crypto = __require("crypto");
|
|
162762
162831
|
var node_fs_promises = __require("fs/promises");
|
|
162763
162832
|
var node_path = __require("path");
|
|
@@ -163867,12 +163936,12 @@ var require_lib = __commonJS({
|
|
|
163867
163936
|
}
|
|
163868
163937
|
});
|
|
163869
163938
|
|
|
163870
|
-
// ../system/dist/wal-maintenance-
|
|
163871
|
-
var
|
|
163872
|
-
"../system/dist/wal-maintenance-
|
|
163939
|
+
// ../system/dist/wal-maintenance-Bo_lo3Dh.js
|
|
163940
|
+
var require_wal_maintenance_Bo_lo3Dh = __commonJS({
|
|
163941
|
+
"../system/dist/wal-maintenance-Bo_lo3Dh.js"(exports) {
|
|
163873
163942
|
"use strict";
|
|
163874
163943
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
163875
|
-
var require_dist10 =
|
|
163944
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
163876
163945
|
var require_prefix_range = require_prefix_range_D_KueXbQ();
|
|
163877
163946
|
var node_crypto = __require("crypto");
|
|
163878
163947
|
var node_module = __require("module");
|
|
@@ -164810,8 +164879,41 @@ CREATE TABLE IF NOT EXISTS _record_sequences (
|
|
|
164810
164879
|
if (this.schemaReady) {
|
|
164811
164880
|
ensureRecordsSchema(db);
|
|
164812
164881
|
for (const row of loadKinds(db)) this.kinds.set(keyOf(row.owner, row.kind), row);
|
|
164882
|
+
this.correctSequences();
|
|
164883
|
+
}
|
|
164884
|
+
}
|
|
164885
|
+
/**
|
|
164886
|
+
* Boot correction: every kind that ever allocated an id has its counter raised
|
|
164887
|
+
* above the highest numeric id it holds. Adopted legacy rows (or any caller
|
|
164888
|
+
* chosen numeric id) kept ids far above a counter that started at 1, and the
|
|
164889
|
+
* upsert would have overwritten another device's row on the first collision.
|
|
164890
|
+
* Runs on the engine's own connection, over the (kind_id, id) unique index.
|
|
164891
|
+
*/
|
|
164892
|
+
correctSequences() {
|
|
164893
|
+
const seq = this.db.prepare("SELECT kind_id FROM _record_sequences");
|
|
164894
|
+
for (const { kind_id: kindId } of seq.all()) {
|
|
164895
|
+
const top = this.db.prepare("SELECT MAX(CAST(id AS INTEGER)) AS m FROM records WHERE kind_id = ? AND id GLOB '[0-9]*'").get(kindId);
|
|
164896
|
+
if (top?.m === null || top === void 0) continue;
|
|
164897
|
+
if (this.db.prepare("UPDATE _record_sequences SET next = ? WHERE kind_id = ? AND next < ?").run(top.m + 1, kindId, top.m + 1).changes > 0) this.options.logger.warn("records: id sequence raised above the highest stored id", { meta: {
|
|
164898
|
+
kindId,
|
|
164899
|
+
next: top.m + 1
|
|
164900
|
+
} });
|
|
164813
164901
|
}
|
|
164814
164902
|
}
|
|
164903
|
+
/** Ids handed out by allocateId and not yet written: their first write is insert-only. */
|
|
164904
|
+
pendingAllocated = /* @__PURE__ */ new Set();
|
|
164905
|
+
static PENDING_ALLOCATED_MAX = 4096;
|
|
164906
|
+
/** Raise a kind's counter above the numeric ids of a caller-supplied batch (adoption). */
|
|
164907
|
+
raiseSequenceFor(k, records) {
|
|
164908
|
+
let top = -1;
|
|
164909
|
+
for (const r of records) if (/^\d{1,15}$/.test(r.id)) top = Math.max(top, Number(r.id));
|
|
164910
|
+
if (top < 0) return;
|
|
164911
|
+
if (k.declaration.adoptsFrom !== void 0) {
|
|
164912
|
+
this.db.prepare("INSERT INTO _record_sequences(kind_id, next) VALUES (?, ?) ON CONFLICT(kind_id) DO UPDATE SET next = MAX(next, excluded.next)").run(k.kindId, top + 1);
|
|
164913
|
+
return;
|
|
164914
|
+
}
|
|
164915
|
+
this.db.prepare("UPDATE _record_sequences SET next = ? WHERE kind_id = ? AND next < ?").run(top + 1, k.kindId, top + 1);
|
|
164916
|
+
}
|
|
164815
164917
|
schemaReady;
|
|
164816
164918
|
kindOf(owner, kind) {
|
|
164817
164919
|
const row = this.kinds.get(keyOf(owner, kind));
|
|
@@ -164950,6 +165052,17 @@ CREATE TABLE IF NOT EXISTS _record_sequences (
|
|
|
164950
165052
|
/** One row, inside the caller's transaction. */
|
|
164951
165053
|
writeRecord(owner, k, rec, ifRev, nowMs) {
|
|
164952
165054
|
const header = validateHeader(k.kind, k.declaration, rec, nowMs);
|
|
165055
|
+
const allocatedKey = `${k.kindId}:${rec.id}`;
|
|
165056
|
+
if (this.pendingAllocated.has(allocatedKey) && this.storedRow(k, rec.id) !== void 0) {
|
|
165057
|
+
this.options.logger.warn("records: an allocated id collided with a stored row; write refused", {
|
|
165058
|
+
tags: { deviceId: rec.deviceId },
|
|
165059
|
+
meta: {
|
|
165060
|
+
kind: k.kind,
|
|
165061
|
+
id: rec.id
|
|
165062
|
+
}
|
|
165063
|
+
});
|
|
165064
|
+
throw new require_dist10.RevConflictError(`${k.kind}/${rec.id}: an allocated id is insert-only and a row already holds it`);
|
|
165065
|
+
}
|
|
164953
165066
|
const stored = k.declaration.secretPaths.length > 0 || ifRev !== void 0 ? this.storedRow(k, rec.id) : void 0;
|
|
164954
165067
|
if (ifRev !== void 0) {
|
|
164955
165068
|
if (ifRev === 0 && stored !== void 0) throw new require_dist10.RevConflictError(`${k.kind}/${rec.id}: the row exists (ifRev 0 means "must not exist")`);
|
|
@@ -164963,6 +165076,7 @@ CREATE TABLE IF NOT EXISTS _record_sequences (
|
|
|
164963
165076
|
} }), nowMs);
|
|
164964
165077
|
const row = this.wrapWrite(k, () => this.db.prepare(this.upsertSql(k.kindId)).get(header.id, header.deviceId, header.at, header.expiresAt, nowMs, json));
|
|
164965
165078
|
if (row === void 0) throw new Error("records: the upsert returned no revision");
|
|
165079
|
+
this.pendingAllocated.delete(allocatedKey);
|
|
164966
165080
|
return {
|
|
164967
165081
|
rev: row.rev,
|
|
164968
165082
|
releasedRefs: checked.releasedRefs
|
|
@@ -164987,6 +165101,7 @@ CREATE TABLE IF NOT EXISTS _record_sequences (
|
|
|
164987
165101
|
const released = [];
|
|
164988
165102
|
this.timed("putMany", input.kind, () => this.db.transaction(() => {
|
|
164989
165103
|
for (const rec of input.records) released.push(...this.writeRecord(input.owner, k, rec, void 0, nowMs).releasedRefs);
|
|
165104
|
+
this.raiseSequenceFor(k, input.records);
|
|
164990
165105
|
})());
|
|
164991
165106
|
this.afterWrite(k, input.records.map((r) => r.deviceId));
|
|
164992
165107
|
return {
|
|
@@ -165109,6 +165224,11 @@ CREATE TABLE IF NOT EXISTS _record_sequences (
|
|
|
165109
165224
|
const k = this.kindOf(input.owner, input.kind);
|
|
165110
165225
|
const row = this.db.prepare("INSERT INTO _record_sequences(kind_id, next) VALUES (?, 2) ON CONFLICT(kind_id) DO UPDATE SET next = next + 1 RETURNING next - 1 AS id").get(k.kindId);
|
|
165111
165226
|
if (row === void 0) throw new Error("records: the sequence returned no id");
|
|
165227
|
+
this.pendingAllocated.add(`${k.kindId}:${row.id}`);
|
|
165228
|
+
if (this.pendingAllocated.size > RecordsEngine2.PENDING_ALLOCATED_MAX) {
|
|
165229
|
+
const oldest = this.pendingAllocated.values().next();
|
|
165230
|
+
if (oldest.done !== true) this.pendingAllocated.delete(oldest.value);
|
|
165231
|
+
}
|
|
165112
165232
|
return { id: row.id };
|
|
165113
165233
|
}
|
|
165114
165234
|
/**
|
|
@@ -168071,9 +168191,9 @@ var require_sqlite_settings_addon = __commonJS({
|
|
|
168071
168191
|
[Symbol.toStringTag]: { value: "Module" }
|
|
168072
168192
|
});
|
|
168073
168193
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
168074
|
-
var require_dist10 =
|
|
168194
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
168075
168195
|
var require_retired_settings_keys = require_retired_settings_keys_D_VwZiDt();
|
|
168076
|
-
var require_wal_maintenance =
|
|
168196
|
+
var require_wal_maintenance = require_wal_maintenance_Bo_lo3Dh();
|
|
168077
168197
|
var require_sqlite_snapshot_protocol = require_sqlite_snapshot_protocol_B9OndqZv();
|
|
168078
168198
|
var require_wal_checkpoint_policy = require_wal_checkpoint_policy_d2z2qPqx();
|
|
168079
168199
|
var node_fs_promises = __require("fs/promises");
|
|
@@ -169930,7 +170050,7 @@ var require_sqlite_storage = __commonJS({
|
|
|
169930
170050
|
});
|
|
169931
170051
|
require_chunk_Cek0wNdY();
|
|
169932
170052
|
var require_builtins_sqlite_storage_filesystem_storage_addon = require_filesystem_storage_addon();
|
|
169933
|
-
var require_wal_maintenance =
|
|
170053
|
+
var require_wal_maintenance = require_wal_maintenance_Bo_lo3Dh();
|
|
169934
170054
|
var require_builtins_sqlite_storage_sqlite_settings_addon = require_sqlite_settings_addon();
|
|
169935
170055
|
var ConfigStore = class {
|
|
169936
170056
|
db;
|
|
@@ -170014,7 +170134,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
170014
170134
|
[Symbol.toStringTag]: { value: "Module" }
|
|
170015
170135
|
});
|
|
170016
170136
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
170017
|
-
var require_dist10 =
|
|
170137
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
170018
170138
|
var require_read_all_rows$1 = require_read_all_rows_CVoO1ONM();
|
|
170019
170139
|
var zod = require_zod();
|
|
170020
170140
|
var node_crypto = __require("crypto");
|
|
@@ -170038,6 +170158,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
170038
170158
|
mode: require_dist10.StorageLocationModeSchema.optional(),
|
|
170039
170159
|
isDefault: zod.z.boolean().optional()
|
|
170040
170160
|
});
|
|
170161
|
+
var StorageSeedMarkerBodySchema = zod.z.object({ seededAt: zod.z.number() });
|
|
170041
170162
|
var StorageDrainStateBodySchema = zod.z.object({
|
|
170042
170163
|
locationId: zod.z.string(),
|
|
170043
170164
|
startedAtMs: zod.z.number(),
|
|
@@ -170062,6 +170183,14 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
170062
170183
|
retention: { none: "operator delete or declaration prune only" },
|
|
170063
170184
|
adoptsFrom: STORAGE_LOCATIONS
|
|
170064
170185
|
},
|
|
170186
|
+
"seed-markers": {
|
|
170187
|
+
schema: StorageSeedMarkerBodySchema,
|
|
170188
|
+
class: "config",
|
|
170189
|
+
writeTrigger: "a declared location type was seeded (or found already present on an existing install); the id is the type",
|
|
170190
|
+
device: "none",
|
|
170191
|
+
at: "none",
|
|
170192
|
+
retention: { none: "one row per location type ever seeded \u2014 what makes an operator delete stick" }
|
|
170193
|
+
},
|
|
170065
170194
|
"drain-state": {
|
|
170066
170195
|
schema: StorageDrainStateBodySchema,
|
|
170067
170196
|
class: "config",
|
|
@@ -170141,9 +170270,27 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
170141
170270
|
store;
|
|
170142
170271
|
declared = false;
|
|
170143
170272
|
locationsKind;
|
|
170144
|
-
constructor(store, locationsKind = null) {
|
|
170273
|
+
constructor(store, locationsKind = null, seedMarkersKind = null) {
|
|
170145
170274
|
this.store = store;
|
|
170146
170275
|
this.locationsKind = locationsKind;
|
|
170276
|
+
this.seedMarkersKind = seedMarkersKind;
|
|
170277
|
+
}
|
|
170278
|
+
seedMarkersKind;
|
|
170279
|
+
static seedMarkersOf(records) {
|
|
170280
|
+
return records.kind(storageOrchestratorRecordKinds["seed-markers"]);
|
|
170281
|
+
}
|
|
170282
|
+
async loadSeededTypes() {
|
|
170283
|
+
const kind = this.seedMarkersKind;
|
|
170284
|
+
if (kind === null) return [];
|
|
170285
|
+
return (await (0, import_read_all_rows.readAllRows)(kind)).map((r) => r.id);
|
|
170286
|
+
}
|
|
170287
|
+
async markTypeSeeded(type) {
|
|
170288
|
+
const kind = this.seedMarkersKind;
|
|
170289
|
+
if (kind === null) return;
|
|
170290
|
+
await kind.put({
|
|
170291
|
+
id: type,
|
|
170292
|
+
data: { seededAt: Date.now() }
|
|
170293
|
+
});
|
|
170147
170294
|
}
|
|
170148
170295
|
static recordStoresOf(records) {
|
|
170149
170296
|
return records.kind(storageOrchestratorRecordKinds.locations);
|
|
@@ -171110,20 +171257,77 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
171110
171257
|
}
|
|
171111
171258
|
};
|
|
171112
171259
|
}
|
|
171113
|
-
|
|
171260
|
+
var STORAGE_CLASS_SUBTREES = {
|
|
171261
|
+
eventMedia: ["events"],
|
|
171262
|
+
recordingsLow: ["low"],
|
|
171263
|
+
recordings: ["high", "mid"]
|
|
171264
|
+
};
|
|
171265
|
+
function isDotEntry(name) {
|
|
171266
|
+
return name.startsWith(".");
|
|
171267
|
+
}
|
|
171268
|
+
async function dirHasAnyEntry(dir) {
|
|
171269
|
+
let handle;
|
|
171270
|
+
try {
|
|
171271
|
+
handle = await (0, node_fs_promises.opendir)(dir);
|
|
171272
|
+
} catch (err) {
|
|
171273
|
+
if (err.code === "ENOENT") return false;
|
|
171274
|
+
throw err;
|
|
171275
|
+
}
|
|
171276
|
+
try {
|
|
171277
|
+
return await handle.read() !== null;
|
|
171278
|
+
} finally {
|
|
171279
|
+
await handle.close();
|
|
171280
|
+
}
|
|
171281
|
+
}
|
|
171282
|
+
async function probeLocalDirectoryOccupancy(input) {
|
|
171283
|
+
let names;
|
|
171284
|
+
try {
|
|
171285
|
+
names = await (0, node_fs_promises.readdir)(input.basePath);
|
|
171286
|
+
} catch (err) {
|
|
171287
|
+
if (err.code === "ENOENT") return "empty";
|
|
171288
|
+
return "unknown";
|
|
171289
|
+
}
|
|
171290
|
+
const visible = names.filter((name) => !isDotEntry(name));
|
|
171291
|
+
const subtrees = STORAGE_CLASS_SUBTREES[input.type];
|
|
171292
|
+
if (subtrees === void 0) return visible.length > 0 ? "occupied" : "empty";
|
|
171293
|
+
try {
|
|
171294
|
+
for (const camera of visible) for (const subtree of subtrees) if (await dirHasAnyEntry(node_path.default.join(input.basePath, camera, subtree))) return "occupied";
|
|
171295
|
+
} catch {
|
|
171296
|
+
return "unknown";
|
|
171297
|
+
}
|
|
171298
|
+
return "empty";
|
|
171299
|
+
}
|
|
171300
|
+
var STORAGE_CLASS_ROOT_SUBTREES = { homekitClips: ["homekit-clips"] };
|
|
171301
|
+
function classifyPath(type, relativePath) {
|
|
171302
|
+
const rootSubtrees = STORAGE_CLASS_ROOT_SUBTREES[type];
|
|
171303
|
+
const cameraSubtrees = STORAGE_CLASS_SUBTREES[type];
|
|
171304
|
+
if (rootSubtrees === void 0 && cameraSubtrees === void 0) return "own";
|
|
171305
|
+
const segments = relativePath.split("/").filter((segment) => segment.length > 0);
|
|
171306
|
+
if (rootSubtrees !== void 0) {
|
|
171307
|
+
const top = segments[0];
|
|
171308
|
+
return top !== void 0 && rootSubtrees.includes(top) ? "own" : "foreign";
|
|
171309
|
+
}
|
|
171310
|
+
if (segments.length < 2) return "descend";
|
|
171311
|
+
const subtree = segments[1];
|
|
171312
|
+
return subtree !== void 0 && cameraSubtrees?.includes(subtree) === true ? "own" : "foreign";
|
|
171313
|
+
}
|
|
171314
|
+
async function collectFiles(io, scope, prefix) {
|
|
171114
171315
|
const entries = await io.list(prefix);
|
|
171115
171316
|
const files = [];
|
|
171116
171317
|
for (const entry of entries) {
|
|
171318
|
+
const verdict = scope(entry);
|
|
171319
|
+
if (verdict === "foreign") continue;
|
|
171117
171320
|
if ((await io.list(entry)).length > 0) {
|
|
171118
|
-
files.push(...await collectFiles(io, entry));
|
|
171321
|
+
files.push(...await collectFiles(io, scope, entry));
|
|
171119
171322
|
continue;
|
|
171120
171323
|
}
|
|
171121
|
-
files.push(entry);
|
|
171324
|
+
if (verdict === "own") files.push(entry);
|
|
171122
171325
|
}
|
|
171123
171326
|
return files;
|
|
171124
171327
|
}
|
|
171125
|
-
|
|
171126
|
-
|
|
171328
|
+
var WHOLE_ROOT = () => "own";
|
|
171329
|
+
async function moveLocationTree(io, scope = WHOLE_ROOT) {
|
|
171330
|
+
const candidates = await collectFiles(io, scope);
|
|
171127
171331
|
const copied = [];
|
|
171128
171332
|
let bytes = 0;
|
|
171129
171333
|
for (const relativePath of candidates) {
|
|
@@ -171145,6 +171349,118 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
171145
171349
|
bytes
|
|
171146
171350
|
};
|
|
171147
171351
|
}
|
|
171352
|
+
var RepointRefusedError = class extends Error {
|
|
171353
|
+
reason;
|
|
171354
|
+
name = "RepointRefusedError";
|
|
171355
|
+
constructor(reason, message) {
|
|
171356
|
+
super(message);
|
|
171357
|
+
this.reason = reason;
|
|
171358
|
+
}
|
|
171359
|
+
};
|
|
171360
|
+
function rootsOverlap(a, b) {
|
|
171361
|
+
if (a === b) return true;
|
|
171362
|
+
const within = (inner, outer) => inner.startsWith(outer.endsWith("/") ? outer : `${outer}/`);
|
|
171363
|
+
return within(a, b) || within(b, a);
|
|
171364
|
+
}
|
|
171365
|
+
function basePathOf$1(config) {
|
|
171366
|
+
const raw = config["basePath"];
|
|
171367
|
+
return typeof raw === "string" && raw.length > 0 ? raw : null;
|
|
171368
|
+
}
|
|
171369
|
+
var LocationRepointer = class {
|
|
171370
|
+
deps;
|
|
171371
|
+
claims = /* @__PURE__ */ new Set();
|
|
171372
|
+
constructor(deps) {
|
|
171373
|
+
this.deps = deps;
|
|
171374
|
+
}
|
|
171375
|
+
/**
|
|
171376
|
+
* Move `stored`'s own subtree to `next`'s root, then run `commit` (the row
|
|
171377
|
+
* save) while the claim is still held. Throws {@link RepointRefusedError}
|
|
171378
|
+
* with NOTHING copied or deleted when a mover is on the root.
|
|
171379
|
+
*/
|
|
171380
|
+
async run(stored, next, commit) {
|
|
171381
|
+
const claim = await this.claim(stored, next);
|
|
171382
|
+
try {
|
|
171383
|
+
await this.refuseWhileMovers(claim, stored);
|
|
171384
|
+
const moved = await moveLocationTree(await this.deps.ioFor(stored, next), (path) => classifyPath(stored.type, path));
|
|
171385
|
+
this.logMoved(stored, next, moved);
|
|
171386
|
+
return await commit();
|
|
171387
|
+
} finally {
|
|
171388
|
+
this.claims.delete(claim);
|
|
171389
|
+
}
|
|
171390
|
+
}
|
|
171391
|
+
/**
|
|
171392
|
+
* May a mover that touches `locationIds` run? Refuses while a repoint holds
|
|
171393
|
+
* an overlapping root. Called by the owning addon AFTER its job is
|
|
171394
|
+
* registered, so the repoint's mover listing and this check cannot both miss.
|
|
171395
|
+
*/
|
|
171396
|
+
async clearance(locationIds) {
|
|
171397
|
+
const keys = await this.keysOf(locationIds);
|
|
171398
|
+
for (const claim of this.claims) if (claim.keys.some((held) => keys.some((key) => rootsOverlap(held, key)))) return {
|
|
171399
|
+
clear: false,
|
|
171400
|
+
reason: "repoint-active",
|
|
171401
|
+
repointLocationId: claim.locationId
|
|
171402
|
+
};
|
|
171403
|
+
return { clear: true };
|
|
171404
|
+
}
|
|
171405
|
+
async claim(stored, next) {
|
|
171406
|
+
const paths = [basePathOf$1(stored.config), basePathOf$1(next.config)].filter((path) => path !== null);
|
|
171407
|
+
const keys = await Promise.all(paths.map((path) => this.deps.resolveKey(path)));
|
|
171408
|
+
for (const other of this.claims) if (other.keys.some((held) => keys.some((key) => rootsOverlap(held, key)))) this.refuse(stored, "repoint-active", `a repoint of "${other.locationId}" holds the same root`);
|
|
171409
|
+
const claim = {
|
|
171410
|
+
locationId: stored.id,
|
|
171411
|
+
keys
|
|
171412
|
+
};
|
|
171413
|
+
this.claims.add(claim);
|
|
171414
|
+
return claim;
|
|
171415
|
+
}
|
|
171416
|
+
async refuseWhileMovers(claim, stored) {
|
|
171417
|
+
let movers;
|
|
171418
|
+
try {
|
|
171419
|
+
movers = await this.deps.listMovers();
|
|
171420
|
+
} catch (err) {
|
|
171421
|
+
this.claims.delete(claim);
|
|
171422
|
+
this.refuse(stored, "movers-unreadable", `the active movers could not be listed (${err instanceof Error ? err.message : String(err)})`);
|
|
171423
|
+
}
|
|
171424
|
+
for (const mover of movers) {
|
|
171425
|
+
if (mover.job.state !== "queued" && mover.job.state !== "running") continue;
|
|
171426
|
+
const touched = await this.keysOf(this.locationsTouchedBy(mover));
|
|
171427
|
+
if (claim.keys.some((held) => touched.some((key) => rootsOverlap(held, key)))) {
|
|
171428
|
+
this.claims.delete(claim);
|
|
171429
|
+
this.refuse(stored, "mover-active", `${mover.lane} mover ${mover.job.jobId} (${mover.job.fromLocationId} -> ${mover.job.toLocationId}) touches the same physical root`, {
|
|
171430
|
+
jobId: mover.job.jobId,
|
|
171431
|
+
lane: mover.lane
|
|
171432
|
+
});
|
|
171433
|
+
}
|
|
171434
|
+
}
|
|
171435
|
+
}
|
|
171436
|
+
locationsTouchedBy(mover) {
|
|
171437
|
+
return [mover.job.fromLocationId, mover.job.toLocationId];
|
|
171438
|
+
}
|
|
171439
|
+
/** `*` is the media mover's "from wherever the rows are": every eventMedia location. */
|
|
171440
|
+
async keysOf(locationIds) {
|
|
171441
|
+
const paths = locationIds.flatMap((id) => id === "*" ? this.deps.locationIdsOfType("eventMedia") : [id]).map((id) => this.deps.locationBasePath(id)).filter((path) => path !== null);
|
|
171442
|
+
return Promise.all(paths.map((path) => this.deps.resolveKey(path)));
|
|
171443
|
+
}
|
|
171444
|
+
refuse(stored, reason, detail, meta = {}) {
|
|
171445
|
+
this.deps.logger.warn("storage-orchestrator: REFUSING to re-point a location \u2014 nothing was moved", { meta: {
|
|
171446
|
+
id: stored.id,
|
|
171447
|
+
type: stored.type,
|
|
171448
|
+
reason,
|
|
171449
|
+
detail,
|
|
171450
|
+
...meta
|
|
171451
|
+
} });
|
|
171452
|
+
throw new RepointRefusedError(reason, `re-point of "${stored.id}" refused (${reason}): ${detail}`);
|
|
171453
|
+
}
|
|
171454
|
+
logMoved(stored, next, moved) {
|
|
171455
|
+
this.deps.logger.info("storage-orchestrator: singleton location re-pointed \u2014 its data was carried over", { meta: {
|
|
171456
|
+
id: stored.id,
|
|
171457
|
+
type: stored.type,
|
|
171458
|
+
from: basePathOf$1(stored.config),
|
|
171459
|
+
to: basePathOf$1(next.config),
|
|
171460
|
+
...moved
|
|
171461
|
+
} });
|
|
171462
|
+
}
|
|
171463
|
+
};
|
|
171148
171464
|
function resolveRefusalFor(location, locality) {
|
|
171149
171465
|
if (locality !== false) return null;
|
|
171150
171466
|
return `storage.resolve is a request for a path this node can open with node:fs, and location "${location.id}" is served by the remote provider "${location.providerId}" (nodeLocal: false) \u2014 the path it would return exists on the remote host, not here. Read and write this location through the storage cap (read/write, or beginUpload/writeChunk/finalizeUpload) instead.`;
|
|
@@ -171454,46 +171770,6 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
171454
171770
|
args: envelope.args
|
|
171455
171771
|
}, { timeout: HUB_SETTINGS_FORWARD_TIMEOUT_MS }));
|
|
171456
171772
|
}
|
|
171457
|
-
var STORAGE_CLASS_SUBTREES = {
|
|
171458
|
-
eventMedia: ["events"],
|
|
171459
|
-
recordingsLow: ["low"],
|
|
171460
|
-
recordings: ["high", "mid"]
|
|
171461
|
-
};
|
|
171462
|
-
function isDotEntry(name) {
|
|
171463
|
-
return name.startsWith(".");
|
|
171464
|
-
}
|
|
171465
|
-
async function dirHasAnyEntry(dir) {
|
|
171466
|
-
let handle;
|
|
171467
|
-
try {
|
|
171468
|
-
handle = await (0, node_fs_promises.opendir)(dir);
|
|
171469
|
-
} catch (err) {
|
|
171470
|
-
if (err.code === "ENOENT") return false;
|
|
171471
|
-
throw err;
|
|
171472
|
-
}
|
|
171473
|
-
try {
|
|
171474
|
-
return await handle.read() !== null;
|
|
171475
|
-
} finally {
|
|
171476
|
-
await handle.close();
|
|
171477
|
-
}
|
|
171478
|
-
}
|
|
171479
|
-
async function probeLocalDirectoryOccupancy(input) {
|
|
171480
|
-
let names;
|
|
171481
|
-
try {
|
|
171482
|
-
names = await (0, node_fs_promises.readdir)(input.basePath);
|
|
171483
|
-
} catch (err) {
|
|
171484
|
-
if (err.code === "ENOENT") return "empty";
|
|
171485
|
-
return "unknown";
|
|
171486
|
-
}
|
|
171487
|
-
const visible = names.filter((name) => !isDotEntry(name));
|
|
171488
|
-
const subtrees = STORAGE_CLASS_SUBTREES[input.type];
|
|
171489
|
-
if (subtrees === void 0) return visible.length > 0 ? "occupied" : "empty";
|
|
171490
|
-
try {
|
|
171491
|
-
for (const camera of visible) for (const subtree of subtrees) if (await dirHasAnyEntry(node_path.default.join(input.basePath, camera, subtree))) return "occupied";
|
|
171492
|
-
} catch {
|
|
171493
|
-
return "unknown";
|
|
171494
|
-
}
|
|
171495
|
-
return "empty";
|
|
171496
|
-
}
|
|
171497
171773
|
var DEFAULT_STALE_AFTER_MS = 6e4;
|
|
171498
171774
|
var LocationOccupancySlice = class {
|
|
171499
171775
|
deps;
|
|
@@ -171994,6 +172270,44 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
171994
172270
|
getLocalNodeId() {
|
|
171995
172271
|
return this.localNode;
|
|
171996
172272
|
}
|
|
172273
|
+
/**
|
|
172274
|
+
* Whether a seed must wait for an ANSWERED read of the store (D49). True on a
|
|
172275
|
+
* node whose locations live in a store: seeding before that read lands writes
|
|
172276
|
+
* defaults the store's own rows (not yet adopted, or not yet read) then
|
|
172277
|
+
* contradict. False on a node that has no store by design — it seeds in memory
|
|
172278
|
+
* at every boot.
|
|
172279
|
+
*/
|
|
172280
|
+
storeRequiredForSeed = false;
|
|
172281
|
+
setStoreRequiredForSeed(required) {
|
|
172282
|
+
this.storeRequiredForSeed = required;
|
|
172283
|
+
}
|
|
172284
|
+
/**
|
|
172285
|
+
* The location types a default was ever seeded for — null when the store
|
|
172286
|
+
* cannot remember (then a type with no row is seeded, as before). What makes
|
|
172287
|
+
* an operator's delete of a seeded default STICK: zero rows today is not
|
|
172288
|
+
* "fresh install", it is only fresh when nothing was ever seeded.
|
|
172289
|
+
*/
|
|
172290
|
+
seededTypes = null;
|
|
172291
|
+
/** The store held locations but no seed memory: an install older than the memory. */
|
|
172292
|
+
installPredatesSeedMemory = false;
|
|
172293
|
+
async loadSeedMemory(store, rowCount) {
|
|
172294
|
+
if (!store.loadSeededTypes) return;
|
|
172295
|
+
const types = await store.loadSeededTypes();
|
|
172296
|
+
this.seededTypes = new Set(types);
|
|
172297
|
+
this.installPredatesSeedMemory = types.length === 0 && rowCount > 0;
|
|
172298
|
+
}
|
|
172299
|
+
rememberSeeded(type) {
|
|
172300
|
+
const seeded = this.seededTypes;
|
|
172301
|
+
const store = this.locationStore;
|
|
172302
|
+
if (seeded === null || seeded.has(type) || !store?.markTypeSeeded) return;
|
|
172303
|
+
seeded.add(type);
|
|
172304
|
+
store.markTypeSeeded(type).catch((err) => {
|
|
172305
|
+
this.logger.error("storage-orchestrator: persisting the seed memory failed", { meta: {
|
|
172306
|
+
type,
|
|
172307
|
+
error: err instanceof Error ? err.message : String(err)
|
|
172308
|
+
} });
|
|
172309
|
+
});
|
|
172310
|
+
}
|
|
171997
172311
|
/** True once a persistence store is wired (constructor or {@link attachStore}). */
|
|
171998
172312
|
hasStore() {
|
|
171999
172313
|
return this.locationStore !== null;
|
|
@@ -172027,6 +172341,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
172027
172341
|
async attachStore(store) {
|
|
172028
172342
|
if (this.locationStore) return;
|
|
172029
172343
|
const rows = await store.loadAll();
|
|
172344
|
+
await this.loadSeedMemory(store, rows.length);
|
|
172030
172345
|
this.locationStore = store;
|
|
172031
172346
|
const dbIds = new Set(rows.map((r) => r.id));
|
|
172032
172347
|
for (const loc of rows) this.locations.set(loc.id, loc);
|
|
@@ -172165,6 +172480,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
172165
172480
|
async initialize() {
|
|
172166
172481
|
if (!this.locationStore) return;
|
|
172167
172482
|
const rows = await this.locationStore.loadAll();
|
|
172483
|
+
await this.loadSeedMemory(this.locationStore, rows.length);
|
|
172168
172484
|
for (const loc of rows) this.locations.set(loc.id, loc);
|
|
172169
172485
|
this.logger.info("storage-orchestrator: hydrated locations from store", { meta: { loaded: this.locations.size } });
|
|
172170
172486
|
this.migrateOntoTheWriteSet(rows);
|
|
@@ -172617,14 +172933,35 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
172617
172933
|
* directory for derivative slots like `recordingsLow` → `recordings`).
|
|
172618
172934
|
*/
|
|
172619
172935
|
seedDefaults(input) {
|
|
172936
|
+
if (this.storeRequiredForSeed && this.locationStore === null) {
|
|
172937
|
+
this.logger.warn("storage-orchestrator: seed deferred \u2014 the location store has not answered a read yet (not wired, adoption pending, or the read failed); seeding now could shadow the operator's existing locations");
|
|
172938
|
+
return {
|
|
172939
|
+
added: 0,
|
|
172940
|
+
deferred: "store-not-answered"
|
|
172941
|
+
};
|
|
172942
|
+
}
|
|
172620
172943
|
let added = 0;
|
|
172944
|
+
let deferredProvider = false;
|
|
172621
172945
|
const declById = new Map(input.declarations.map((d) => [d.id, d]));
|
|
172622
172946
|
const rootFor = (d) => {
|
|
172623
172947
|
const dedicated = d.defaultRoot === "media" ? input.mediaBasePath : d.defaultRoot === "backup" ? input.backupBasePath : void 0;
|
|
172624
172948
|
return node_path.join(dedicated ?? input.basePath, d.id);
|
|
172625
172949
|
};
|
|
172626
172950
|
for (const d of input.declarations) {
|
|
172627
|
-
if (this.hasAnyLocationOfType(d.id))
|
|
172951
|
+
if (this.hasAnyLocationOfType(d.id)) {
|
|
172952
|
+
this.rememberSeeded(d.id);
|
|
172953
|
+
continue;
|
|
172954
|
+
}
|
|
172955
|
+
if (this.seededTypes?.has(d.id)) continue;
|
|
172956
|
+
if (this.installPredatesSeedMemory) {
|
|
172957
|
+
this.logger.info("storage-orchestrator: existing install \u2014 not re-creating a default the operator may have removed", { meta: { type: d.id } });
|
|
172958
|
+
this.rememberSeeded(d.id);
|
|
172959
|
+
continue;
|
|
172960
|
+
}
|
|
172961
|
+
if (this.nodeLocalResolver !== null && this.nodeLocalResolver(input.providerId) === void 0) {
|
|
172962
|
+
deferredProvider = true;
|
|
172963
|
+
continue;
|
|
172964
|
+
}
|
|
172628
172965
|
const base = d.defaultsTo ? this.getLocationById(`${d.defaultsTo}:default`)?.config["basePath"] ?? rootFor(declById.get(d.defaultsTo) ?? d) : rootFor(d);
|
|
172629
172966
|
this.upsertLocation({
|
|
172630
172967
|
id: `${d.id}:default`,
|
|
@@ -172635,12 +172972,18 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
172635
172972
|
enabled: true,
|
|
172636
172973
|
isSystem: false
|
|
172637
172974
|
});
|
|
172975
|
+
this.rememberSeeded(d.id);
|
|
172638
172976
|
added++;
|
|
172639
172977
|
}
|
|
172640
172978
|
if (added > 0) this.logger.info("storage-orchestrator: seeded default locations", { meta: {
|
|
172641
172979
|
added,
|
|
172642
172980
|
basePath: input.basePath
|
|
172643
172981
|
} });
|
|
172982
|
+
if (deferredProvider) this.logger.info("storage-orchestrator: seed deferred for some types \u2014 provider not classified yet", { meta: { providerId: input.providerId } });
|
|
172983
|
+
return deferredProvider ? {
|
|
172984
|
+
added,
|
|
172985
|
+
deferred: "provider-unclassified"
|
|
172986
|
+
} : { added };
|
|
172644
172987
|
}
|
|
172645
172988
|
/**
|
|
172646
172989
|
* The same-type physical-root refusal (D389).
|
|
@@ -172972,29 +173315,69 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
172972
173315
|
lowPercent: 15,
|
|
172973
173316
|
criticalPercent: 5
|
|
172974
173317
|
};
|
|
172975
|
-
|
|
172976
|
-
|
|
172977
|
-
|
|
172978
|
-
|
|
172979
|
-
|
|
172980
|
-
|
|
172981
|
-
|
|
172982
|
-
|
|
172983
|
-
|
|
172984
|
-
|
|
172985
|
-
|
|
172986
|
-
|
|
173318
|
+
var UNMANAGED_HYSTERESIS_POINTS = 2;
|
|
173319
|
+
var MANAGED_LOW_ENTER = 0.8;
|
|
173320
|
+
var MANAGED_LOW_EXIT = 0.9;
|
|
173321
|
+
var MANAGED_CRITICAL_ENTER = 0.5;
|
|
173322
|
+
var MANAGED_CRITICAL_EXIT = 0.6;
|
|
173323
|
+
var MANAGED_LOW_GRACE_MS = 10 * 6e4;
|
|
173324
|
+
function boundsOf(floorPercent, config) {
|
|
173325
|
+
if (floorPercent === void 0) return {
|
|
173326
|
+
lowEnter: config.lowPercent,
|
|
173327
|
+
lowExit: config.lowPercent + UNMANAGED_HYSTERESIS_POINTS,
|
|
173328
|
+
criticalEnter: config.criticalPercent,
|
|
173329
|
+
criticalExit: config.criticalPercent + UNMANAGED_HYSTERESIS_POINTS,
|
|
173330
|
+
lowGraceMs: 0,
|
|
173331
|
+
lowReason: "free-below-warn",
|
|
173332
|
+
criticalReason: "free-below-critical"
|
|
172987
173333
|
};
|
|
172988
173334
|
return {
|
|
172989
|
-
|
|
172990
|
-
|
|
173335
|
+
lowEnter: floorPercent * MANAGED_LOW_ENTER,
|
|
173336
|
+
lowExit: floorPercent * MANAGED_LOW_EXIT,
|
|
173337
|
+
criticalEnter: floorPercent * MANAGED_CRITICAL_ENTER,
|
|
173338
|
+
criticalExit: floorPercent * MANAGED_CRITICAL_EXIT,
|
|
173339
|
+
lowGraceMs: MANAGED_LOW_GRACE_MS,
|
|
173340
|
+
lowReason: "free-below-floor",
|
|
173341
|
+
criticalReason: "free-below-hard-bound"
|
|
172991
173342
|
};
|
|
172992
173343
|
}
|
|
172993
173344
|
var StorageLocationBandMonitor = class {
|
|
172994
173345
|
config;
|
|
173346
|
+
now;
|
|
172995
173347
|
band = /* @__PURE__ */ new Map();
|
|
172996
|
-
|
|
173348
|
+
/** When free first went under `lowEnter` and has stayed there. */
|
|
173349
|
+
belowLowSince = /* @__PURE__ */ new Map();
|
|
173350
|
+
constructor(config = DEFAULT_STORAGE_LOCATION_BAND_CONFIG, now = Date.now) {
|
|
172997
173351
|
this.config = config;
|
|
173352
|
+
this.now = now;
|
|
173353
|
+
}
|
|
173354
|
+
nextBand(locationId, previous, free, b) {
|
|
173355
|
+
if (free < b.criticalEnter || previous === "critical" && free < b.criticalExit) return {
|
|
173356
|
+
band: "critical",
|
|
173357
|
+
reason: b.criticalReason
|
|
173358
|
+
};
|
|
173359
|
+
const lowActive = previous === "low" || previous === "critical";
|
|
173360
|
+
if (free < b.lowEnter || lowActive && free < b.lowExit) {
|
|
173361
|
+
if (lowActive) return {
|
|
173362
|
+
band: "low",
|
|
173363
|
+
reason: b.lowReason
|
|
173364
|
+
};
|
|
173365
|
+
const since = this.belowLowSince.get(locationId) ?? this.now();
|
|
173366
|
+
this.belowLowSince.set(locationId, since);
|
|
173367
|
+
if (this.now() - since >= b.lowGraceMs) return {
|
|
173368
|
+
band: "low",
|
|
173369
|
+
reason: b.lowReason
|
|
173370
|
+
};
|
|
173371
|
+
return {
|
|
173372
|
+
band: previous ?? "ok",
|
|
173373
|
+
reason: "free-ok"
|
|
173374
|
+
};
|
|
173375
|
+
}
|
|
173376
|
+
this.belowLowSince.delete(locationId);
|
|
173377
|
+
return {
|
|
173378
|
+
band: "ok",
|
|
173379
|
+
reason: "free-ok"
|
|
173380
|
+
};
|
|
172998
173381
|
}
|
|
172999
173382
|
/**
|
|
173000
173383
|
* Observe one sweep of managed locations. Locations missing from `samples`
|
|
@@ -173005,8 +173388,9 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173005
173388
|
const out = [];
|
|
173006
173389
|
for (const sample of samples) {
|
|
173007
173390
|
seen.add(sample.locationId);
|
|
173008
|
-
|
|
173391
|
+
if (sample.freePercent === null) continue;
|
|
173009
173392
|
const previous = this.band.get(sample.locationId) ?? null;
|
|
173393
|
+
const { band, reason } = this.nextBand(sample.locationId, previous, sample.freePercent, boundsOf(sample.floorPercent, this.config));
|
|
173010
173394
|
if (previous === band) continue;
|
|
173011
173395
|
this.band.set(sample.locationId, band);
|
|
173012
173396
|
if (previous === null && band === "ok") continue;
|
|
@@ -173016,11 +173400,17 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173016
173400
|
...sample.locationName !== void 0 ? { locationName: sample.locationName } : {},
|
|
173017
173401
|
band,
|
|
173018
173402
|
freePercent: sample.freePercent,
|
|
173403
|
+
...sample.floorPercent !== void 0 ? { floorPercent: sample.floorPercent } : {},
|
|
173404
|
+
...sample.freeBytes !== void 0 ? { freeBytes: sample.freeBytes } : {},
|
|
173405
|
+
...sample.floorBytes !== void 0 ? { floorBytes: sample.floorBytes } : {},
|
|
173019
173406
|
reason,
|
|
173020
173407
|
previous
|
|
173021
173408
|
});
|
|
173022
173409
|
}
|
|
173023
|
-
for (const id of [...this.band.keys()]) if (!seen.has(id))
|
|
173410
|
+
for (const id of [...this.band.keys()]) if (!seen.has(id)) {
|
|
173411
|
+
this.band.delete(id);
|
|
173412
|
+
this.belowLowSince.delete(id);
|
|
173413
|
+
}
|
|
173024
173414
|
return out;
|
|
173025
173415
|
}
|
|
173026
173416
|
};
|
|
@@ -173033,6 +173423,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173033
173423
|
var CAP_PROVIDER_REGISTERED_CATEGORY = "capability:provider-registered";
|
|
173034
173424
|
var StorageOrchestratorAddon = class extends require_dist10.BaseAddon {
|
|
173035
173425
|
locationsKind = null;
|
|
173426
|
+
seedMarkersKind = null;
|
|
173036
173427
|
drainStateKind = null;
|
|
173037
173428
|
service = null;
|
|
173038
173429
|
pressureManager = null;
|
|
@@ -173058,6 +173449,8 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173058
173449
|
pressureTimer = null;
|
|
173059
173450
|
pressureSweepInFlight = false;
|
|
173060
173451
|
migration = null;
|
|
173452
|
+
/** Guards every single-location repoint and arbitrates movers per physical root. */
|
|
173453
|
+
repointer = null;
|
|
173061
173454
|
/**
|
|
173062
173455
|
* Cached `providerId → nodeLocal` snapshot (SP1). Backs the orchestrator's
|
|
173063
173456
|
* synchronous `NodeLocalResolver` — `getProviderInfo()` is async, so we
|
|
@@ -173094,6 +173487,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173094
173487
|
if (records !== void 0) {
|
|
173095
173488
|
await records.declare(storageOrchestratorRecordKinds);
|
|
173096
173489
|
this.locationsKind = SqliteLocationStore.recordStoresOf(records);
|
|
173490
|
+
this.seedMarkersKind = SqliteLocationStore.seedMarkersOf(records);
|
|
173097
173491
|
this.drainStateKind = SqliteDrainStateStore.recordStoresOf(records);
|
|
173098
173492
|
}
|
|
173099
173493
|
const getProviders = () => {
|
|
@@ -173113,6 +173507,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173113
173507
|
return proxy;
|
|
173114
173508
|
});
|
|
173115
173509
|
this.service = service;
|
|
173510
|
+
service.setStoreRequiredForSeed(this.locationsKind !== null);
|
|
173116
173511
|
service.setNodeLocalResolver((providerId) => this.nodeLocalByProvider.get(providerId));
|
|
173117
173512
|
service.setOccupancyProbe((location) => this.locationOccupancy(location));
|
|
173118
173513
|
await service.initialize();
|
|
@@ -173136,8 +173531,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173136
173531
|
...input,
|
|
173137
173532
|
config: keychained
|
|
173138
173533
|
};
|
|
173139
|
-
await this.
|
|
173140
|
-
const saved = service.upsertLocation(next);
|
|
173534
|
+
const saved = await this.upsertCarryingData(stored, next, () => service.upsertLocation(next));
|
|
173141
173535
|
this.announceLocationsChanged(saved.id, saved.type, "upsert");
|
|
173142
173536
|
return this.redacted(saved);
|
|
173143
173537
|
},
|
|
@@ -173347,6 +173741,49 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173347
173741
|
deviceKeyOf: (locationId) => this.locationDeviceKey(locationId)
|
|
173348
173742
|
});
|
|
173349
173743
|
this.migration = migration;
|
|
173744
|
+
this.repointer = new LocationRepointer({
|
|
173745
|
+
logger: this.ctx.logger,
|
|
173746
|
+
resolveKey: async (basePath) => {
|
|
173747
|
+
try {
|
|
173748
|
+
return await node_fs_promises.realpath(basePath);
|
|
173749
|
+
} catch {
|
|
173750
|
+
return node_path.resolve(basePath);
|
|
173751
|
+
}
|
|
173752
|
+
},
|
|
173753
|
+
locationBasePath: (id) => this.locationBasePath(id),
|
|
173754
|
+
locationIdsOfType: (type) => service.listLocations({ type }).map((loc) => loc.id),
|
|
173755
|
+
listMovers: () => migration.movers(),
|
|
173756
|
+
ioFor: async (stored, next) => {
|
|
173757
|
+
const target = {
|
|
173758
|
+
...stored,
|
|
173759
|
+
config: next.config
|
|
173760
|
+
};
|
|
173761
|
+
const [source, destination] = await Promise.all([service.getProviderFor(stored), service.getProviderFor(target)]);
|
|
173762
|
+
return {
|
|
173763
|
+
list: (prefix) => source.list(prefix === void 0 ? { location: stored } : {
|
|
173764
|
+
location: stored,
|
|
173765
|
+
prefix
|
|
173766
|
+
}),
|
|
173767
|
+
read: (relativePath) => source.read({
|
|
173768
|
+
location: stored,
|
|
173769
|
+
relativePath
|
|
173770
|
+
}),
|
|
173771
|
+
write: (relativePath, data) => destination.write({
|
|
173772
|
+
location: target,
|
|
173773
|
+
relativePath,
|
|
173774
|
+
data
|
|
173775
|
+
}),
|
|
173776
|
+
readBack: (relativePath) => destination.read({
|
|
173777
|
+
location: target,
|
|
173778
|
+
relativePath
|
|
173779
|
+
}),
|
|
173780
|
+
deleteSource: (relativePath) => source.delete({
|
|
173781
|
+
location: stored,
|
|
173782
|
+
relativePath
|
|
173783
|
+
})
|
|
173784
|
+
};
|
|
173785
|
+
}
|
|
173786
|
+
});
|
|
173350
173787
|
const cleanup = new StorageCleanupCoordinator({
|
|
173351
173788
|
locations: service,
|
|
173352
173789
|
state: this.state("storage-cleanup", require_dist10.StorageCleanupJobSchema.nullable(), null),
|
|
@@ -173382,6 +173819,13 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173382
173819
|
status: ({ jobId }) => migration.status(jobId),
|
|
173383
173820
|
cancel: async ({ jobId }) => ({ cancelled: await migration.cancel(jobId) }),
|
|
173384
173821
|
movers: () => migration.movers(),
|
|
173822
|
+
moverClearance: async ({ locationIds }) => {
|
|
173823
|
+
const verdict = await this.requireRepointer().clearance(locationIds);
|
|
173824
|
+
return verdict.clear ? { clear: true } : {
|
|
173825
|
+
clear: false,
|
|
173826
|
+
repointLocationId: verdict.repointLocationId
|
|
173827
|
+
};
|
|
173828
|
+
},
|
|
173385
173829
|
residue: () => migration.residue(),
|
|
173386
173830
|
drain: async (input) => ({ jobId: await migration.drain(input) }),
|
|
173387
173831
|
cleanupStart: async (input) => ({ jobId: await cleanup.start(input) }),
|
|
@@ -173509,7 +173953,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173509
173953
|
else this.ctx.logger.info("storage-orchestrator: this node boots no data-store engine \u2014 storage locations are seeded from addon declarations at every boot, and node-pinned locations live on the hub");
|
|
173510
173954
|
return null;
|
|
173511
173955
|
}
|
|
173512
|
-
return new SqliteLocationStore(engine, this.locationsKind);
|
|
173956
|
+
return new SqliteLocationStore(engine, this.locationsKind, this.seedMarkersKind);
|
|
173513
173957
|
}
|
|
173514
173958
|
/**
|
|
173515
173959
|
* Late-wire the persistence store once a `data-store-provider` engine
|
|
@@ -173521,12 +173965,26 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173521
173965
|
* restart — the service never hydrates from / persists to SQLite.
|
|
173522
173966
|
*/
|
|
173523
173967
|
storeWireInFlight = null;
|
|
173968
|
+
/** True while the locations kind is empty and its legacy table still holds rows. */
|
|
173969
|
+
async adoptionIsPending() {
|
|
173970
|
+
const records = this.ctx.records;
|
|
173971
|
+
if (records === void 0 || this.locationsKind === null) return false;
|
|
173972
|
+
try {
|
|
173973
|
+
await records.declare(storageOrchestratorRecordKinds);
|
|
173974
|
+
return false;
|
|
173975
|
+
} catch (err) {
|
|
173976
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
173977
|
+
this.ctx.logger.warn("storage-orchestrator: persistence NOT wired \u2014 the storage-locations kind is not authoritative yet (adoption pending or the check failed); seeding is deferred", { meta: { error: message } });
|
|
173978
|
+
return true;
|
|
173979
|
+
}
|
|
173980
|
+
}
|
|
173524
173981
|
async ensureStoreWired() {
|
|
173525
173982
|
const service = this.service;
|
|
173526
173983
|
if (!service || service.hasStore()) return;
|
|
173527
173984
|
if (this.storeWireInFlight) return this.storeWireInFlight;
|
|
173528
173985
|
const store = this.resolveLocationStore(true);
|
|
173529
173986
|
if (!store) return;
|
|
173987
|
+
if (await this.adoptionIsPending()) return;
|
|
173530
173988
|
this.ctx.logger.info("storage-orchestrator: data-store engine now available \u2014 wiring persistence");
|
|
173531
173989
|
this.storeWireInFlight = service.attachStore(store).then(() => this.seedFromDeclarations()).catch((err) => {
|
|
173532
173990
|
this.ctx.logger.error("storage-orchestrator: attachStore failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
@@ -173555,7 +174013,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173555
174013
|
}
|
|
173556
174014
|
/**
|
|
173557
174015
|
* Sample free space for every managed location and emit NC band edges.
|
|
173558
|
-
* A failed capacity read stays `null`
|
|
174016
|
+
* A failed capacity read stays `null` and changes no band — never folded to 0 (D393).
|
|
173559
174017
|
*/
|
|
173560
174018
|
async emitLocationBandEvents() {
|
|
173561
174019
|
const svc = this.service;
|
|
@@ -173571,11 +174029,18 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173571
174029
|
};
|
|
173572
174030
|
const capacity = await this.volumeCapacityOf(locationId).catch(() => null);
|
|
173573
174031
|
const freePercent = capacity === null ? null : freePercentOf(capacity);
|
|
174032
|
+
if (capacity === null) ctx.logger.debug("storage: location capacity unreadable \u2014 band unchanged", { meta: { locationId } });
|
|
174033
|
+
const floorPercent = thresholds.get(locationId);
|
|
173574
174034
|
return {
|
|
173575
174035
|
locationId,
|
|
173576
174036
|
nodeId: loc.nodeId,
|
|
173577
174037
|
locationName: loc.displayName,
|
|
173578
|
-
freePercent
|
|
174038
|
+
freePercent,
|
|
174039
|
+
...floorPercent !== void 0 ? { floorPercent } : {},
|
|
174040
|
+
...capacity !== null ? {
|
|
174041
|
+
freeBytes: capacity.availableBytes,
|
|
174042
|
+
...floorPercent !== void 0 ? { floorBytes: Math.round(capacity.totalBytes * floorPercent / 100) } : {}
|
|
174043
|
+
} : {}
|
|
173579
174044
|
};
|
|
173580
174045
|
}));
|
|
173581
174046
|
for (const edge of this.locationBandMonitor.observe(samples)) {
|
|
@@ -173584,6 +174049,9 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173584
174049
|
locationId: edge.locationId,
|
|
173585
174050
|
band: edge.band,
|
|
173586
174051
|
freePercent: edge.freePercent,
|
|
174052
|
+
floorPercent: edge.floorPercent ?? null,
|
|
174053
|
+
freeBytes: edge.freeBytes ?? null,
|
|
174054
|
+
floorBytes: edge.floorBytes ?? null,
|
|
173587
174055
|
reason: edge.reason
|
|
173588
174056
|
} });
|
|
173589
174057
|
ctx.eventBus.emit({
|
|
@@ -173698,50 +174166,19 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
173698
174166
|
* A no-op for everything else — a rename, a mode change, a `multi` kind, or a
|
|
173699
174167
|
* location being created for the first time.
|
|
173700
174168
|
*/
|
|
173701
|
-
async
|
|
173702
|
-
if (stored === void 0) return;
|
|
174169
|
+
async upsertCarryingData(stored, next, commit) {
|
|
174170
|
+
if (stored === void 0) return commit();
|
|
173703
174171
|
const service = this.service;
|
|
173704
|
-
if (service === null) return;
|
|
173705
|
-
if (service.listDeclarations().find((entry) => entry.id === next.type)?.cardinality !== "single") return;
|
|
174172
|
+
if (service === null) return commit();
|
|
174173
|
+
if (service.listDeclarations().find((entry) => entry.id === next.type)?.cardinality !== "single") return commit();
|
|
173706
174174
|
const from = stored.config["basePath"];
|
|
173707
174175
|
const to = next.config["basePath"];
|
|
173708
|
-
if (typeof from !== "string" || typeof to !== "string" || from === to) return;
|
|
173709
|
-
|
|
173710
|
-
|
|
173711
|
-
|
|
173712
|
-
|
|
173713
|
-
|
|
173714
|
-
const destination = await service.getProviderFor(target);
|
|
173715
|
-
const moved = await moveLocationTree({
|
|
173716
|
-
list: (prefix) => source.list(prefix === void 0 ? { location: stored } : {
|
|
173717
|
-
location: stored,
|
|
173718
|
-
prefix
|
|
173719
|
-
}),
|
|
173720
|
-
read: (relativePath) => source.read({
|
|
173721
|
-
location: stored,
|
|
173722
|
-
relativePath
|
|
173723
|
-
}),
|
|
173724
|
-
write: (relativePath, data) => destination.write({
|
|
173725
|
-
location: target,
|
|
173726
|
-
relativePath,
|
|
173727
|
-
data
|
|
173728
|
-
}),
|
|
173729
|
-
readBack: (relativePath) => destination.read({
|
|
173730
|
-
location: target,
|
|
173731
|
-
relativePath
|
|
173732
|
-
}),
|
|
173733
|
-
deleteSource: (relativePath) => source.delete({
|
|
173734
|
-
location: stored,
|
|
173735
|
-
relativePath
|
|
173736
|
-
})
|
|
173737
|
-
});
|
|
173738
|
-
this.ctx.logger.info("storage-orchestrator: singleton location re-pointed \u2014 its data was carried over", { meta: {
|
|
173739
|
-
id: stored.id,
|
|
173740
|
-
type: stored.type,
|
|
173741
|
-
from,
|
|
173742
|
-
to,
|
|
173743
|
-
...moved
|
|
173744
|
-
} });
|
|
174176
|
+
if (typeof from !== "string" || typeof to !== "string" || from === to) return commit();
|
|
174177
|
+
return this.requireRepointer().run(stored, next, commit);
|
|
174178
|
+
}
|
|
174179
|
+
requireRepointer() {
|
|
174180
|
+
if (this.repointer === null) throw new Error("storage-orchestrator: not initialized");
|
|
174181
|
+
return this.repointer;
|
|
173745
174182
|
}
|
|
173746
174183
|
secretKeysFor(providerId, config) {
|
|
173747
174184
|
return secretKeysForConfig(config, this.declaredSecretKeys(providerId));
|
|
@@ -174145,11 +174582,11 @@ var require_storage_orchestrator = __commonJS({
|
|
|
174145
174582
|
}
|
|
174146
174583
|
});
|
|
174147
174584
|
|
|
174148
|
-
// ../system/dist/constants-
|
|
174149
|
-
var
|
|
174150
|
-
"../system/dist/constants-
|
|
174585
|
+
// ../system/dist/constants-DBGG6Zu5.js
|
|
174586
|
+
var require_constants_DBGG6Zu5 = __commonJS({
|
|
174587
|
+
"../system/dist/constants-DBGG6Zu5.js"(exports) {
|
|
174151
174588
|
"use strict";
|
|
174152
|
-
var MESH_CA_KEY_REF =
|
|
174589
|
+
var MESH_CA_KEY_REF = require_dist_Bi4Ioxop().buildSecretRef({
|
|
174153
174590
|
owner: "system",
|
|
174154
174591
|
scope: { kind: "global" },
|
|
174155
174592
|
fieldPath: "meshCaKey"
|
|
@@ -174212,14 +174649,14 @@ var require_constants_B3fDUnJt = __commonJS({
|
|
|
174212
174649
|
}
|
|
174213
174650
|
});
|
|
174214
174651
|
|
|
174215
|
-
// ../system/dist/agent-https-
|
|
174216
|
-
var
|
|
174217
|
-
"../system/dist/agent-https-
|
|
174652
|
+
// ../system/dist/agent-https-B7IjRRzT.js
|
|
174653
|
+
var require_agent_https_B7IjRRzT = __commonJS({
|
|
174654
|
+
"../system/dist/agent-https-B7IjRRzT.js"(exports) {
|
|
174218
174655
|
"use strict";
|
|
174219
174656
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
174220
|
-
var require_dist10 =
|
|
174657
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
174221
174658
|
var require_x509_es = require_x509_es_C4cOo48M();
|
|
174222
|
-
var require_constants15 =
|
|
174659
|
+
var require_constants15 = require_constants_DBGG6Zu5();
|
|
174223
174660
|
var zod = require_zod();
|
|
174224
174661
|
var node_crypto = __require("crypto");
|
|
174225
174662
|
var _camstack_types_node = require_node();
|
|
@@ -192962,11 +193399,11 @@ var require_system_config_addon = __commonJS({
|
|
|
192962
193399
|
[Symbol.toStringTag]: { value: "Module" }
|
|
192963
193400
|
});
|
|
192964
193401
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
192965
|
-
var require_dist10 =
|
|
193402
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
192966
193403
|
var require_safe_buffer$1 = require_safe_buffer_D3aoa_7X();
|
|
192967
193404
|
var require_x509_es = require_x509_es_C4cOo48M();
|
|
192968
|
-
var require_constants$8 =
|
|
192969
|
-
var require_agent_https =
|
|
193405
|
+
var require_constants$8 = require_constants_DBGG6Zu5();
|
|
193406
|
+
var require_agent_https = require_agent_https_B7IjRRzT();
|
|
192970
193407
|
var require_src$1 = require_src_CnAqG6EF();
|
|
192971
193408
|
var zod = require_zod();
|
|
192972
193409
|
var node_crypto = __require("crypto");
|
|
@@ -272679,7 +273116,7 @@ var require_winston_logging = __commonJS({
|
|
|
272679
273116
|
[Symbol.toStringTag]: { value: "Module" }
|
|
272680
273117
|
});
|
|
272681
273118
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
272682
|
-
var require_dist10 =
|
|
273119
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
272683
273120
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
272684
273121
|
var node_path = __require("path");
|
|
272685
273122
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -280329,14 +280766,14 @@ var require_lib_8oZrELLm = __commonJS({
|
|
|
280329
280766
|
}
|
|
280330
280767
|
});
|
|
280331
280768
|
|
|
280332
|
-
// ../system/dist/hub-mdns-ciao-
|
|
280333
|
-
var
|
|
280334
|
-
"../system/dist/hub-mdns-ciao-
|
|
280769
|
+
// ../system/dist/hub-mdns-ciao-2FzLWfbD.js
|
|
280770
|
+
var require_hub_mdns_ciao_2FzLWfbD = __commonJS({
|
|
280771
|
+
"../system/dist/hub-mdns-ciao-2FzLWfbD.js"(exports) {
|
|
280335
280772
|
"use strict";
|
|
280336
280773
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
280337
|
-
var require_dist10 =
|
|
280774
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
280338
280775
|
var require_x509_es = require_x509_es_C4cOo48M();
|
|
280339
|
-
var require_agent_https =
|
|
280776
|
+
var require_agent_https = require_agent_https_B7IjRRzT();
|
|
280340
280777
|
var node_crypto = __require("crypto");
|
|
280341
280778
|
var _camstack_types_node = require_node();
|
|
280342
280779
|
var node_fs_promises = __require("fs/promises");
|
|
@@ -281335,12 +281772,12 @@ var require_platform_key_source_Di7HrlGR = __commonJS({
|
|
|
281335
281772
|
}
|
|
281336
281773
|
});
|
|
281337
281774
|
|
|
281338
|
-
// ../system/dist/restore-archive-
|
|
281339
|
-
var
|
|
281340
|
-
"../system/dist/restore-archive-
|
|
281775
|
+
// ../system/dist/restore-archive-C0ymYQk7.js
|
|
281776
|
+
var require_restore_archive_C0ymYQk7 = __commonJS({
|
|
281777
|
+
"../system/dist/restore-archive-C0ymYQk7.js"(exports) {
|
|
281341
281778
|
"use strict";
|
|
281342
281779
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
281343
|
-
var require_dist10 =
|
|
281780
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
281344
281781
|
var require_read_all_rows$1 = require_read_all_rows_CVoO1ONM();
|
|
281345
281782
|
var zod = require_zod();
|
|
281346
281783
|
var node_crypto = __require("crypto");
|
|
@@ -292661,9 +293098,9 @@ var require_dist3 = __commonJS({
|
|
|
292661
293098
|
"use strict";
|
|
292662
293099
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
292663
293100
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
292664
|
-
var require_dist10 =
|
|
293101
|
+
var require_dist10 = require_dist_Bi4Ioxop();
|
|
292665
293102
|
var require_read_all_rows$1 = require_read_all_rows_CVoO1ONM();
|
|
292666
|
-
var require_device_ca =
|
|
293103
|
+
var require_device_ca = require_device_ca_B3hUVfYk();
|
|
292667
293104
|
var require_builtins_alerts_alerts_addon = require_alerts_addon();
|
|
292668
293105
|
require_alerts();
|
|
292669
293106
|
var require_builtins_calendars_calendars_addon = require_calendars_addon();
|
|
@@ -292688,21 +293125,21 @@ var require_dist3 = __commonJS({
|
|
|
292688
293125
|
var require_builtins_native_metrics_native_metrics_addon = require_native_metrics_addon();
|
|
292689
293126
|
var require_builtins_device_history_device_history_addon = require_device_history_addon();
|
|
292690
293127
|
var require_builtins_sqlite_storage_filesystem_storage_addon = require_filesystem_storage_addon();
|
|
292691
|
-
var require_wal_maintenance =
|
|
293128
|
+
var require_wal_maintenance = require_wal_maintenance_Bo_lo3Dh();
|
|
292692
293129
|
var require_builtins_sqlite_storage_sqlite_settings_addon = require_sqlite_settings_addon();
|
|
292693
293130
|
var require_builtins_sqlite_storage_index = require_sqlite_storage();
|
|
292694
293131
|
var require_builtins_storage_orchestrator_storage_orchestrator_addon = require_storage_orchestrator_addon();
|
|
292695
293132
|
require_storage_orchestrator();
|
|
292696
|
-
var require_constants15 =
|
|
292697
|
-
var require_agent_https =
|
|
293133
|
+
var require_constants15 = require_constants_DBGG6Zu5();
|
|
293134
|
+
var require_agent_https = require_agent_https_B7IjRRzT();
|
|
292698
293135
|
var require_builtins_system_config_system_config_addon = require_system_config_addon();
|
|
292699
293136
|
require_system_config();
|
|
292700
293137
|
var require_builtins_winston_logging_index = require_winston_logging();
|
|
292701
293138
|
var require_custom_action_registry = require_custom_action_registry_COyb49zm();
|
|
292702
|
-
var require_hub_mdns_ciao =
|
|
293139
|
+
var require_hub_mdns_ciao = require_hub_mdns_ciao_2FzLWfbD();
|
|
292703
293140
|
var require_platform_key_source = require_platform_key_source_Di7HrlGR();
|
|
292704
293141
|
var require_resource_monitor = require_resource_monitor_mio9dSCT();
|
|
292705
|
-
var require_restore_archive =
|
|
293142
|
+
var require_restore_archive = require_restore_archive_C0ymYQk7();
|
|
292706
293143
|
var zod = require_zod();
|
|
292707
293144
|
var node_crypto = __require("crypto");
|
|
292708
293145
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
@@ -316148,7 +316585,7 @@ var require_enums = __commonJS({
|
|
|
316148
316585
|
"../types/dist/enums.js"(exports) {
|
|
316149
316586
|
"use strict";
|
|
316150
316587
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
316151
|
-
var require_event_category =
|
|
316588
|
+
var require_event_category = require_event_category_eSqkye_K();
|
|
316152
316589
|
var EventSourceType = /* @__PURE__ */ (function(EventSourceType2) {
|
|
316153
316590
|
EventSourceType2["Addon"] = "addon";
|
|
316154
316591
|
EventSourceType2["Core"] = "core";
|
|
@@ -316168,8 +316605,8 @@ var require_dist4 = __commonJS({
|
|
|
316168
316605
|
"../types/dist/index.js"(exports) {
|
|
316169
316606
|
"use strict";
|
|
316170
316607
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
316171
|
-
var require_sleep =
|
|
316172
|
-
var require_event_category =
|
|
316608
|
+
var require_sleep = require_sleep_BE7_6UnC();
|
|
316609
|
+
var require_event_category = require_event_category_eSqkye_K();
|
|
316173
316610
|
var require_composition = require_composition_eoYYVfOp();
|
|
316174
316611
|
var require_node_color2 = require_node_color();
|
|
316175
316612
|
var require_err_msg = require_err_msg_BhVbr0NX();
|
|
@@ -318580,6 +319017,31 @@ var require_dist4 = __commonJS({
|
|
|
318580
319017
|
error: zod.z.string().nullable()
|
|
318581
319018
|
});
|
|
318582
319019
|
var StorageCleanupStatusInputSchema = zod.z.object({ jobId: zod.z.string().optional() });
|
|
319020
|
+
async function startMoverUnderClearance(deps) {
|
|
319021
|
+
const refuse = (detail) => {
|
|
319022
|
+
throw new Error(`mover refused: ${detail}`);
|
|
319023
|
+
};
|
|
319024
|
+
const ask = async () => {
|
|
319025
|
+
try {
|
|
319026
|
+
return await deps.clearance(deps.locationIds);
|
|
319027
|
+
} catch (err) {
|
|
319028
|
+
return refuse(`the storage orchestrator could not be asked (${err instanceof Error ? err.message : String(err)})`);
|
|
319029
|
+
}
|
|
319030
|
+
};
|
|
319031
|
+
const blocked = (answer) => `a re-point of "${answer.repointLocationId ?? "a location"}" holds an overlapping storage root`;
|
|
319032
|
+
const before = await ask();
|
|
319033
|
+
if (!before.clear) return refuse(blocked(before));
|
|
319034
|
+
const jobId = deps.start();
|
|
319035
|
+
const after = await ask().catch((err) => {
|
|
319036
|
+
deps.cancel(jobId);
|
|
319037
|
+
throw err;
|
|
319038
|
+
});
|
|
319039
|
+
if (!after.clear) {
|
|
319040
|
+
deps.cancel(jobId);
|
|
319041
|
+
return refuse(blocked(after));
|
|
319042
|
+
}
|
|
319043
|
+
return jobId;
|
|
319044
|
+
}
|
|
318583
319045
|
var SUB_DETECTION_TYPES = ["face", "plate"];
|
|
318584
319046
|
var RECOGNITION_TYPES = [
|
|
318585
319047
|
"face",
|
|
@@ -321577,7 +322039,14 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
321577
322039
|
]);
|
|
321578
322040
|
var AlertActionSchema = zod.z.object({
|
|
321579
322041
|
label: zod.z.string(),
|
|
321580
|
-
href: zod.z.string().optional()
|
|
322042
|
+
href: zod.z.string().optional(),
|
|
322043
|
+
/**
|
|
322044
|
+
* How `href` is followed. Absent / `app`: an admin-ui route (client-side).
|
|
322045
|
+
* `server`: a route the HUB serves (an addon HTTP route such as an OAuth
|
|
322046
|
+
* start) — the browser must leave the SPA with a full navigation, because
|
|
322047
|
+
* the SPA has no such route and would bounce to the home page.
|
|
322048
|
+
*/
|
|
322049
|
+
navigation: zod.z.enum(["app", "server"]).optional()
|
|
321581
322050
|
});
|
|
321582
322051
|
var AlertStatusSchema = zod.z.enum([
|
|
321583
322052
|
"active",
|
|
@@ -353092,6 +353561,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
353092
353561
|
"server-updated",
|
|
353093
353562
|
"export-completed",
|
|
353094
353563
|
"backup-completed",
|
|
353564
|
+
"alert-critical",
|
|
353565
|
+
"alert-error",
|
|
353566
|
+
"alert-critical-resolved",
|
|
353095
353567
|
"camera-online",
|
|
353096
353568
|
"camera-offline",
|
|
353097
353569
|
"camera-disabled",
|
|
@@ -354230,6 +354702,18 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
354230
354702
|
value: "backup-completed",
|
|
354231
354703
|
label: "Backup completed"
|
|
354232
354704
|
},
|
|
354705
|
+
{
|
|
354706
|
+
value: "alert-critical",
|
|
354707
|
+
label: "Critical alert raised"
|
|
354708
|
+
},
|
|
354709
|
+
{
|
|
354710
|
+
value: "alert-error",
|
|
354711
|
+
label: "Error alert raised"
|
|
354712
|
+
},
|
|
354713
|
+
{
|
|
354714
|
+
value: "alert-critical-resolved",
|
|
354715
|
+
label: "Critical alert resolved"
|
|
354716
|
+
},
|
|
354233
354717
|
{
|
|
354234
354718
|
value: "alarm-arm-refused",
|
|
354235
354719
|
label: "Alarm arm refused"
|
|
@@ -363216,6 +363700,18 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
363216
363700
|
*/
|
|
363217
363701
|
movers: require_sleep.method(zod.z.object({}), zod.z.array(StorageMigrationMoverSchema).readonly(), { auth: "admin" }),
|
|
363218
363702
|
/**
|
|
363703
|
+
* May a mover that touches these locations run NOW? One claim per physical
|
|
363704
|
+
* root is owned by the storage orchestrator: a single-location repoint holds
|
|
363705
|
+
* it while it carries its subtree, and a mover (`relocateMedia`,
|
|
363706
|
+
* `relocateFootage`, a migration move) asks here AFTER registering its job and
|
|
363707
|
+
* cancels itself on `clear: false`. The repoint, in turn, refuses while a
|
|
363708
|
+
* registered mover touches its root. Asked, never polled (D3).
|
|
363709
|
+
*/
|
|
363710
|
+
moverClearance: require_sleep.method(zod.z.object({ locationIds: zod.z.array(zod.z.string()).readonly() }), zod.z.object({
|
|
363711
|
+
clear: zod.z.boolean(),
|
|
363712
|
+
repointLocationId: zod.z.string().optional()
|
|
363713
|
+
}), { auth: "admin" }),
|
|
363714
|
+
/**
|
|
363219
363715
|
* What each class's SOURCE still holds, from the archive — never from the
|
|
363220
363716
|
* resident index (D295). Only classes with something left (or something
|
|
363221
363717
|
* unknown) are listed, so an empty list means there is nothing to drain and
|
|
@@ -367555,43 +368051,139 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
367555
368051
|
"error",
|
|
367556
368052
|
"unavailable"
|
|
367557
368053
|
]);
|
|
368054
|
+
var DishwasherOperationStateSchema = zod.z.enum([
|
|
368055
|
+
"Inactive",
|
|
368056
|
+
"Ready",
|
|
368057
|
+
"DelayedStart",
|
|
368058
|
+
"Run",
|
|
368059
|
+
"Pause",
|
|
368060
|
+
"ActionRequired",
|
|
368061
|
+
"Finished",
|
|
368062
|
+
"Error",
|
|
368063
|
+
"Aborting"
|
|
368064
|
+
]);
|
|
368065
|
+
var DishwasherAvailabilitySchema = zod.z.enum([
|
|
368066
|
+
"available",
|
|
368067
|
+
"offline",
|
|
368068
|
+
"description-missing"
|
|
368069
|
+
]);
|
|
367558
368070
|
var DishwasherConsumableLevelSchema = zod.z.enum([
|
|
367559
368071
|
"ok",
|
|
367560
368072
|
"low",
|
|
367561
368073
|
"empty"
|
|
367562
368074
|
]);
|
|
367563
368075
|
var DishwasherStatusSchema = zod.z.object({
|
|
368076
|
+
availability: DishwasherAvailabilitySchema,
|
|
368077
|
+
/** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
|
|
367564
368078
|
state: DishwasherStateSchema,
|
|
367565
|
-
/**
|
|
368079
|
+
/** The appliance's operation state as reported; null when not known. */
|
|
368080
|
+
operationState: DishwasherOperationStateSchema.nullable(),
|
|
368081
|
+
/** Feature key of the ACTIVE (running) program, or null when none runs / not known. */
|
|
367566
368082
|
program: zod.z.string().nullable(),
|
|
367567
|
-
/**
|
|
368083
|
+
/** Feature key of the SELECTED program (what Start would run), or null when none / not known. */
|
|
368084
|
+
selectedProgram: zod.z.string().nullable(),
|
|
368085
|
+
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
367568
368086
|
availablePrograms: zod.z.array(zod.z.string()),
|
|
367569
|
-
/**
|
|
367570
|
-
|
|
368087
|
+
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
368088
|
+
remainingSeconds: zod.z.number().int().nonnegative().nullable(),
|
|
368089
|
+
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
368090
|
+
delayedStartSeconds: zod.z.number().int().nonnegative().nullable(),
|
|
367571
368091
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
367572
368092
|
progressPercent: zod.z.number().min(0).max(100).nullable(),
|
|
367573
|
-
/** True when the door is reported open. */
|
|
367574
|
-
doorOpen: zod.z.boolean(),
|
|
367575
|
-
/** True when
|
|
367576
|
-
|
|
367577
|
-
/**
|
|
367578
|
-
|
|
368093
|
+
/** True when the door is reported open; null when the door state is not known. */
|
|
368094
|
+
doorOpen: zod.z.boolean().nullable(),
|
|
368095
|
+
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
368096
|
+
doorLocked: zod.z.boolean().nullable(),
|
|
368097
|
+
/** True when remote start is allowed (door closed, power on, etc.); null when not known. */
|
|
368098
|
+
remoteStartAllowed: zod.z.boolean().nullable(),
|
|
368099
|
+
/** True when the appliance accepts remote control now; null when not known. */
|
|
368100
|
+
remoteControlActive: zod.z.boolean().nullable(),
|
|
368101
|
+
/** True while somebody operates the appliance at its panel; null when not reported. */
|
|
368102
|
+
localControlActive: zod.z.boolean().nullable(),
|
|
368103
|
+
/** Main power / switched-on state; null when not known. */
|
|
368104
|
+
powerOn: zod.z.boolean().nullable(),
|
|
368105
|
+
/** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
|
|
368106
|
+
powerState: zod.z.string().nullable(),
|
|
367579
368107
|
saltLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
367580
368108
|
rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
367581
|
-
|
|
367582
|
-
|
|
368109
|
+
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
368110
|
+
halfLoad: zod.z.boolean().nullable(),
|
|
368111
|
+
hygienePlus: zod.z.boolean().nullable(),
|
|
367583
368112
|
/** Extra dry option when the appliance exposes it. */
|
|
367584
|
-
extraDry: zod.z.boolean(),
|
|
368113
|
+
extraDry: zod.z.boolean().nullable(),
|
|
367585
368114
|
/** Intensive zone (lower basket) when the appliance exposes it. */
|
|
367586
|
-
intensiveZone: zod.z.boolean(),
|
|
368115
|
+
intensiveZone: zod.z.boolean().nullable(),
|
|
367587
368116
|
/** VarioSpeed / VarioSpeed+ when the appliance exposes it. */
|
|
367588
|
-
varioSpeedPlus: zod.z.boolean(),
|
|
367589
|
-
/** Child lock (controls disabled on the appliance). */
|
|
367590
|
-
childLock: zod.z.boolean(),
|
|
368117
|
+
varioSpeedPlus: zod.z.boolean().nullable(),
|
|
368118
|
+
/** Child lock (controls disabled on the appliance); null when not known. */
|
|
368119
|
+
childLock: zod.z.boolean().nullable(),
|
|
368120
|
+
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
368121
|
+
activeEvents: zod.z.array(zod.z.string()),
|
|
368122
|
+
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
367591
368123
|
errorCode: zod.z.number().nullable(),
|
|
368124
|
+
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
367592
368125
|
errorLabel: zod.z.string().nullable(),
|
|
368126
|
+
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
367593
368127
|
lastFetchedAt: zod.z.number()
|
|
367594
368128
|
});
|
|
368129
|
+
var DeviceIdSchema = zod.z.number().int().nonnegative();
|
|
368130
|
+
var DishwasherValueSchema = zod.z.union([
|
|
368131
|
+
zod.z.boolean(),
|
|
368132
|
+
zod.z.string(),
|
|
368133
|
+
zod.z.number()
|
|
368134
|
+
]);
|
|
368135
|
+
var DishwasherAccessSchema = zod.z.enum([
|
|
368136
|
+
"none",
|
|
368137
|
+
"read",
|
|
368138
|
+
"readWrite",
|
|
368139
|
+
"writeOnly",
|
|
368140
|
+
"readStatic"
|
|
368141
|
+
]);
|
|
368142
|
+
var DishwasherOptionDescriptorSchema = zod.z.object({
|
|
368143
|
+
/** Feature key (`Dishcare.Dishwasher.Option.ExtraDry`). */
|
|
368144
|
+
key: zod.z.string(),
|
|
368145
|
+
/** Last segment of the key, for display. */
|
|
368146
|
+
name: zod.z.string(),
|
|
368147
|
+
type: zod.z.enum([
|
|
368148
|
+
"boolean",
|
|
368149
|
+
"number",
|
|
368150
|
+
"enum",
|
|
368151
|
+
"string"
|
|
368152
|
+
]),
|
|
368153
|
+
access: DishwasherAccessSchema,
|
|
368154
|
+
/** The appliance reports this entity as currently available. */
|
|
368155
|
+
available: zod.z.boolean(),
|
|
368156
|
+
/** Unit the description declares for a number; null when it declares none. */
|
|
368157
|
+
unit: zod.z.string().nullable(),
|
|
368158
|
+
min: zod.z.number().nullable(),
|
|
368159
|
+
max: zod.z.number().nullable(),
|
|
368160
|
+
step: zod.z.number().nullable(),
|
|
368161
|
+
/** Allowed members of an enum; null for other types. */
|
|
368162
|
+
enumValues: zod.z.array(zod.z.string()).nullable(),
|
|
368163
|
+
defaultValue: DishwasherValueSchema.nullable()
|
|
368164
|
+
});
|
|
368165
|
+
var DishwasherProgramSchema = zod.z.object({
|
|
368166
|
+
/** Feature key (`Dishcare.Dishwasher.Program.Eco50`) — what `setProgram` / `start` take. */
|
|
368167
|
+
key: zod.z.string(),
|
|
368168
|
+
name: zod.z.string(),
|
|
368169
|
+
/** The appliance currently offers this program. */
|
|
368170
|
+
available: zod.z.boolean(),
|
|
368171
|
+
/** The options this program lists, with the program-level access / availability / default. */
|
|
368172
|
+
options: zod.z.array(DishwasherOptionDescriptorSchema)
|
|
368173
|
+
});
|
|
368174
|
+
var DishwasherOptionsSchema = zod.z.object({
|
|
368175
|
+
availability: DishwasherAvailabilitySchema,
|
|
368176
|
+
/** What the appliance can be told to do, from the commands its description declares. */
|
|
368177
|
+
supportsStart: zod.z.boolean(),
|
|
368178
|
+
supportsPause: zod.z.boolean(),
|
|
368179
|
+
supportsResume: zod.z.boolean(),
|
|
368180
|
+
supportsStop: zod.z.boolean(),
|
|
368181
|
+
supportsPower: zod.z.boolean(),
|
|
368182
|
+
/** Every program the description lists, with its options. */
|
|
368183
|
+
programs: zod.z.array(DishwasherProgramSchema),
|
|
368184
|
+
/** Every option and setting entity the description lists (programs reference these by key). */
|
|
368185
|
+
options: zod.z.array(DishwasherOptionDescriptorSchema)
|
|
368186
|
+
});
|
|
367595
368187
|
var dishwasherCapability = {
|
|
367596
368188
|
name: "dishwasher",
|
|
367597
368189
|
scope: "device",
|
|
@@ -367599,86 +368191,102 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
367599
368191
|
mode: "singleton",
|
|
367600
368192
|
deviceTypes: [require_err_msg.DeviceType.Dishwasher],
|
|
367601
368193
|
methods: {
|
|
367602
|
-
|
|
368194
|
+
/**
|
|
368195
|
+
* Start a program. Without `program` the selected one starts. `options` are
|
|
368196
|
+
* option feature keys; each is checked against the program's constraints.
|
|
368197
|
+
*/
|
|
368198
|
+
start: require_sleep.method(zod.z.object({
|
|
368199
|
+
deviceId: DeviceIdSchema,
|
|
368200
|
+
program: zod.z.string().min(1).optional(),
|
|
368201
|
+
options: zod.z.record(zod.z.string(), DishwasherValueSchema).optional()
|
|
368202
|
+
}), zod.z.void(), {
|
|
367603
368203
|
kind: "mutation",
|
|
367604
368204
|
auth: "protected"
|
|
367605
368205
|
}),
|
|
367606
|
-
pause: require_sleep.method(zod.z.object({ deviceId:
|
|
368206
|
+
pause: require_sleep.method(zod.z.object({ deviceId: DeviceIdSchema }), zod.z.void(), {
|
|
367607
368207
|
kind: "mutation",
|
|
367608
368208
|
auth: "protected"
|
|
367609
368209
|
}),
|
|
367610
|
-
|
|
368210
|
+
resume: require_sleep.method(zod.z.object({ deviceId: DeviceIdSchema }), zod.z.void(), {
|
|
367611
368211
|
kind: "mutation",
|
|
367612
368212
|
auth: "protected"
|
|
367613
368213
|
}),
|
|
368214
|
+
stop: require_sleep.method(zod.z.object({ deviceId: DeviceIdSchema }), zod.z.void(), {
|
|
368215
|
+
kind: "mutation",
|
|
368216
|
+
auth: "protected"
|
|
368217
|
+
}),
|
|
368218
|
+
/** Select (not start) a program; refused when the appliance does not offer it. */
|
|
367614
368219
|
setProgram: require_sleep.method(zod.z.object({
|
|
367615
|
-
deviceId:
|
|
368220
|
+
deviceId: DeviceIdSchema,
|
|
367616
368221
|
program: zod.z.string().min(1)
|
|
367617
368222
|
}), zod.z.void(), {
|
|
367618
368223
|
kind: "mutation",
|
|
367619
368224
|
auth: "protected"
|
|
367620
368225
|
}),
|
|
367621
368226
|
setPower: require_sleep.method(zod.z.object({
|
|
367622
|
-
deviceId:
|
|
368227
|
+
deviceId: DeviceIdSchema,
|
|
367623
368228
|
on: zod.z.boolean()
|
|
367624
368229
|
}), zod.z.void(), {
|
|
367625
368230
|
kind: "mutation",
|
|
367626
368231
|
auth: "protected"
|
|
367627
368232
|
}),
|
|
367628
368233
|
setHalfLoad: require_sleep.method(zod.z.object({
|
|
367629
|
-
deviceId:
|
|
368234
|
+
deviceId: DeviceIdSchema,
|
|
367630
368235
|
on: zod.z.boolean()
|
|
367631
368236
|
}), zod.z.void(), {
|
|
367632
368237
|
kind: "mutation",
|
|
367633
368238
|
auth: "protected"
|
|
367634
368239
|
}),
|
|
367635
368240
|
setHygienePlus: require_sleep.method(zod.z.object({
|
|
367636
|
-
deviceId:
|
|
368241
|
+
deviceId: DeviceIdSchema,
|
|
367637
368242
|
on: zod.z.boolean()
|
|
367638
368243
|
}), zod.z.void(), {
|
|
367639
368244
|
kind: "mutation",
|
|
367640
368245
|
auth: "protected"
|
|
367641
368246
|
}),
|
|
367642
368247
|
setExtraDry: require_sleep.method(zod.z.object({
|
|
367643
|
-
deviceId:
|
|
368248
|
+
deviceId: DeviceIdSchema,
|
|
367644
368249
|
on: zod.z.boolean()
|
|
367645
368250
|
}), zod.z.void(), {
|
|
367646
368251
|
kind: "mutation",
|
|
367647
368252
|
auth: "protected"
|
|
367648
368253
|
}),
|
|
367649
368254
|
setIntensiveZone: require_sleep.method(zod.z.object({
|
|
367650
|
-
deviceId:
|
|
368255
|
+
deviceId: DeviceIdSchema,
|
|
367651
368256
|
on: zod.z.boolean()
|
|
367652
368257
|
}), zod.z.void(), {
|
|
367653
368258
|
kind: "mutation",
|
|
367654
368259
|
auth: "protected"
|
|
367655
368260
|
}),
|
|
367656
368261
|
setVarioSpeedPlus: require_sleep.method(zod.z.object({
|
|
367657
|
-
deviceId:
|
|
368262
|
+
deviceId: DeviceIdSchema,
|
|
367658
368263
|
on: zod.z.boolean()
|
|
367659
368264
|
}), zod.z.void(), {
|
|
367660
368265
|
kind: "mutation",
|
|
367661
368266
|
auth: "protected"
|
|
367662
368267
|
}),
|
|
367663
368268
|
setChildLock: require_sleep.method(zod.z.object({
|
|
367664
|
-
deviceId:
|
|
368269
|
+
deviceId: DeviceIdSchema,
|
|
367665
368270
|
on: zod.z.boolean()
|
|
367666
368271
|
}), zod.z.void(), {
|
|
367667
368272
|
kind: "mutation",
|
|
367668
368273
|
auth: "protected"
|
|
367669
368274
|
}),
|
|
368275
|
+
/**
|
|
368276
|
+
* Write any option or setting by feature key. Refused when the description does
|
|
368277
|
+
* not list it, it is not writable or not available now, or the value is outside
|
|
368278
|
+
* its declared range / members.
|
|
368279
|
+
*/
|
|
367670
368280
|
setOption: require_sleep.method(zod.z.object({
|
|
367671
|
-
deviceId:
|
|
368281
|
+
deviceId: DeviceIdSchema,
|
|
367672
368282
|
key: zod.z.string().min(1),
|
|
367673
|
-
value:
|
|
367674
|
-
zod.z.boolean(),
|
|
367675
|
-
zod.z.string(),
|
|
367676
|
-
zod.z.number()
|
|
367677
|
-
])
|
|
368283
|
+
value: DishwasherValueSchema
|
|
367678
368284
|
}), zod.z.void(), {
|
|
367679
368285
|
kind: "mutation",
|
|
367680
368286
|
auth: "protected"
|
|
367681
|
-
})
|
|
368287
|
+
}),
|
|
368288
|
+
/** What this appliance can do, from its own description — the UI is derived from it. */
|
|
368289
|
+
getOptions: require_sleep.method(zod.z.object({ deviceId: DeviceIdSchema }), DishwasherOptionsSchema, { auth: "protected" })
|
|
367682
368290
|
},
|
|
367683
368291
|
status: {
|
|
367684
368292
|
schema: DishwasherStatusSchema,
|
|
@@ -382698,6 +383306,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
382698
383306
|
addonId: null,
|
|
382699
383307
|
access: "view"
|
|
382700
383308
|
},
|
|
383309
|
+
"dishwasher.getOptions": {
|
|
383310
|
+
capName: "dishwasher",
|
|
383311
|
+
capScope: "device",
|
|
383312
|
+
addonId: null,
|
|
383313
|
+
access: "view"
|
|
383314
|
+
},
|
|
382701
383315
|
"dishwasher.getStatus": {
|
|
382702
383316
|
capName: "dishwasher",
|
|
382703
383317
|
capScope: "device",
|
|
@@ -382710,6 +383324,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
382710
383324
|
addonId: null,
|
|
382711
383325
|
access: "create"
|
|
382712
383326
|
},
|
|
383327
|
+
"dishwasher.resume": {
|
|
383328
|
+
capName: "dishwasher",
|
|
383329
|
+
capScope: "device",
|
|
383330
|
+
addonId: null,
|
|
383331
|
+
access: "create"
|
|
383332
|
+
},
|
|
382713
383333
|
"dishwasher.setChildLock": {
|
|
382714
383334
|
capName: "dishwasher",
|
|
382715
383335
|
capScope: "device",
|
|
@@ -387210,6 +387830,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
387210
387830
|
addonId: null,
|
|
387211
387831
|
access: "view"
|
|
387212
387832
|
},
|
|
387833
|
+
"storageMigration.moverClearance": {
|
|
387834
|
+
capName: "storage-migration",
|
|
387835
|
+
capScope: "system",
|
|
387836
|
+
addonId: null,
|
|
387837
|
+
access: "view"
|
|
387838
|
+
},
|
|
387213
387839
|
"storageMigration.movers": {
|
|
387214
387840
|
capName: "storage-migration",
|
|
387215
387841
|
capScope: "system",
|
|
@@ -392558,6 +393184,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
392558
393184
|
form: "single",
|
|
392559
393185
|
optional: false
|
|
392560
393186
|
}],
|
|
393187
|
+
"dishwasher.getOptions": [{
|
|
393188
|
+
name: "deviceId",
|
|
393189
|
+
form: "single",
|
|
393190
|
+
optional: false
|
|
393191
|
+
}],
|
|
392561
393192
|
"dishwasher.getStatus": [{
|
|
392562
393193
|
name: "deviceId",
|
|
392563
393194
|
form: "single",
|
|
@@ -392568,6 +393199,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
392568
393199
|
form: "single",
|
|
392569
393200
|
optional: false
|
|
392570
393201
|
}],
|
|
393202
|
+
"dishwasher.resume": [{
|
|
393203
|
+
name: "deviceId",
|
|
393204
|
+
form: "single",
|
|
393205
|
+
optional: false
|
|
393206
|
+
}],
|
|
392571
393207
|
"dishwasher.setChildLock": [{
|
|
392572
393208
|
name: "deviceId",
|
|
392573
393209
|
form: "single",
|
|
@@ -396202,6 +396838,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
396202
396838
|
status: (input) => dispatch("storageMigration", "status", "query", input),
|
|
396203
396839
|
cancel: (input) => dispatch("storageMigration", "cancel", "mutation", input),
|
|
396204
396840
|
movers: (input) => dispatch("storageMigration", "movers", "query", input),
|
|
396841
|
+
moverClearance: (input) => dispatch("storageMigration", "moverClearance", "query", input),
|
|
396205
396842
|
residue: (input) => dispatch("storageMigration", "residue", "query", input),
|
|
396206
396843
|
drain: (input) => dispatch("storageMigration", "drain", "mutation", input),
|
|
396207
396844
|
cleanupStart: (input) => dispatch("storageMigration", "cleanupStart", "mutation", input),
|
|
@@ -396739,7 +397376,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
396739
397376
|
case "deviceTypes":
|
|
396740
397377
|
return kind.startsWith("device-") || kind === "detection-blind";
|
|
396741
397378
|
case "nodeIds":
|
|
396742
|
-
return kind.startsWith("node-") || kind === "addon-crash-loop" || kind === "addon-update-available" || kind === "addon-updated" || kind === "server-update-available" || kind === "wrapper-update-available" || kind === "server-updated" || kind.startsWith("storage-location-");
|
|
397379
|
+
return kind.startsWith("node-") || kind === "addon-crash-loop" || kind === "addon-update-available" || kind === "addon-updated" || kind === "server-update-available" || kind === "wrapper-update-available" || kind === "server-updated" || kind.startsWith("storage-location-") || kind.startsWith("alert-");
|
|
396743
397380
|
case "packageNames":
|
|
396744
397381
|
return kind.endsWith("update-available") || kind === "addon-updated" || kind === "node-updating" || kind === "server-updated";
|
|
396745
397382
|
case "consumableLowPercent":
|
|
@@ -396788,6 +397425,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
396788
397425
|
"wrapper-update-available": "system",
|
|
396789
397426
|
"backup-completed": "system",
|
|
396790
397427
|
"export-completed": "system",
|
|
397428
|
+
"alert-critical": "system",
|
|
397429
|
+
"alert-error": "system",
|
|
397430
|
+
"alert-critical-resolved": "system",
|
|
396791
397431
|
"storage-location-low": "system",
|
|
396792
397432
|
"storage-location-critical": "system",
|
|
396793
397433
|
"storage-location-ok": "system",
|
|
@@ -396923,6 +397563,16 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
396923
397563
|
"storage-location-ok"
|
|
396924
397564
|
]
|
|
396925
397565
|
},
|
|
397566
|
+
{
|
|
397567
|
+
id: "alerts",
|
|
397568
|
+
family: "system",
|
|
397569
|
+
label: "Alerts",
|
|
397570
|
+
kinds: [
|
|
397571
|
+
"alert-critical",
|
|
397572
|
+
"alert-error",
|
|
397573
|
+
"alert-critical-resolved"
|
|
397574
|
+
]
|
|
397575
|
+
},
|
|
396926
397576
|
{
|
|
396927
397577
|
id: "alarm",
|
|
396928
397578
|
family: "alarm",
|
|
@@ -397995,6 +398645,69 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
397995
398645
|
return sensorKinds.every((kind) => NC_SENSOR_TRANSITION_KINDS.includes(normaliseKind(kind)));
|
|
397996
398646
|
}
|
|
397997
398647
|
var NC_SENSOR_TRANSITION_UNSUPPORTED_REASON = "Only a sensor that raises and clears (water, smoke, gas, CO, vibration, tamper, motion, contact) can fire on one edge. Pick only such sensor kinds, or the rule fires on every change.";
|
|
398648
|
+
var AlertEpisodePayloadSchema = zod.z.object({
|
|
398649
|
+
phase: zod.z.enum(["raised", "resolved"]),
|
|
398650
|
+
episodeId: zod.z.string().min(1),
|
|
398651
|
+
alertId: zod.z.string().min(1),
|
|
398652
|
+
severity: AlertSeveritySchema,
|
|
398653
|
+
category: zod.z.string(),
|
|
398654
|
+
title: zod.z.string(),
|
|
398655
|
+
message: zod.z.string(),
|
|
398656
|
+
sourceType: zod.z.string().optional(),
|
|
398657
|
+
sourceId: zod.z.string().optional(),
|
|
398658
|
+
nodeId: zod.z.string().optional(),
|
|
398659
|
+
/** The alert's own action link (where the operator acts on it), when it has one. */
|
|
398660
|
+
actionUrl: zod.z.string().optional(),
|
|
398661
|
+
at: zod.z.number()
|
|
398662
|
+
});
|
|
398663
|
+
function parseAlertEpisodePayload(data) {
|
|
398664
|
+
const parsed = AlertEpisodePayloadSchema.safeParse(data);
|
|
398665
|
+
return parsed.success ? parsed.data : null;
|
|
398666
|
+
}
|
|
398667
|
+
function isAlertEpisodeOpen(status) {
|
|
398668
|
+
return status !== "completed" && status !== "dismissed";
|
|
398669
|
+
}
|
|
398670
|
+
function isAlertEpisodeSeverity(severity) {
|
|
398671
|
+
return severity === "critical" || severity === "error";
|
|
398672
|
+
}
|
|
398673
|
+
function alertEpisodeId(alert) {
|
|
398674
|
+
const minted = alert.metadata?.["episodeId"];
|
|
398675
|
+
return typeof minted === "string" && minted.length > 0 ? minted : `${alert.id}@${String(alert.createdAt)}`;
|
|
398676
|
+
}
|
|
398677
|
+
function alertNodeId(alert) {
|
|
398678
|
+
const direct = alert.metadata?.["nodeId"];
|
|
398679
|
+
if (typeof direct === "string") return direct;
|
|
398680
|
+
const runner = alert.metadata?.["runner"];
|
|
398681
|
+
if (typeof runner === "object" && runner !== null && "nodeId" in runner) {
|
|
398682
|
+
const id = runner.nodeId;
|
|
398683
|
+
if (typeof id === "string") return id;
|
|
398684
|
+
}
|
|
398685
|
+
return alert.source?.type === "node" ? alert.source.id : void 0;
|
|
398686
|
+
}
|
|
398687
|
+
function alertEpisodeKind(severity, phase) {
|
|
398688
|
+
if (severity === "critical") return phase === "raised" ? "alert-critical" : "alert-critical-resolved";
|
|
398689
|
+
if (severity === "error" && phase === "raised") return "alert-error";
|
|
398690
|
+
return null;
|
|
398691
|
+
}
|
|
398692
|
+
function alertEpisodePayload(alert, phase, at) {
|
|
398693
|
+
const nodeId = alertNodeId(alert);
|
|
398694
|
+
return {
|
|
398695
|
+
phase,
|
|
398696
|
+
episodeId: alertEpisodeId(alert),
|
|
398697
|
+
alertId: alert.id,
|
|
398698
|
+
severity: alert.severity,
|
|
398699
|
+
category: alert.category,
|
|
398700
|
+
title: alert.title,
|
|
398701
|
+
message: alert.message,
|
|
398702
|
+
...alert.source !== void 0 ? {
|
|
398703
|
+
sourceType: alert.source.type,
|
|
398704
|
+
sourceId: alert.source.id
|
|
398705
|
+
} : {},
|
|
398706
|
+
...nodeId !== void 0 ? { nodeId } : {},
|
|
398707
|
+
...alert.action?.href !== void 0 ? { actionUrl: alert.action.href } : {},
|
|
398708
|
+
at
|
|
398709
|
+
};
|
|
398710
|
+
}
|
|
397998
398711
|
var RULE_BODY_ONLY = ["body"];
|
|
397999
398712
|
var RULE_TEXT = ["title", "body"];
|
|
398000
398713
|
var BATTERY = ["device-battery-low", "device-battery-normal"];
|
|
@@ -398004,6 +398717,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
398004
398717
|
"device-tank-full",
|
|
398005
398718
|
"device-tank-normal"
|
|
398006
398719
|
];
|
|
398720
|
+
var ALERT_EPISODE = [
|
|
398721
|
+
"alert-critical",
|
|
398722
|
+
"alert-error",
|
|
398723
|
+
"alert-critical-resolved"
|
|
398724
|
+
];
|
|
398007
398725
|
var UPDATES = [
|
|
398008
398726
|
"addon-update-available",
|
|
398009
398727
|
"server-update-available",
|
|
@@ -398525,7 +399243,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
398525
399243
|
"server-updated",
|
|
398526
399244
|
"storage-location-low",
|
|
398527
399245
|
"storage-location-critical",
|
|
398528
|
-
"storage-location-ok"
|
|
399246
|
+
"storage-location-ok",
|
|
399247
|
+
...ALERT_EPISODE
|
|
398529
399248
|
]
|
|
398530
399249
|
},
|
|
398531
399250
|
{
|
|
@@ -398547,7 +399266,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
398547
399266
|
"server-updated",
|
|
398548
399267
|
"storage-location-low",
|
|
398549
399268
|
"storage-location-critical",
|
|
398550
|
-
"storage-location-ok"
|
|
399269
|
+
"storage-location-ok",
|
|
399270
|
+
...ALERT_EPISODE
|
|
398551
399271
|
]
|
|
398552
399272
|
},
|
|
398553
399273
|
{
|
|
@@ -398614,7 +399334,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
398614
399334
|
families: ["rule"],
|
|
398615
399335
|
fields: [...RULE_TEXT],
|
|
398616
399336
|
kinds: ["system"],
|
|
398617
|
-
systemEventKinds: ["recording-degraded"]
|
|
399337
|
+
systemEventKinds: ["recording-degraded", ...ALERT_EPISODE]
|
|
398618
399338
|
},
|
|
398619
399339
|
{
|
|
398620
399340
|
name: "locationName",
|
|
@@ -398811,13 +399531,53 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
398811
399531
|
},
|
|
398812
399532
|
{
|
|
398813
399533
|
name: "title",
|
|
398814
|
-
label: "Export title",
|
|
399534
|
+
label: "Export or alert title",
|
|
398815
399535
|
example: "Ingresso 08:00",
|
|
398816
399536
|
group: "system",
|
|
398817
399537
|
families: ["rule"],
|
|
398818
399538
|
fields: [...RULE_TEXT],
|
|
398819
399539
|
kinds: ["system"],
|
|
398820
|
-
systemEventKinds: ["export-completed"]
|
|
399540
|
+
systemEventKinds: ["export-completed", ...ALERT_EPISODE]
|
|
399541
|
+
},
|
|
399542
|
+
{
|
|
399543
|
+
name: "severity",
|
|
399544
|
+
label: "Alert severity",
|
|
399545
|
+
example: "critical",
|
|
399546
|
+
group: "system",
|
|
399547
|
+
families: ["rule"],
|
|
399548
|
+
fields: [...RULE_TEXT],
|
|
399549
|
+
kinds: ["system"],
|
|
399550
|
+
systemEventKinds: [...ALERT_EPISODE]
|
|
399551
|
+
},
|
|
399552
|
+
{
|
|
399553
|
+
name: "category",
|
|
399554
|
+
label: "Alert category",
|
|
399555
|
+
example: "addon.runner-failed",
|
|
399556
|
+
group: "system",
|
|
399557
|
+
families: ["rule"],
|
|
399558
|
+
fields: [...RULE_TEXT],
|
|
399559
|
+
kinds: ["system"],
|
|
399560
|
+
systemEventKinds: [...ALERT_EPISODE]
|
|
399561
|
+
},
|
|
399562
|
+
{
|
|
399563
|
+
name: "source",
|
|
399564
|
+
label: "Alert source (addon, node or runner)",
|
|
399565
|
+
example: "recorder",
|
|
399566
|
+
group: "system",
|
|
399567
|
+
families: ["rule"],
|
|
399568
|
+
fields: [...RULE_TEXT],
|
|
399569
|
+
kinds: ["system"],
|
|
399570
|
+
systemEventKinds: [...ALERT_EPISODE]
|
|
399571
|
+
},
|
|
399572
|
+
{
|
|
399573
|
+
name: "actionUrl",
|
|
399574
|
+
label: "Alert action link",
|
|
399575
|
+
example: "/system/addons",
|
|
399576
|
+
group: "system",
|
|
399577
|
+
families: ["rule"],
|
|
399578
|
+
fields: [...RULE_TEXT],
|
|
399579
|
+
kinds: ["system"],
|
|
399580
|
+
systemEventKinds: [...ALERT_EPISODE]
|
|
398821
399581
|
},
|
|
398822
399582
|
{
|
|
398823
399583
|
name: "exportId",
|
|
@@ -399013,7 +399773,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
399013
399773
|
"device-tank-full",
|
|
399014
399774
|
"device-tank-normal",
|
|
399015
399775
|
"node-restarting",
|
|
399016
|
-
"node-updating"
|
|
399776
|
+
"node-updating",
|
|
399777
|
+
"alert-critical",
|
|
399778
|
+
"alert-error",
|
|
399779
|
+
"alert-critical-resolved"
|
|
399017
399780
|
];
|
|
399018
399781
|
function servedTemplateVars() {
|
|
399019
399782
|
return NC_TEMPLATE_VARS.filter((d) => !isHeldBackTemplateVar(d)).map((d) => d.systemEventKinds === void 0 ? d : {
|
|
@@ -402214,6 +402977,52 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
402214
402977
|
}
|
|
402215
402978
|
current[parts[parts.length - 1]] = value;
|
|
402216
402979
|
}
|
|
402980
|
+
var OAUTH_LANDING_PATH = "/sso-complete";
|
|
402981
|
+
var OAUTH_LANDING_REASONS = [
|
|
402982
|
+
"access_denied",
|
|
402983
|
+
"invalid_state",
|
|
402984
|
+
"invalid_request",
|
|
402985
|
+
"unknown_broker",
|
|
402986
|
+
"not_configured",
|
|
402987
|
+
"exchange_failed",
|
|
402988
|
+
"no_refresh_token",
|
|
402989
|
+
"unavailable",
|
|
402990
|
+
"unknown"
|
|
402991
|
+
];
|
|
402992
|
+
function isOauthLandingReason(value) {
|
|
402993
|
+
return OAUTH_LANDING_REASONS.some((reason) => reason === value);
|
|
402994
|
+
}
|
|
402995
|
+
function oauthLandingUrl(origin, outcome) {
|
|
402996
|
+
const params = new URLSearchParams({
|
|
402997
|
+
return: "oauth",
|
|
402998
|
+
status: outcome.status
|
|
402999
|
+
});
|
|
403000
|
+
if (outcome.addonId !== void 0) params.set("addon", outcome.addonId);
|
|
403001
|
+
if (outcome.brokerId !== void 0) params.set("broker", outcome.brokerId);
|
|
403002
|
+
if (outcome.integration !== void 0) params.set("integration", outcome.integration);
|
|
403003
|
+
if (outcome.status === "error") params.set("reason", outcome.reason ?? "unknown");
|
|
403004
|
+
if (outcome.action === "disconnect") params.set("action", "disconnect");
|
|
403005
|
+
return `${origin === null ? "" : origin.replace(/\/+$/, "")}${OAUTH_LANDING_PATH}#${params.toString()}`;
|
|
403006
|
+
}
|
|
403007
|
+
function parseOauthLandingFragment(hash) {
|
|
403008
|
+
if (!hash.startsWith("#")) return null;
|
|
403009
|
+
const params = new URLSearchParams(hash.slice(1));
|
|
403010
|
+
if (params.get("return") !== "oauth") return null;
|
|
403011
|
+
const status = params.get("status");
|
|
403012
|
+
if (status !== "success" && status !== "error") return null;
|
|
403013
|
+
const addonId = params.get("addon");
|
|
403014
|
+
const brokerId = params.get("broker");
|
|
403015
|
+
const integration = params.get("integration");
|
|
403016
|
+
const reasonRaw = params.get("reason");
|
|
403017
|
+
return {
|
|
403018
|
+
status,
|
|
403019
|
+
...addonId !== null && addonId.length > 0 ? { addonId } : {},
|
|
403020
|
+
...brokerId !== null && brokerId.length > 0 ? { brokerId } : {},
|
|
403021
|
+
...integration !== null && integration.length > 0 ? { integration } : {},
|
|
403022
|
+
...status === "error" ? { reason: isOauthLandingReason(reasonRaw) ? reasonRaw : "unknown" } : {},
|
|
403023
|
+
...params.get("action") === "disconnect" ? { action: "disconnect" } : {}
|
|
403024
|
+
};
|
|
403025
|
+
}
|
|
402217
403026
|
var MB = 1024 * 1024;
|
|
402218
403027
|
var DEFAULT_POOL_MEMORY_POLICY = {
|
|
402219
403028
|
sampleIntervalMs: 6e4,
|
|
@@ -403066,6 +403875,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
403066
403875
|
exports.AlarmArmModeSchema = AlarmArmModeSchema;
|
|
403067
403876
|
exports.AlarmPanelStatusSchema = AlarmPanelStatusSchema;
|
|
403068
403877
|
exports.AlarmStateSchema = AlarmStateSchema;
|
|
403878
|
+
exports.AlertEpisodePayloadSchema = AlertEpisodePayloadSchema;
|
|
403069
403879
|
exports.AlertSchema = AlertSchema;
|
|
403070
403880
|
exports.AlertSeveritySchema = AlertSeveritySchema;
|
|
403071
403881
|
exports.AlertSourceSchema = AlertSourceSchema;
|
|
@@ -403544,9 +404354,16 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
403544
404354
|
exports.DiscoveredChildStatusSchema = DiscoveredChildStatusSchema;
|
|
403545
404355
|
exports.DiscoveredDeviceSchema = DiscoveredDeviceSchema;
|
|
403546
404356
|
exports.DiscoveredTargetSchema = DiscoveredTargetSchema;
|
|
404357
|
+
exports.DishwasherAccessSchema = DishwasherAccessSchema;
|
|
404358
|
+
exports.DishwasherAvailabilitySchema = DishwasherAvailabilitySchema;
|
|
403547
404359
|
exports.DishwasherConsumableLevelSchema = DishwasherConsumableLevelSchema;
|
|
404360
|
+
exports.DishwasherOperationStateSchema = DishwasherOperationStateSchema;
|
|
404361
|
+
exports.DishwasherOptionDescriptorSchema = DishwasherOptionDescriptorSchema;
|
|
404362
|
+
exports.DishwasherOptionsSchema = DishwasherOptionsSchema;
|
|
404363
|
+
exports.DishwasherProgramSchema = DishwasherProgramSchema;
|
|
403548
404364
|
exports.DishwasherStateSchema = DishwasherStateSchema;
|
|
403549
404365
|
exports.DishwasherStatusSchema = DishwasherStatusSchema;
|
|
404366
|
+
exports.DishwasherValueSchema = DishwasherValueSchema;
|
|
403550
404367
|
exports.DiskReconcileJobSchema = DiskReconcileJobSchema;
|
|
403551
404368
|
exports.DisposerChain = require_sleep.DisposerChain;
|
|
403552
404369
|
exports.DoorbellPressEventSchema = DoorbellPressEventSchema;
|
|
@@ -404214,6 +405031,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
404214
405031
|
exports.NotificationSchema = NotificationSchema;
|
|
404215
405032
|
exports.NotifierStatusSchema = NotifierStatusSchema;
|
|
404216
405033
|
exports.NumericSensorStatusSchema = NumericSensorStatusSchema;
|
|
405034
|
+
exports.OAUTH_LANDING_PATH = OAUTH_LANDING_PATH;
|
|
405035
|
+
exports.OAUTH_LANDING_REASONS = OAUTH_LANDING_REASONS;
|
|
404217
405036
|
exports.OPERATOR_WRITTEN_STALE_MS = OPERATOR_WRITTEN_STALE_MS;
|
|
404218
405037
|
exports.OPS_LOG_DEFAULT_LIMIT = OPS_LOG_DEFAULT_LIMIT;
|
|
404219
405038
|
exports.OPS_LOG_RING_DEFAULT_MAX = OPS_LOG_RING_DEFAULT_MAX;
|
|
@@ -404894,6 +405713,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
404894
405713
|
exports.alarmPanelCapability = alarmPanelCapability;
|
|
404895
405714
|
exports.alarmPatchLanded = alarmPatchLanded;
|
|
404896
405715
|
exports.alarmProfileById = alarmProfileById;
|
|
405716
|
+
exports.alertEpisodeId = alertEpisodeId;
|
|
405717
|
+
exports.alertEpisodeKind = alertEpisodeKind;
|
|
405718
|
+
exports.alertEpisodePayload = alertEpisodePayload;
|
|
405719
|
+
exports.alertNodeId = alertNodeId;
|
|
404897
405720
|
exports.alertsCapability = alertsCapability;
|
|
404898
405721
|
exports.allDoActions = allDoActions;
|
|
404899
405722
|
exports.allowedSuppliedEffect = allowedSuppliedEffect;
|
|
@@ -405250,6 +406073,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
405250
406073
|
exports.invocationFromEncodeProfile = require_composition.invocationFromEncodeProfile;
|
|
405251
406074
|
exports.isAgentOnlyPlacement = isAgentOnlyPlacement;
|
|
405252
406075
|
exports.isAlarmControllableCap = isAlarmControllableCap;
|
|
406076
|
+
exports.isAlertEpisodeOpen = isAlertEpisodeOpen;
|
|
406077
|
+
exports.isAlertEpisodeSeverity = isAlertEpisodeSeverity;
|
|
405253
406078
|
exports.isAppLinkBase = isAppLinkBase;
|
|
405254
406079
|
exports.isAppStartRefusal = isAppStartRefusal;
|
|
405255
406080
|
exports.isArrayOutputSchema = isArrayOutputSchema;
|
|
@@ -405285,6 +406110,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
405285
406110
|
exports.isLocationEnabled = isLocationEnabled;
|
|
405286
406111
|
exports.isMediaOwnerType = isMediaOwnerType;
|
|
405287
406112
|
exports.isNode = isNode;
|
|
406113
|
+
exports.isOauthLandingReason = isOauthLandingReason;
|
|
405288
406114
|
exports.isObjectInput = isObjectInput;
|
|
405289
406115
|
exports.isOccupancyRule = isOccupancyRule;
|
|
405290
406116
|
exports.isOwnerOnlyEventCategory = require_event_category.isOwnerOnlyEventCategory;
|
|
@@ -405408,6 +406234,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
405408
406234
|
exports.notifierCapability = notifierCapability;
|
|
405409
406235
|
exports.numericSensorCapability = numericSensorCapability;
|
|
405410
406236
|
exports.oauthIntegrationCapability = oauthIntegrationCapability;
|
|
406237
|
+
exports.oauthLandingUrl = oauthLandingUrl;
|
|
405411
406238
|
exports.objectInputDeclaresAddonId = objectInputDeclaresAddonId;
|
|
405412
406239
|
exports.objectInputDeclaresRequiredDeviceId = objectInputDeclaresRequiredDeviceId;
|
|
405413
406240
|
exports.occupancyScope = occupancyScope;
|
|
@@ -405420,6 +406247,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
405420
406247
|
exports.overlayClusterStepSettings = overlayClusterStepSettings;
|
|
405421
406248
|
exports.packagePickerItems = packagePickerItems;
|
|
405422
406249
|
exports.parseAdminBase = parseAdminBase;
|
|
406250
|
+
exports.parseAlertEpisodePayload = parseAlertEpisodePayload;
|
|
405423
406251
|
exports.parseAppAuthCallback = parseAppAuthCallback;
|
|
405424
406252
|
exports.parseAppFlowRequest = parseAppFlowRequest;
|
|
405425
406253
|
exports.parseAppPageLang = parseAppPageLang;
|
|
@@ -405430,6 +406258,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
405430
406258
|
exports.parseJsonObject = require_sleep.parseJsonObject;
|
|
405431
406259
|
exports.parseJsonUnknown = require_sleep.parseJsonUnknown;
|
|
405432
406260
|
exports.parseMediaOwnerKey = parseMediaOwnerKey;
|
|
406261
|
+
exports.parseOauthLandingFragment = parseOauthLandingFragment;
|
|
405433
406262
|
exports.parseOccupancyScope = parseOccupancyScope;
|
|
405434
406263
|
exports.parseProcStatus = parseProcStatus;
|
|
405435
406264
|
exports.parseProfileBrokerId = require_sleep.parseProfileBrokerId;
|
|
@@ -405632,6 +406461,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
405632
406461
|
exports.snapshotCapability = snapshotCapability;
|
|
405633
406462
|
exports.splitTranslationRef = splitTranslationRef;
|
|
405634
406463
|
exports.ssoBridgeCapability = ssoBridgeCapability;
|
|
406464
|
+
exports.startMoverUnderClearance = startMoverUnderClearance;
|
|
405635
406465
|
exports.startReachabilityPoll = startReachabilityPoll;
|
|
405636
406466
|
exports.stateLabel = stateLabel;
|
|
405637
406467
|
exports.stateVocabularyFor = stateVocabularyFor;
|
|
@@ -571830,6 +572660,10 @@ var require_app_page_shell = __commonJS({
|
|
|
571830
572660
|
`.error:empty{display:none}`,
|
|
571831
572661
|
`.btn:focus-visible,.link:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}`,
|
|
571832
572662
|
`code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;overflow-wrap:anywhere}`,
|
|
572663
|
+
`.field{display:flex;flex-direction:column;gap:var(--spacing-md)}`,
|
|
572664
|
+
`.field label{font-size:12px;line-height:16px;font-weight:500;color:var(--color-foreground-muted)}`,
|
|
572665
|
+
`input[type=url],input[type=text]{width:100%;min-height:44px;padding:10px 12px;border:1px solid var(--color-border);border-radius:var(--radius-lg);background:var(--color-background);color:var(--color-foreground);font:inherit}`,
|
|
572666
|
+
`input[type=url]:focus-visible,input[type=text]:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}`,
|
|
571833
572667
|
`form{display:contents}`,
|
|
571834
572668
|
`.actions{display:flex;flex-direction:column;gap:var(--spacing-md)}`
|
|
571835
572669
|
].join("");
|
|
@@ -571973,6 +572807,7 @@ var require_oauth2_routes = __commonJS({
|
|
|
571973
572807
|
exports.isRedirectUriAllowed = isRedirectUriAllowed;
|
|
571974
572808
|
exports.summariseScopes = summariseScopes;
|
|
571975
572809
|
exports.registerOauth2Routes = registerOauth2Routes;
|
|
572810
|
+
var types_1 = require_dist4();
|
|
571976
572811
|
var session_cookie_js_1 = require_session_cookie();
|
|
571977
572812
|
var app_page_strings_js_1 = require_app_page_strings();
|
|
571978
572813
|
var consent_page_js_1 = require_consent_page();
|
|
@@ -572119,7 +572954,7 @@ var require_oauth2_routes = __commonJS({
|
|
|
572119
572954
|
}
|
|
572120
572955
|
return scopes.map((s) => s.type).join(", ") || "no permissions";
|
|
572121
572956
|
}
|
|
572122
|
-
function refuseAuthorize(reply, logger, method, call, refusal) {
|
|
572957
|
+
function refuseAuthorize(request, reply, logger, method, call, refusal) {
|
|
572123
572958
|
logger.warn(`oauth2 authorize refused: ${refusal.error}`, {
|
|
572124
572959
|
meta: {
|
|
572125
572960
|
method,
|
|
@@ -572132,7 +572967,18 @@ var require_oauth2_routes = __commonJS({
|
|
|
572132
572967
|
if (refusal.retryAfterSec !== void 0) {
|
|
572133
572968
|
void reply.header("Retry-After", String(refusal.retryAfterSec));
|
|
572134
572969
|
}
|
|
572135
|
-
return reply
|
|
572970
|
+
return answerRefusal(request, reply, refusal.status, { error: refusal.error, ...refusal.detail }, refusal.status === 503 ? "unavailable" : "invalid_request", typeof refusal.detail?.received === "string" ? refusal.detail.received : void 0);
|
|
572971
|
+
}
|
|
572972
|
+
function answerRefusal(request, reply, status, body, reason, integration) {
|
|
572973
|
+
const accept = request.headers.accept;
|
|
572974
|
+
if (typeof accept === "string" && accept.includes("text/html")) {
|
|
572975
|
+
return reply.redirect((0, types_1.oauthLandingUrl)(null, {
|
|
572976
|
+
status: "error",
|
|
572977
|
+
reason,
|
|
572978
|
+
...integration !== void 0 && /^[A-Za-z0-9._-]{1,64}$/.test(integration) ? { integration } : {}
|
|
572979
|
+
}));
|
|
572980
|
+
}
|
|
572981
|
+
return reply.status(status).send(body);
|
|
572136
572982
|
}
|
|
572137
572983
|
function refuseUnauthenticated(request, reply, logger, call, reason) {
|
|
572138
572984
|
const redirected = (0, session_cookie_js_1.shouldRedirectToLogin)(request.method, request.headers.accept);
|
|
@@ -572181,13 +573027,13 @@ var require_oauth2_routes = __commonJS({
|
|
|
572181
573027
|
}
|
|
572182
573028
|
const registry = deps.getRegistry();
|
|
572183
573029
|
if (!registry) {
|
|
572184
|
-
return reply
|
|
573030
|
+
return answerRefusal(request, reply, 503, { error: "service_unavailable" }, "unavailable");
|
|
572185
573031
|
}
|
|
572186
573032
|
const { descriptors, pendingAddons } = await readIntegrationRegistry(registry);
|
|
572187
573033
|
const query = request.query;
|
|
572188
573034
|
const v = validateAuthorizeQuery(query, descriptors, pendingAddons);
|
|
572189
573035
|
if (!v.ok) {
|
|
572190
|
-
return refuseAuthorize(reply, deps.logger, "GET", call, v);
|
|
573036
|
+
return refuseAuthorize(request, reply, deps.logger, "GET", call, v);
|
|
572191
573037
|
}
|
|
572192
573038
|
const descriptor = descriptors.get(v.integration);
|
|
572193
573039
|
if (!isRedirectUriAllowed(v.redirectUri, descriptor.allowedRedirectPrefixes, descriptor.allowedPrivateHostPaths ?? [])) {
|
|
@@ -572201,7 +573047,7 @@ var require_oauth2_routes = __commonJS({
|
|
|
572201
573047
|
allowedPrivateHostPaths: descriptor.allowedPrivateHostPaths ?? []
|
|
572202
573048
|
}
|
|
572203
573049
|
});
|
|
572204
|
-
return reply
|
|
573050
|
+
return answerRefusal(request, reply, 400, { error: "invalid_request \u2014 redirect_uri not allowed for this integration" }, "invalid_request", v.integration);
|
|
572205
573051
|
}
|
|
572206
573052
|
const html = (0, consent_page_js_1.renderConsentPage)({
|
|
572207
573053
|
lang: (0, app_page_strings_js_1.resolveAppPageLang)({
|
|
@@ -572258,7 +573104,7 @@ var require_oauth2_routes = __commonJS({
|
|
|
572258
573104
|
}
|
|
572259
573105
|
const registry = deps.getRegistry();
|
|
572260
573106
|
if (!registry) {
|
|
572261
|
-
return reply
|
|
573107
|
+
return answerRefusal(request, reply, 503, { error: "service_unavailable" }, "unavailable");
|
|
572262
573108
|
}
|
|
572263
573109
|
const { descriptors, pendingAddons } = await readIntegrationRegistry(registry);
|
|
572264
573110
|
const body = request.body;
|
|
@@ -572272,7 +573118,7 @@ var require_oauth2_routes = __commonJS({
|
|
|
572272
573118
|
};
|
|
572273
573119
|
const v = validateAuthorizeQuery(formQuery, descriptors, pendingAddons);
|
|
572274
573120
|
if (!v.ok) {
|
|
572275
|
-
return refuseAuthorize(reply, deps.logger, "POST", call, v);
|
|
573121
|
+
return refuseAuthorize(request, reply, deps.logger, "POST", call, v);
|
|
572276
573122
|
}
|
|
572277
573123
|
const descriptor = descriptors.get(v.integration);
|
|
572278
573124
|
if (!isRedirectUriAllowed(v.redirectUri, descriptor.allowedRedirectPrefixes, descriptor.allowedPrivateHostPaths ?? [])) {
|
|
@@ -572286,7 +573132,7 @@ var require_oauth2_routes = __commonJS({
|
|
|
572286
573132
|
allowedPrivateHostPaths: descriptor.allowedPrivateHostPaths ?? []
|
|
572287
573133
|
}
|
|
572288
573134
|
});
|
|
572289
|
-
return reply
|
|
573135
|
+
return answerRefusal(request, reply, 400, { error: "invalid_request \u2014 redirect_uri not allowed for this integration" }, "invalid_request", v.integration);
|
|
572290
573136
|
}
|
|
572291
573137
|
if (body.consent !== "allow") {
|
|
572292
573138
|
return reply.redirect(`${v.redirectUri}?error=access_denied&state=${encodeURIComponent(v.state)}`);
|
|
@@ -592273,7 +593119,7 @@ var require_manual_boot = __commonJS({
|
|
|
592273
593119
|
throw new Error("the process service did not answer");
|
|
592274
593120
|
return rows;
|
|
592275
593121
|
},
|
|
592276
|
-
// The verdict reaches the alert centre (one
|
|
593122
|
+
// The verdict reaches the alert centre (one critical alert).
|
|
592277
593123
|
onResult: (check) => {
|
|
592278
593124
|
eventBusService.emit({
|
|
592279
593125
|
id: (0, node_crypto_1.randomUUID)(),
|