@camstack/addon-pipeline 1.2.631 → 1.2.632
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/CHANGELOG.md +6 -0
- package/dist/audio-analyzer/index.js +3 -3
- package/dist/audio-analyzer/index.mjs +3 -3
- package/dist/{custom-model-catalog-DLv2FLul.mjs → custom-model-catalog-B2w26VBG.mjs} +2 -2
- package/dist/{custom-model-catalog-5IT-gwL2.js → custom-model-catalog-DN4xBVQE.js} +2 -2
- package/dist/detection-pipeline/index.js +4 -4
- package/dist/detection-pipeline/index.mjs +4 -4
- package/dist/{dist-CVvwej3J.js → dist-CLo3QHtG.js} +1540 -932
- package/dist/{dist-DV6W_qKY.mjs → dist-DWkdwtle.mjs} +1540 -932
- package/dist/{model-catalogs-lWWyJZqw.js → model-catalogs-DIviCtiQ.js} +1 -1
- package/dist/{model-catalogs-CI9KoY4D.mjs → model-catalogs-rs7okKyp.mjs} +1 -1
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-KEh_tmT2.mjs → node-CAJ1Dal-.mjs} +1 -1
- package/dist/{node-BQ7P2No5.js → node-CPqDCFas.js} +1 -1
- package/dist/pipeline-runner/index.js +3 -3
- package/dist/pipeline-runner/index.mjs +3 -3
- package/dist/{process-memory-C-3bSKF5.js → process-memory-BrKzYxim.js} +1 -1
- package/dist/{process-memory-ChQO96Xb.mjs → process-memory-DJWthb6k.mjs} +1 -1
- package/dist/recorder/index.js +3 -2
- package/dist/recorder/index.mjs +3 -2
- package/dist/{segment-demux-js-8YepQCG3.js → segment-demux-js-Bt5bxfyh.js} +1 -1
- package/dist/{segment-demux-js-Dy75tkrR.mjs → segment-demux-js-CZdgio0n.mjs} +1 -1
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CKN6MEA_.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CjjdxZUq.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DZmxw-we.mjs +26 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CFflpMdb.mjs +26 -0
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-BqjKmOsK.mjs → hostInit-MWvZi8Nq.mjs} +2 -2
- package/dist/stream-broker/index.js +3 -3
- package/dist/stream-broker/index.mjs +3 -3
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BPnizAbp.mjs +0 -26
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BL5-HIQd.mjs +0 -26
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
let node_crypto = require("node:crypto");
|
|
2
|
-
//#region ../types/dist/event-category-
|
|
2
|
+
//#region ../types/dist/event-category-DmZDPDf_.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -626,7 +626,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
626
626
|
* (a track was promoted to a stationary-registry entry) or departs (the
|
|
627
627
|
* object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
|
|
628
628
|
* the dedicated "Stationary" section — never the live event feed. Payload:
|
|
629
|
-
* `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp }`.
|
|
629
|
+
* `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp, observedAt, zones }`.
|
|
630
630
|
*/
|
|
631
631
|
EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
|
|
632
632
|
/**
|
|
@@ -764,6 +764,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
764
764
|
*/
|
|
765
765
|
EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
|
|
766
766
|
/**
|
|
767
|
+
* An action run started or ended. Emitted by the `actions` surface.
|
|
768
|
+
* Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
|
|
769
|
+
*/
|
|
770
|
+
EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
|
|
771
|
+
/**
|
|
767
772
|
* Progress update from a running model conversion job.
|
|
768
773
|
* Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
|
|
769
774
|
* Emitted by `addon-model-studio` on the converting node.
|
|
@@ -5575,7 +5580,7 @@ var ZodIssueCode = {
|
|
|
5575
5580
|
var ZodFirstPartyTypeKind;
|
|
5576
5581
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5577
5582
|
//#endregion
|
|
5578
|
-
//#region ../types/dist/sleep
|
|
5583
|
+
//#region ../types/dist/sleep-Crlmu_tO.mjs
|
|
5579
5584
|
/**
|
|
5580
5585
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5581
5586
|
* window to float samples (D455).
|
|
@@ -9034,6 +9039,8 @@ Object.freeze({ "doorbell": "lastPressedAt" });
|
|
|
9034
9039
|
/** Every capability name, so addon code can check a name without the schema graph. */
|
|
9035
9040
|
var CAP_NAMES = Object.freeze([
|
|
9036
9041
|
"accessories",
|
|
9042
|
+
"action-source",
|
|
9043
|
+
"actions",
|
|
9037
9044
|
"addon-pages",
|
|
9038
9045
|
"addon-pages-source",
|
|
9039
9046
|
"addon-routes",
|
|
@@ -9222,11 +9229,11 @@ var CAP_NAMES = Object.freeze([
|
|
|
9222
9229
|
Object.freeze({
|
|
9223
9230
|
"air-quality-sensor": [
|
|
9224
9231
|
{
|
|
9225
|
-
"path": "
|
|
9232
|
+
"path": "co2",
|
|
9226
9233
|
"valueType": "number"
|
|
9227
9234
|
},
|
|
9228
9235
|
{
|
|
9229
|
-
"path": "
|
|
9236
|
+
"path": "voc",
|
|
9230
9237
|
"valueType": "number"
|
|
9231
9238
|
},
|
|
9232
9239
|
{
|
|
@@ -9276,7 +9283,7 @@ Object.freeze({
|
|
|
9276
9283
|
}
|
|
9277
9284
|
],
|
|
9278
9285
|
"ambient-light-sensor": [{
|
|
9279
|
-
"path": "
|
|
9286
|
+
"path": "illuminance",
|
|
9280
9287
|
"valueType": "number"
|
|
9281
9288
|
}],
|
|
9282
9289
|
"audio-metrics": [
|
|
@@ -9337,7 +9344,7 @@ Object.freeze({
|
|
|
9337
9344
|
],
|
|
9338
9345
|
"battery": [
|
|
9339
9346
|
{
|
|
9340
|
-
"path": "
|
|
9347
|
+
"path": "level",
|
|
9341
9348
|
"valueType": "number"
|
|
9342
9349
|
},
|
|
9343
9350
|
{
|
|
@@ -9359,7 +9366,7 @@ Object.freeze({
|
|
|
9359
9366
|
"valueType": "number"
|
|
9360
9367
|
},
|
|
9361
9368
|
{
|
|
9362
|
-
"path": "
|
|
9369
|
+
"path": "voltage",
|
|
9363
9370
|
"valueType": "number"
|
|
9364
9371
|
},
|
|
9365
9372
|
{
|
|
@@ -9380,7 +9387,7 @@ Object.freeze({
|
|
|
9380
9387
|
"valueType": "boolean"
|
|
9381
9388
|
}],
|
|
9382
9389
|
"brightness": [{
|
|
9383
|
-
"path": "
|
|
9390
|
+
"path": "level",
|
|
9384
9391
|
"valueType": "number"
|
|
9385
9392
|
}],
|
|
9386
9393
|
"broker": [{
|
|
@@ -9581,7 +9588,7 @@ Object.freeze({
|
|
|
9581
9588
|
"valueType": "number"
|
|
9582
9589
|
},
|
|
9583
9590
|
{
|
|
9584
|
-
"path": "
|
|
9591
|
+
"path": "colorTemperature",
|
|
9585
9592
|
"valueType": "number"
|
|
9586
9593
|
}
|
|
9587
9594
|
],
|
|
@@ -9760,15 +9767,15 @@ Object.freeze({
|
|
|
9760
9767
|
"valueType": "string"
|
|
9761
9768
|
},
|
|
9762
9769
|
{
|
|
9763
|
-
"path": "
|
|
9770
|
+
"path": "remaining",
|
|
9764
9771
|
"valueType": "number"
|
|
9765
9772
|
},
|
|
9766
9773
|
{
|
|
9767
|
-
"path": "
|
|
9774
|
+
"path": "delayedStart",
|
|
9768
9775
|
"valueType": "number"
|
|
9769
9776
|
},
|
|
9770
9777
|
{
|
|
9771
|
-
"path": "
|
|
9778
|
+
"path": "progress",
|
|
9772
9779
|
"valueType": "number"
|
|
9773
9780
|
},
|
|
9774
9781
|
{
|
|
@@ -9882,7 +9889,7 @@ Object.freeze({
|
|
|
9882
9889
|
],
|
|
9883
9890
|
"fan-control": [
|
|
9884
9891
|
{
|
|
9885
|
-
"path": "
|
|
9892
|
+
"path": "speed",
|
|
9886
9893
|
"valueType": "number"
|
|
9887
9894
|
},
|
|
9888
9895
|
{
|
|
@@ -9982,7 +9989,7 @@ Object.freeze({
|
|
|
9982
9989
|
}
|
|
9983
9990
|
],
|
|
9984
9991
|
"humidity-sensor": [{
|
|
9985
|
-
"path": "
|
|
9992
|
+
"path": "humidity",
|
|
9986
9993
|
"valueType": "number"
|
|
9987
9994
|
}],
|
|
9988
9995
|
"image": [{
|
|
@@ -10092,7 +10099,7 @@ Object.freeze({
|
|
|
10092
10099
|
"valueType": "number"
|
|
10093
10100
|
},
|
|
10094
10101
|
{
|
|
10095
|
-
"path": "
|
|
10102
|
+
"path": "progress",
|
|
10096
10103
|
"valueType": "number"
|
|
10097
10104
|
},
|
|
10098
10105
|
{
|
|
@@ -10171,11 +10178,11 @@ Object.freeze({
|
|
|
10171
10178
|
"valueType": "string"
|
|
10172
10179
|
},
|
|
10173
10180
|
{
|
|
10174
|
-
"path": "
|
|
10181
|
+
"path": "position",
|
|
10175
10182
|
"valueType": "number"
|
|
10176
10183
|
},
|
|
10177
10184
|
{
|
|
10178
|
-
"path": "
|
|
10185
|
+
"path": "duration",
|
|
10179
10186
|
"valueType": "number"
|
|
10180
10187
|
},
|
|
10181
10188
|
{
|
|
@@ -10277,11 +10284,11 @@ Object.freeze({
|
|
|
10277
10284
|
]
|
|
10278
10285
|
},
|
|
10279
10286
|
{
|
|
10280
|
-
"path": "
|
|
10287
|
+
"path": "signal",
|
|
10281
10288
|
"valueType": "number"
|
|
10282
10289
|
},
|
|
10283
10290
|
{
|
|
10284
|
-
"path": "
|
|
10291
|
+
"path": "rssi",
|
|
10285
10292
|
"valueType": "number"
|
|
10286
10293
|
},
|
|
10287
10294
|
{
|
|
@@ -10336,6 +10343,18 @@ Object.freeze({
|
|
|
10336
10343
|
"path": "foodLevel",
|
|
10337
10344
|
"valueType": "number"
|
|
10338
10345
|
},
|
|
10346
|
+
{
|
|
10347
|
+
"path": "bowlFood",
|
|
10348
|
+
"valueType": "number"
|
|
10349
|
+
},
|
|
10350
|
+
{
|
|
10351
|
+
"path": "eating",
|
|
10352
|
+
"valueType": "boolean"
|
|
10353
|
+
},
|
|
10354
|
+
{
|
|
10355
|
+
"path": "supportsMarkRefilled",
|
|
10356
|
+
"valueType": "boolean"
|
|
10357
|
+
},
|
|
10339
10358
|
{
|
|
10340
10359
|
"path": "food1",
|
|
10341
10360
|
"valueType": "number"
|
|
@@ -10400,23 +10419,23 @@ Object.freeze({
|
|
|
10400
10419
|
],
|
|
10401
10420
|
"power-meter": [
|
|
10402
10421
|
{
|
|
10403
|
-
"path": "
|
|
10422
|
+
"path": "power",
|
|
10404
10423
|
"valueType": "number"
|
|
10405
10424
|
},
|
|
10406
10425
|
{
|
|
10407
|
-
"path": "
|
|
10426
|
+
"path": "energy",
|
|
10408
10427
|
"valueType": "number"
|
|
10409
10428
|
},
|
|
10410
10429
|
{
|
|
10411
|
-
"path": "
|
|
10430
|
+
"path": "voltage",
|
|
10412
10431
|
"valueType": "number"
|
|
10413
10432
|
},
|
|
10414
10433
|
{
|
|
10415
|
-
"path": "
|
|
10434
|
+
"path": "current",
|
|
10416
10435
|
"valueType": "number"
|
|
10417
10436
|
},
|
|
10418
10437
|
{
|
|
10419
|
-
"path": "
|
|
10438
|
+
"path": "apparentPower",
|
|
10420
10439
|
"valueType": "number"
|
|
10421
10440
|
},
|
|
10422
10441
|
{
|
|
@@ -10444,14 +10463,10 @@ Object.freeze({
|
|
|
10444
10463
|
{
|
|
10445
10464
|
"path": "gps.accuracyMeters",
|
|
10446
10465
|
"valueType": "number"
|
|
10447
|
-
},
|
|
10448
|
-
{
|
|
10449
|
-
"path": "batteryPercent",
|
|
10450
|
-
"valueType": "number"
|
|
10451
10466
|
}
|
|
10452
10467
|
],
|
|
10453
10468
|
"pressure-sensor": [{
|
|
10454
|
-
"path": "
|
|
10469
|
+
"path": "pressure",
|
|
10455
10470
|
"valueType": "number"
|
|
10456
10471
|
}],
|
|
10457
10472
|
"privacy-mask": [{
|
|
@@ -10765,7 +10780,7 @@ Object.freeze({
|
|
|
10765
10780
|
"valueType": "boolean"
|
|
10766
10781
|
}],
|
|
10767
10782
|
"temperature-sensor": [{
|
|
10768
|
-
"path": "
|
|
10783
|
+
"path": "temperature",
|
|
10769
10784
|
"valueType": "number"
|
|
10770
10785
|
}],
|
|
10771
10786
|
"update": [
|
|
@@ -10813,7 +10828,7 @@ Object.freeze({
|
|
|
10813
10828
|
"valueType": "string"
|
|
10814
10829
|
},
|
|
10815
10830
|
{
|
|
10816
|
-
"path": "
|
|
10831
|
+
"path": "progress",
|
|
10817
10832
|
"valueType": "number"
|
|
10818
10833
|
},
|
|
10819
10834
|
{
|
|
@@ -11450,7 +11465,7 @@ function errMsg(err) {
|
|
|
11450
11465
|
return String(err);
|
|
11451
11466
|
}
|
|
11452
11467
|
//#endregion
|
|
11453
|
-
//#region ../types/dist/composition-
|
|
11468
|
+
//#region ../types/dist/composition-CZImLpOI.mjs
|
|
11454
11469
|
var AUDIO_ENCODER_BY_CODEC = {
|
|
11455
11470
|
opus: "libopus",
|
|
11456
11471
|
aac: "aac",
|
|
@@ -18162,6 +18177,14 @@ var AutomationConditionLeafSchema = object({
|
|
|
18162
18177
|
array(union$1([string(), number()]))
|
|
18163
18178
|
])
|
|
18164
18179
|
});
|
|
18180
|
+
var AutomationConditionStationaryPresentSchema = object({
|
|
18181
|
+
kind: literal("stationary-present"),
|
|
18182
|
+
deviceId: number().int().nonnegative(),
|
|
18183
|
+
/** Class names; a macro class matches every raw class that maps to it. */
|
|
18184
|
+
classes: array(string().min(1)).min(1).optional(),
|
|
18185
|
+
/** The parked object must be in at least one of these zones. */
|
|
18186
|
+
zones: array(string().min(1)).min(1).optional()
|
|
18187
|
+
});
|
|
18165
18188
|
/**
|
|
18166
18189
|
* The expression leaf, declared as a plain object rather than an intersection
|
|
18167
18190
|
* with {@link ExpressionSourceSchema}: a discriminated union has to be able to
|
|
@@ -18195,7 +18218,8 @@ var AutomationConditionSchema = lazy(() => discriminatedUnion("kind", [
|
|
|
18195
18218
|
child: AutomationConditionSchema
|
|
18196
18219
|
}),
|
|
18197
18220
|
AutomationConditionLeafSchema,
|
|
18198
|
-
AutomationConditionExpressionSchema
|
|
18221
|
+
AutomationConditionExpressionSchema,
|
|
18222
|
+
AutomationConditionStationaryPresentSchema
|
|
18199
18223
|
]));
|
|
18200
18224
|
/**
|
|
18201
18225
|
* What starts a run.
|
|
@@ -18236,7 +18260,34 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
18236
18260
|
kind: literal("schedule"),
|
|
18237
18261
|
cron: string().min(1).max(120)
|
|
18238
18262
|
}),
|
|
18239
|
-
object({ kind: literal("manual") })
|
|
18263
|
+
object({ kind: literal("manual") }),
|
|
18264
|
+
object({
|
|
18265
|
+
kind: literal("detection"),
|
|
18266
|
+
/** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
|
|
18267
|
+
* matches every raw class that maps to it; any other name matches
|
|
18268
|
+
* exactly. */
|
|
18269
|
+
classes: array(string().min(1)).min(1),
|
|
18270
|
+
deviceIds: array(number().int().nonnegative()).min(1),
|
|
18271
|
+
/** The track must have visited at least one of these zones. */
|
|
18272
|
+
zones: array(string().min(1)).min(1).optional(),
|
|
18273
|
+
/** Best-so-far confidence the track must reach. */
|
|
18274
|
+
minScore: number().min(0).max(1).optional()
|
|
18275
|
+
}),
|
|
18276
|
+
object({
|
|
18277
|
+
kind: literal("stationary"),
|
|
18278
|
+
deviceIds: array(number().int().nonnegative()).min(1),
|
|
18279
|
+
/** Class names; a macro class matches like the detection trigger. */
|
|
18280
|
+
classes: array(string().min(1)).min(1).optional(),
|
|
18281
|
+
/** The parked object must be in at least one of these zones. */
|
|
18282
|
+
zones: array(string().min(1)).min(1).optional(),
|
|
18283
|
+
/** `appeared`: it became parked. `departed`: the registry retired it.
|
|
18284
|
+
* The vocabulary of `PipelineAnalyticsStationaryChanged`. */
|
|
18285
|
+
phase: _enum(["appeared", "departed"])
|
|
18286
|
+
}),
|
|
18287
|
+
object({
|
|
18288
|
+
kind: literal("interval"),
|
|
18289
|
+
minutes: number().int().min(1).max(1440)
|
|
18290
|
+
})
|
|
18240
18291
|
]);
|
|
18241
18292
|
/**
|
|
18242
18293
|
* One action step.
|
|
@@ -18256,28 +18307,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
18256
18307
|
* is called. The runner still receives a number and is untouched; the
|
|
18257
18308
|
* resolution is the recipe's job, not the runner's.
|
|
18258
18309
|
*/
|
|
18310
|
+
var AutomationWaitStepSchema = object({
|
|
18311
|
+
kind: literal("wait"),
|
|
18312
|
+
seconds: number().min(0).max(300)
|
|
18313
|
+
});
|
|
18314
|
+
var AutomationCapStepSchema = object({
|
|
18315
|
+
kind: literal("cap"),
|
|
18316
|
+
/**
|
|
18317
|
+
* One device, several same-family devices (locks / climate family / …),
|
|
18318
|
+
* or `{ $var }` for the device that triggered the run. An array is
|
|
18319
|
+
* fan-out at codegen — each id gets the same cap.method call.
|
|
18320
|
+
*/
|
|
18321
|
+
deviceId: union$1([
|
|
18322
|
+
number().int(),
|
|
18323
|
+
array(number().int()).min(1),
|
|
18324
|
+
object({ $var: string().min(1) })
|
|
18325
|
+
]),
|
|
18326
|
+
cap: string().min(1),
|
|
18327
|
+
method: string().min(1),
|
|
18328
|
+
/** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
|
|
18329
|
+
* SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
|
|
18330
|
+
* the expression leaf. */
|
|
18331
|
+
args: record(string(), unknown()).optional()
|
|
18332
|
+
});
|
|
18333
|
+
/**
|
|
18334
|
+
* The steps an internal Action may contain: cap and wait, and nothing that can
|
|
18335
|
+
* call back into an Action — so an Action can never reach itself (no cycles).
|
|
18336
|
+
*/
|
|
18337
|
+
var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
|
|
18259
18338
|
var AutomationActionSchema = discriminatedUnion("kind", [
|
|
18339
|
+
AutomationWaitStepSchema,
|
|
18340
|
+
AutomationCapStepSchema,
|
|
18260
18341
|
object({
|
|
18261
|
-
kind: literal("
|
|
18262
|
-
|
|
18263
|
-
|
|
18264
|
-
|
|
18265
|
-
|
|
18266
|
-
|
|
18267
|
-
|
|
18268
|
-
|
|
18269
|
-
|
|
18270
|
-
*/
|
|
18271
|
-
deviceId: union$1([
|
|
18272
|
-
number().int(),
|
|
18273
|
-
array(number().int()).min(1),
|
|
18274
|
-
object({ $var: string().min(1) })
|
|
18275
|
-
]),
|
|
18276
|
-
cap: string().min(1),
|
|
18277
|
-
method: string().min(1),
|
|
18278
|
-
/** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
|
|
18279
|
-
* evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
|
|
18280
|
-
args: record(string(), unknown()).optional()
|
|
18342
|
+
kind: literal("action"),
|
|
18343
|
+
/** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
|
|
18344
|
+
actionId: string().min(1),
|
|
18345
|
+
/** Values for the action's declared variables; the others take their default. */
|
|
18346
|
+
variables: record(string(), union$1([
|
|
18347
|
+
string(),
|
|
18348
|
+
number(),
|
|
18349
|
+
boolean()
|
|
18350
|
+
])).optional()
|
|
18281
18351
|
}),
|
|
18282
18352
|
object({
|
|
18283
18353
|
kind: literal("code"),
|
|
@@ -18286,74 +18356,743 @@ var AutomationActionSchema = discriminatedUnion("kind", [
|
|
|
18286
18356
|
code: string().min(1).max(2e4)
|
|
18287
18357
|
})
|
|
18288
18358
|
]);
|
|
18359
|
+
/**
|
|
18360
|
+
* How a trigger that arrives while the automation is busy (or cooling down) is
|
|
18361
|
+
* handled. One of the automation's execution modes, never a property of its
|
|
18362
|
+
* actions. Absent means `single`.
|
|
18363
|
+
*
|
|
18364
|
+
* - `single` — drop the trigger while a run is in progress (traced + logged).
|
|
18365
|
+
* - `restart` — abort the run in progress (at its next step boundary), start fresh.
|
|
18366
|
+
* - `queued` — queue up to `max` triggers, drop the rest (traced).
|
|
18367
|
+
* - `parallel` — up to `max` runs at once, drop the rest (traced).
|
|
18368
|
+
* - `cooldown` — `single`, and no new run until `minutes` after the last run
|
|
18369
|
+
* STARTED; persisted across a restart. A manual trigger bypasses only this
|
|
18370
|
+
* wait, never the single/queued limits.
|
|
18371
|
+
*/
|
|
18372
|
+
var AutomationRunModeSchema = discriminatedUnion("mode", [
|
|
18373
|
+
object({ mode: literal("single") }),
|
|
18374
|
+
object({ mode: literal("restart") }),
|
|
18375
|
+
object({
|
|
18376
|
+
mode: literal("queued"),
|
|
18377
|
+
max: number().int().min(1).max(10)
|
|
18378
|
+
}),
|
|
18379
|
+
object({
|
|
18380
|
+
mode: literal("parallel"),
|
|
18381
|
+
max: number().int().min(1).max(10)
|
|
18382
|
+
}),
|
|
18383
|
+
object({
|
|
18384
|
+
mode: literal("cooldown"),
|
|
18385
|
+
minutes: number().int().min(1).max(1440)
|
|
18386
|
+
})
|
|
18387
|
+
]);
|
|
18289
18388
|
var AutomationRecipeSchema = object({
|
|
18290
18389
|
triggers: array(AutomationTriggerSchema),
|
|
18291
18390
|
conditions: AutomationConditionSchema.optional(),
|
|
18292
|
-
actions: array(AutomationActionSchema)
|
|
18391
|
+
actions: array(AutomationActionSchema),
|
|
18392
|
+
runMode: AutomationRunModeSchema.optional(),
|
|
18393
|
+
/** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
|
|
18394
|
+
keepTraces: number().int().min(1).max(100).optional()
|
|
18293
18395
|
});
|
|
18396
|
+
var COCO_80_LABELS = [
|
|
18397
|
+
{
|
|
18398
|
+
id: "person",
|
|
18399
|
+
name: "Person"
|
|
18400
|
+
},
|
|
18401
|
+
{
|
|
18402
|
+
id: "bicycle",
|
|
18403
|
+
name: "Bicycle"
|
|
18404
|
+
},
|
|
18405
|
+
{
|
|
18406
|
+
id: "car",
|
|
18407
|
+
name: "Car"
|
|
18408
|
+
},
|
|
18409
|
+
{
|
|
18410
|
+
id: "motorcycle",
|
|
18411
|
+
name: "Motorcycle"
|
|
18412
|
+
},
|
|
18413
|
+
{
|
|
18414
|
+
id: "airplane",
|
|
18415
|
+
name: "Airplane"
|
|
18416
|
+
},
|
|
18417
|
+
{
|
|
18418
|
+
id: "bus",
|
|
18419
|
+
name: "Bus"
|
|
18420
|
+
},
|
|
18421
|
+
{
|
|
18422
|
+
id: "train",
|
|
18423
|
+
name: "Train"
|
|
18424
|
+
},
|
|
18425
|
+
{
|
|
18426
|
+
id: "truck",
|
|
18427
|
+
name: "Truck"
|
|
18428
|
+
},
|
|
18429
|
+
{
|
|
18430
|
+
id: "boat",
|
|
18431
|
+
name: "Boat"
|
|
18432
|
+
},
|
|
18433
|
+
{
|
|
18434
|
+
id: "traffic light",
|
|
18435
|
+
name: "Traffic Light"
|
|
18436
|
+
},
|
|
18437
|
+
{
|
|
18438
|
+
id: "fire hydrant",
|
|
18439
|
+
name: "Fire Hydrant"
|
|
18440
|
+
},
|
|
18441
|
+
{
|
|
18442
|
+
id: "stop sign",
|
|
18443
|
+
name: "Stop Sign"
|
|
18444
|
+
},
|
|
18445
|
+
{
|
|
18446
|
+
id: "parking meter",
|
|
18447
|
+
name: "Parking Meter"
|
|
18448
|
+
},
|
|
18449
|
+
{
|
|
18450
|
+
id: "bench",
|
|
18451
|
+
name: "Bench"
|
|
18452
|
+
},
|
|
18453
|
+
{
|
|
18454
|
+
id: "bird",
|
|
18455
|
+
name: "Bird"
|
|
18456
|
+
},
|
|
18457
|
+
{
|
|
18458
|
+
id: "cat",
|
|
18459
|
+
name: "Cat"
|
|
18460
|
+
},
|
|
18461
|
+
{
|
|
18462
|
+
id: "dog",
|
|
18463
|
+
name: "Dog"
|
|
18464
|
+
},
|
|
18465
|
+
{
|
|
18466
|
+
id: "horse",
|
|
18467
|
+
name: "Horse"
|
|
18468
|
+
},
|
|
18469
|
+
{
|
|
18470
|
+
id: "sheep",
|
|
18471
|
+
name: "Sheep"
|
|
18472
|
+
},
|
|
18473
|
+
{
|
|
18474
|
+
id: "cow",
|
|
18475
|
+
name: "Cow"
|
|
18476
|
+
},
|
|
18477
|
+
{
|
|
18478
|
+
id: "elephant",
|
|
18479
|
+
name: "Elephant"
|
|
18480
|
+
},
|
|
18481
|
+
{
|
|
18482
|
+
id: "bear",
|
|
18483
|
+
name: "Bear"
|
|
18484
|
+
},
|
|
18485
|
+
{
|
|
18486
|
+
id: "zebra",
|
|
18487
|
+
name: "Zebra"
|
|
18488
|
+
},
|
|
18489
|
+
{
|
|
18490
|
+
id: "giraffe",
|
|
18491
|
+
name: "Giraffe"
|
|
18492
|
+
},
|
|
18493
|
+
{
|
|
18494
|
+
id: "backpack",
|
|
18495
|
+
name: "Backpack"
|
|
18496
|
+
},
|
|
18497
|
+
{
|
|
18498
|
+
id: "umbrella",
|
|
18499
|
+
name: "Umbrella"
|
|
18500
|
+
},
|
|
18501
|
+
{
|
|
18502
|
+
id: "handbag",
|
|
18503
|
+
name: "Handbag"
|
|
18504
|
+
},
|
|
18505
|
+
{
|
|
18506
|
+
id: "tie",
|
|
18507
|
+
name: "Tie"
|
|
18508
|
+
},
|
|
18509
|
+
{
|
|
18510
|
+
id: "suitcase",
|
|
18511
|
+
name: "Suitcase"
|
|
18512
|
+
},
|
|
18513
|
+
{
|
|
18514
|
+
id: "frisbee",
|
|
18515
|
+
name: "Frisbee"
|
|
18516
|
+
},
|
|
18517
|
+
{
|
|
18518
|
+
id: "skis",
|
|
18519
|
+
name: "Skis"
|
|
18520
|
+
},
|
|
18521
|
+
{
|
|
18522
|
+
id: "snowboard",
|
|
18523
|
+
name: "Snowboard"
|
|
18524
|
+
},
|
|
18525
|
+
{
|
|
18526
|
+
id: "sports ball",
|
|
18527
|
+
name: "Sports Ball"
|
|
18528
|
+
},
|
|
18529
|
+
{
|
|
18530
|
+
id: "kite",
|
|
18531
|
+
name: "Kite"
|
|
18532
|
+
},
|
|
18533
|
+
{
|
|
18534
|
+
id: "baseball bat",
|
|
18535
|
+
name: "Baseball Bat"
|
|
18536
|
+
},
|
|
18537
|
+
{
|
|
18538
|
+
id: "baseball glove",
|
|
18539
|
+
name: "Baseball Glove"
|
|
18540
|
+
},
|
|
18541
|
+
{
|
|
18542
|
+
id: "skateboard",
|
|
18543
|
+
name: "Skateboard"
|
|
18544
|
+
},
|
|
18545
|
+
{
|
|
18546
|
+
id: "surfboard",
|
|
18547
|
+
name: "Surfboard"
|
|
18548
|
+
},
|
|
18549
|
+
{
|
|
18550
|
+
id: "tennis racket",
|
|
18551
|
+
name: "Tennis Racket"
|
|
18552
|
+
},
|
|
18553
|
+
{
|
|
18554
|
+
id: "bottle",
|
|
18555
|
+
name: "Bottle"
|
|
18556
|
+
},
|
|
18557
|
+
{
|
|
18558
|
+
id: "wine glass",
|
|
18559
|
+
name: "Wine Glass"
|
|
18560
|
+
},
|
|
18561
|
+
{
|
|
18562
|
+
id: "cup",
|
|
18563
|
+
name: "Cup"
|
|
18564
|
+
},
|
|
18565
|
+
{
|
|
18566
|
+
id: "fork",
|
|
18567
|
+
name: "Fork"
|
|
18568
|
+
},
|
|
18569
|
+
{
|
|
18570
|
+
id: "knife",
|
|
18571
|
+
name: "Knife"
|
|
18572
|
+
},
|
|
18573
|
+
{
|
|
18574
|
+
id: "spoon",
|
|
18575
|
+
name: "Spoon"
|
|
18576
|
+
},
|
|
18577
|
+
{
|
|
18578
|
+
id: "bowl",
|
|
18579
|
+
name: "Bowl"
|
|
18580
|
+
},
|
|
18581
|
+
{
|
|
18582
|
+
id: "banana",
|
|
18583
|
+
name: "Banana"
|
|
18584
|
+
},
|
|
18585
|
+
{
|
|
18586
|
+
id: "apple",
|
|
18587
|
+
name: "Apple"
|
|
18588
|
+
},
|
|
18589
|
+
{
|
|
18590
|
+
id: "sandwich",
|
|
18591
|
+
name: "Sandwich"
|
|
18592
|
+
},
|
|
18593
|
+
{
|
|
18594
|
+
id: "orange",
|
|
18595
|
+
name: "Orange"
|
|
18596
|
+
},
|
|
18597
|
+
{
|
|
18598
|
+
id: "broccoli",
|
|
18599
|
+
name: "Broccoli"
|
|
18600
|
+
},
|
|
18601
|
+
{
|
|
18602
|
+
id: "carrot",
|
|
18603
|
+
name: "Carrot"
|
|
18604
|
+
},
|
|
18605
|
+
{
|
|
18606
|
+
id: "hot dog",
|
|
18607
|
+
name: "Hot Dog"
|
|
18608
|
+
},
|
|
18609
|
+
{
|
|
18610
|
+
id: "pizza",
|
|
18611
|
+
name: "Pizza"
|
|
18612
|
+
},
|
|
18613
|
+
{
|
|
18614
|
+
id: "donut",
|
|
18615
|
+
name: "Donut"
|
|
18616
|
+
},
|
|
18617
|
+
{
|
|
18618
|
+
id: "cake",
|
|
18619
|
+
name: "Cake"
|
|
18620
|
+
},
|
|
18621
|
+
{
|
|
18622
|
+
id: "chair",
|
|
18623
|
+
name: "Chair"
|
|
18624
|
+
},
|
|
18625
|
+
{
|
|
18626
|
+
id: "couch",
|
|
18627
|
+
name: "Couch"
|
|
18628
|
+
},
|
|
18629
|
+
{
|
|
18630
|
+
id: "potted plant",
|
|
18631
|
+
name: "Potted Plant"
|
|
18632
|
+
},
|
|
18633
|
+
{
|
|
18634
|
+
id: "bed",
|
|
18635
|
+
name: "Bed"
|
|
18636
|
+
},
|
|
18637
|
+
{
|
|
18638
|
+
id: "dining table",
|
|
18639
|
+
name: "Dining Table"
|
|
18640
|
+
},
|
|
18641
|
+
{
|
|
18642
|
+
id: "toilet",
|
|
18643
|
+
name: "Toilet"
|
|
18644
|
+
},
|
|
18645
|
+
{
|
|
18646
|
+
id: "tv",
|
|
18647
|
+
name: "TV"
|
|
18648
|
+
},
|
|
18649
|
+
{
|
|
18650
|
+
id: "laptop",
|
|
18651
|
+
name: "Laptop"
|
|
18652
|
+
},
|
|
18653
|
+
{
|
|
18654
|
+
id: "mouse",
|
|
18655
|
+
name: "Mouse"
|
|
18656
|
+
},
|
|
18657
|
+
{
|
|
18658
|
+
id: "remote",
|
|
18659
|
+
name: "Remote"
|
|
18660
|
+
},
|
|
18661
|
+
{
|
|
18662
|
+
id: "keyboard",
|
|
18663
|
+
name: "Keyboard"
|
|
18664
|
+
},
|
|
18665
|
+
{
|
|
18666
|
+
id: "cell phone",
|
|
18667
|
+
name: "Cell Phone"
|
|
18668
|
+
},
|
|
18669
|
+
{
|
|
18670
|
+
id: "microwave",
|
|
18671
|
+
name: "Microwave"
|
|
18672
|
+
},
|
|
18673
|
+
{
|
|
18674
|
+
id: "oven",
|
|
18675
|
+
name: "Oven"
|
|
18676
|
+
},
|
|
18677
|
+
{
|
|
18678
|
+
id: "toaster",
|
|
18679
|
+
name: "Toaster"
|
|
18680
|
+
},
|
|
18681
|
+
{
|
|
18682
|
+
id: "sink",
|
|
18683
|
+
name: "Sink"
|
|
18684
|
+
},
|
|
18685
|
+
{
|
|
18686
|
+
id: "refrigerator",
|
|
18687
|
+
name: "Refrigerator"
|
|
18688
|
+
},
|
|
18689
|
+
{
|
|
18690
|
+
id: "book",
|
|
18691
|
+
name: "Book"
|
|
18692
|
+
},
|
|
18693
|
+
{
|
|
18694
|
+
id: "clock",
|
|
18695
|
+
name: "Clock"
|
|
18696
|
+
},
|
|
18697
|
+
{
|
|
18698
|
+
id: "vase",
|
|
18699
|
+
name: "Vase"
|
|
18700
|
+
},
|
|
18701
|
+
{
|
|
18702
|
+
id: "scissors",
|
|
18703
|
+
name: "Scissors"
|
|
18704
|
+
},
|
|
18705
|
+
{
|
|
18706
|
+
id: "teddy bear",
|
|
18707
|
+
name: "Teddy Bear"
|
|
18708
|
+
},
|
|
18709
|
+
{
|
|
18710
|
+
id: "hair drier",
|
|
18711
|
+
name: "Hair Drier"
|
|
18712
|
+
},
|
|
18713
|
+
{
|
|
18714
|
+
id: "toothbrush",
|
|
18715
|
+
name: "Toothbrush"
|
|
18716
|
+
}
|
|
18717
|
+
];
|
|
18718
|
+
new Set([
|
|
18719
|
+
{
|
|
18720
|
+
id: "person",
|
|
18721
|
+
name: "Person"
|
|
18722
|
+
},
|
|
18723
|
+
{
|
|
18724
|
+
id: "vehicle",
|
|
18725
|
+
name: "Vehicle"
|
|
18726
|
+
},
|
|
18727
|
+
{
|
|
18728
|
+
id: "animal",
|
|
18729
|
+
name: "Animal"
|
|
18730
|
+
},
|
|
18731
|
+
{
|
|
18732
|
+
id: "package",
|
|
18733
|
+
name: "Package"
|
|
18734
|
+
}
|
|
18735
|
+
].map((l) => l.id));
|
|
18736
|
+
var COCO_TO_MACRO = {
|
|
18737
|
+
mapping: {
|
|
18738
|
+
person: "person",
|
|
18739
|
+
bicycle: "vehicle",
|
|
18740
|
+
car: "vehicle",
|
|
18741
|
+
motorcycle: "vehicle",
|
|
18742
|
+
airplane: "vehicle",
|
|
18743
|
+
bus: "vehicle",
|
|
18744
|
+
train: "vehicle",
|
|
18745
|
+
truck: "vehicle",
|
|
18746
|
+
boat: "vehicle",
|
|
18747
|
+
bird: "animal",
|
|
18748
|
+
cat: "animal",
|
|
18749
|
+
dog: "animal",
|
|
18750
|
+
horse: "animal",
|
|
18751
|
+
sheep: "animal",
|
|
18752
|
+
cow: "animal",
|
|
18753
|
+
elephant: "animal",
|
|
18754
|
+
bear: "animal",
|
|
18755
|
+
zebra: "animal",
|
|
18756
|
+
giraffe: "animal",
|
|
18757
|
+
suitcase: "package",
|
|
18758
|
+
backpack: "package",
|
|
18759
|
+
handbag: "package"
|
|
18760
|
+
},
|
|
18761
|
+
preserveOriginal: false
|
|
18762
|
+
};
|
|
18763
|
+
new Set(Object.values(COCO_TO_MACRO.mapping));
|
|
18294
18764
|
/**
|
|
18295
|
-
*
|
|
18296
|
-
*
|
|
18765
|
+
* Run traces — what an automation (or, later, an Action run) DID, node by node,
|
|
18766
|
+
* so the editor can paint every block green or red with its reason.
|
|
18297
18767
|
*
|
|
18298
|
-
*
|
|
18299
|
-
*
|
|
18300
|
-
*
|
|
18301
|
-
*
|
|
18302
|
-
*
|
|
18768
|
+
* A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
|
|
18769
|
+
* every condition node (containers and leaves, including the ones a
|
|
18770
|
+
* short-circuit never reached), the run-mode verdict and every action step —
|
|
18771
|
+
* each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
|
|
18772
|
+
* for an Action run). Skipped
|
|
18773
|
+
* evaluations are traced too, and identical consecutive skips collapse into a
|
|
18774
|
+
* repeat count so a trigger that fails every 5 minutes cannot flush real runs.
|
|
18303
18775
|
*
|
|
18304
|
-
*
|
|
18305
|
-
*
|
|
18306
|
-
* provider. Splitting the public aggregator from the raw collection
|
|
18307
|
-
* keeps both ends in codegen — there's no hand-written
|
|
18308
|
-
* `addon-pages.router.ts` wrapper anymore.
|
|
18776
|
+
* {@link AutomationStepTraceSchema} is deliberately free of automation
|
|
18777
|
+
* vocabulary so an Action run records the same step shape.
|
|
18309
18778
|
*/
|
|
18310
|
-
|
|
18311
|
-
|
|
18312
|
-
|
|
18313
|
-
|
|
18314
|
-
|
|
18315
|
-
|
|
18316
|
-
|
|
18317
|
-
|
|
18318
|
-
|
|
18779
|
+
/** A value a trace may show: JSON primitives and short lists, nothing deeper. */
|
|
18780
|
+
var TraceValueSchema = union$1([
|
|
18781
|
+
string(),
|
|
18782
|
+
number(),
|
|
18783
|
+
boolean(),
|
|
18784
|
+
_null(),
|
|
18785
|
+
array(union$1([string(), number()]))
|
|
18786
|
+
]);
|
|
18787
|
+
var AutomationRunOutcomeSchema = _enum([
|
|
18788
|
+
"ran",
|
|
18789
|
+
"skipped-trigger",
|
|
18790
|
+
"skipped-conditions",
|
|
18791
|
+
"skipped-cooldown",
|
|
18792
|
+
"skipped-overlap",
|
|
18793
|
+
"failed",
|
|
18794
|
+
"aborted"
|
|
18795
|
+
]);
|
|
18796
|
+
/** `not-evaluated` = a short-circuit never reached the node. */
|
|
18797
|
+
var TraceNodeOutcomeSchema = _enum([
|
|
18798
|
+
"pass",
|
|
18799
|
+
"fail",
|
|
18800
|
+
"not-evaluated"
|
|
18801
|
+
]);
|
|
18802
|
+
var AutomationTriggerTraceSchema = object({
|
|
18803
|
+
kind: string().min(1),
|
|
18804
|
+
outcome: _enum(["pass", "fail"]),
|
|
18805
|
+
/** Why an event was rejected ("class person not in [dog]") or what fired. */
|
|
18806
|
+
reason: string(),
|
|
18807
|
+
/** deviceId, className, trackId, score … — only what the trigger exposes. */
|
|
18808
|
+
vars: record(string(), TraceValueSchema)
|
|
18319
18809
|
});
|
|
18320
|
-
var
|
|
18321
|
-
|
|
18322
|
-
|
|
18323
|
-
|
|
18810
|
+
var AutomationConditionTraceNodeSchema = object({
|
|
18811
|
+
/** `conditions` for the root, `conditions.<i>` for its i-th child, … */
|
|
18812
|
+
path: string().min(1),
|
|
18813
|
+
kind: _enum([
|
|
18814
|
+
"all",
|
|
18815
|
+
"any",
|
|
18816
|
+
"not",
|
|
18817
|
+
"condition",
|
|
18818
|
+
"expression",
|
|
18819
|
+
"stationary-present"
|
|
18820
|
+
]),
|
|
18821
|
+
outcome: TraceNodeOutcomeSchema,
|
|
18822
|
+
reason: string(),
|
|
18823
|
+
deviceId: number().int().optional(),
|
|
18824
|
+
cap: string().optional(),
|
|
18825
|
+
fieldPath: string().optional(),
|
|
18826
|
+
operator: string().optional(),
|
|
18827
|
+
expected: TraceValueSchema.optional(),
|
|
18828
|
+
/** What the mirror held; `null` when it held nothing (unknown). */
|
|
18829
|
+
observed: TraceValueSchema.optional()
|
|
18830
|
+
});
|
|
18831
|
+
var AutomationRunVerdictSchema = object({
|
|
18832
|
+
mode: AutomationRunModeSchema,
|
|
18833
|
+
decision: _enum([
|
|
18834
|
+
"run",
|
|
18835
|
+
"queued",
|
|
18836
|
+
"restart",
|
|
18837
|
+
"drop",
|
|
18838
|
+
"cooldown",
|
|
18839
|
+
"bypass"
|
|
18840
|
+
]),
|
|
18841
|
+
reason: string()
|
|
18842
|
+
});
|
|
18843
|
+
/** One executed (or not-run) step — shared by automations and Action runs. */
|
|
18844
|
+
var AutomationStepTraceSchema = object({
|
|
18845
|
+
/** `actions.<i>` */
|
|
18846
|
+
path: string().min(1),
|
|
18847
|
+
kind: string().min(1),
|
|
18848
|
+
cap: string().optional(),
|
|
18849
|
+
method: string().optional(),
|
|
18850
|
+
deviceId: number().int().optional(),
|
|
18851
|
+
startedAt: number().optional(),
|
|
18852
|
+
endedAt: number().optional(),
|
|
18853
|
+
outcome: _enum([
|
|
18854
|
+
"ok",
|
|
18855
|
+
"error",
|
|
18856
|
+
"not-run"
|
|
18857
|
+
]),
|
|
18858
|
+
message: string().optional()
|
|
18859
|
+
});
|
|
18860
|
+
var AutomationRunTraceSchema = object({
|
|
18861
|
+
runId: string().min(1),
|
|
18862
|
+
startedAt: number(),
|
|
18863
|
+
endedAt: number(),
|
|
18864
|
+
trigger: AutomationTriggerTraceSchema,
|
|
18865
|
+
conditions: array(AutomationConditionTraceNodeSchema),
|
|
18866
|
+
verdict: AutomationRunVerdictSchema.optional(),
|
|
18867
|
+
steps: array(AutomationStepTraceSchema),
|
|
18868
|
+
outcome: AutomationRunOutcomeSchema,
|
|
18869
|
+
/** How many identical consecutive skips this trace stands for (>= 1). */
|
|
18870
|
+
repeat: number().int().min(1),
|
|
18871
|
+
/** When the latest of those repeats happened. */
|
|
18872
|
+
lastAt: number()
|
|
18324
18873
|
});
|
|
18325
|
-
method(_void(), array(AddonPageInfoSchema).readonly());
|
|
18326
18874
|
/**
|
|
18327
|
-
* `
|
|
18328
|
-
*
|
|
18329
|
-
|
|
18330
|
-
|
|
18331
|
-
|
|
18332
|
-
|
|
18875
|
+
* What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
|
|
18876
|
+
* `action:<actionId>`): the cooldown stamp and the trace ring.
|
|
18877
|
+
*/
|
|
18878
|
+
var AutomationStateDocSchema = object({
|
|
18879
|
+
version: literal(1),
|
|
18880
|
+
lastRunStartedAt: number().nullable(),
|
|
18881
|
+
traces: array(AutomationRunTraceSchema)
|
|
18882
|
+
});
|
|
18883
|
+
/**
|
|
18884
|
+
* Actions — named, runnable things an operator (or an automation) can start,
|
|
18885
|
+
* declared as LIST ENTRIES, never as devices.
|
|
18333
18886
|
*
|
|
18334
|
-
*
|
|
18335
|
-
*
|
|
18336
|
-
*
|
|
18887
|
+
* An entry is either **internal** (a short list of cap/wait steps kept in the
|
|
18888
|
+
* hub's `actions` record kind) or declared by an addon through the
|
|
18889
|
+
* `action-source` collection (a Home Assistant script, a scene …). The one
|
|
18890
|
+
* surface the UI and automations talk to is the `actions` cap; it keeps no
|
|
18891
|
+
* catalog of its own (D3) — every `list` asks the providers live.
|
|
18892
|
+
*
|
|
18893
|
+
* This file is the data half: the entry schema, the variables an entry may
|
|
18894
|
+
* declare, and the pure resolution of the values a run was given. It holds no
|
|
18895
|
+
* runtime.
|
|
18337
18896
|
*/
|
|
18338
|
-
|
|
18339
|
-
|
|
18340
|
-
|
|
18341
|
-
|
|
18342
|
-
|
|
18343
|
-
|
|
18344
|
-
|
|
18345
|
-
|
|
18346
|
-
|
|
18347
|
-
|
|
18348
|
-
|
|
18349
|
-
|
|
18350
|
-
|
|
18351
|
-
|
|
18352
|
-
|
|
18353
|
-
|
|
18354
|
-
|
|
18355
|
-
|
|
18356
|
-
|
|
18897
|
+
/** What a variable's value is. `select` takes one of `options`. */
|
|
18898
|
+
var ActionVariableTypeSchema = _enum([
|
|
18899
|
+
"string",
|
|
18900
|
+
"number",
|
|
18901
|
+
"boolean",
|
|
18902
|
+
"select"
|
|
18903
|
+
]);
|
|
18904
|
+
var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
18905
|
+
var ActionVariableValueSchema = union$1([
|
|
18906
|
+
string(),
|
|
18907
|
+
number(),
|
|
18908
|
+
boolean()
|
|
18909
|
+
]);
|
|
18910
|
+
/**
|
|
18911
|
+
* One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
|
|
18912
|
+
* value) or `{{vars.name}}` (inside a string) in their args.
|
|
18913
|
+
*/
|
|
18914
|
+
var ActionVariableSchema = object({
|
|
18915
|
+
name: string().regex(ACTION_VARIABLE_NAME_RE),
|
|
18916
|
+
label: string().min(1).max(120).optional(),
|
|
18917
|
+
type: ActionVariableTypeSchema,
|
|
18918
|
+
required: boolean().optional(),
|
|
18919
|
+
default: ActionVariableValueSchema.optional(),
|
|
18920
|
+
/** The allowed values of a `select`. */
|
|
18921
|
+
options: array(string().min(1)).min(1).optional()
|
|
18922
|
+
}).superRefine((v, ctx) => {
|
|
18923
|
+
if (v.type === "select" && v.options === void 0) ctx.addIssue({
|
|
18924
|
+
code: "custom",
|
|
18925
|
+
message: "a select variable needs options",
|
|
18926
|
+
path: ["options"]
|
|
18927
|
+
});
|
|
18928
|
+
if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
|
|
18929
|
+
code: "custom",
|
|
18930
|
+
message: variableValueError(v, v.default) ?? "invalid default",
|
|
18931
|
+
path: ["default"]
|
|
18932
|
+
});
|
|
18933
|
+
});
|
|
18934
|
+
/** Why `value` is not a legal value for the variable, or null when it is. */
|
|
18935
|
+
function variableValueError(variable, value) {
|
|
18936
|
+
switch (variable.type) {
|
|
18937
|
+
case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
|
|
18938
|
+
case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
|
|
18939
|
+
case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
|
|
18940
|
+
case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
|
|
18941
|
+
}
|
|
18942
|
+
}
|
|
18943
|
+
var ActionSourceKindSchema = _enum(["internal", "addon"]);
|
|
18944
|
+
function isInternalActionId(actionId) {
|
|
18945
|
+
return actionId.startsWith("internal:") && actionId.length > 9;
|
|
18946
|
+
}
|
|
18947
|
+
/** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
|
|
18948
|
+
function addonIdOfActionId(actionId) {
|
|
18949
|
+
if (isInternalActionId(actionId)) return null;
|
|
18950
|
+
const at = actionId.indexOf(":");
|
|
18951
|
+
return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
|
|
18952
|
+
}
|
|
18953
|
+
var ActionStatusSchema = object({
|
|
18954
|
+
isRunning: boolean(),
|
|
18955
|
+
/** Ms epoch the latest run STARTED; null when it never ran. */
|
|
18956
|
+
lastRunAt: number().nullable(),
|
|
18957
|
+
/** The latest run's failure; null on success or when it never ran. */
|
|
18958
|
+
lastError: string().nullable()
|
|
18959
|
+
});
|
|
18960
|
+
var ActionEntrySchema = object({
|
|
18961
|
+
/** `internal:<uuid>` or `<addonId>:<localId>`. */
|
|
18962
|
+
id: string().min(3),
|
|
18963
|
+
name: string().min(1).max(120),
|
|
18964
|
+
/** The addon that declared it; `core-blocks` for an internal one. */
|
|
18965
|
+
addonId: string().min(1),
|
|
18966
|
+
source: ActionSourceKindSchema,
|
|
18967
|
+
/** An addon-declared entry is edited where it was declared. */
|
|
18968
|
+
readOnly: boolean(),
|
|
18969
|
+
/** Internal only: cap and wait steps. No action-in-action, so no cycles. */
|
|
18970
|
+
steps: array(ActionStepSchema).min(1).max(50).optional(),
|
|
18971
|
+
variables: array(ActionVariableSchema).max(20).optional(),
|
|
18972
|
+
status: ActionStatusSchema
|
|
18973
|
+
}).superRefine((entry, ctx) => {
|
|
18974
|
+
if (entry.source === "internal") {
|
|
18975
|
+
if (!isInternalActionId(entry.id)) ctx.addIssue({
|
|
18976
|
+
code: "custom",
|
|
18977
|
+
message: "an internal action id is internal:<uuid>",
|
|
18978
|
+
path: ["id"]
|
|
18979
|
+
});
|
|
18980
|
+
return;
|
|
18981
|
+
}
|
|
18982
|
+
if (entry.steps !== void 0) ctx.addIssue({
|
|
18983
|
+
code: "custom",
|
|
18984
|
+
message: "only an internal action carries steps",
|
|
18985
|
+
path: ["steps"]
|
|
18986
|
+
});
|
|
18987
|
+
if (!entry.readOnly) ctx.addIssue({
|
|
18988
|
+
code: "custom",
|
|
18989
|
+
message: "an addon action is read-only here",
|
|
18990
|
+
path: ["readOnly"]
|
|
18991
|
+
});
|
|
18992
|
+
if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
|
|
18993
|
+
code: "custom",
|
|
18994
|
+
message: "an addon action id is <addonId>:<localId>",
|
|
18995
|
+
path: ["id"]
|
|
18996
|
+
});
|
|
18997
|
+
});
|
|
18998
|
+
/** What an operator writes for an internal action. */
|
|
18999
|
+
var ActionInputSchema = object({
|
|
19000
|
+
name: string().min(1).max(120),
|
|
19001
|
+
steps: array(ActionStepSchema).min(1).max(50),
|
|
19002
|
+
variables: array(ActionVariableSchema).max(20).optional()
|
|
19003
|
+
});
|
|
19004
|
+
/** Who started a run. Absent = the operator pressed it. */
|
|
19005
|
+
var ActionRunOriginSchema = object({
|
|
19006
|
+
/** The automation block whose step started it. */
|
|
19007
|
+
blockId: string().min(1).optional() });
|
|
19008
|
+
/** `started` = the caller did not ask to wait. */
|
|
19009
|
+
var ActionRunOutcomeSchema = union$1([AutomationRunOutcomeSchema, literal("started")]);
|
|
19010
|
+
var ActionRunResultSchema = object({
|
|
19011
|
+
runId: string().min(1),
|
|
19012
|
+
outcome: ActionRunOutcomeSchema,
|
|
19013
|
+
/** Why it did not run, or what failed. */
|
|
19014
|
+
message: string().optional()
|
|
19015
|
+
});
|
|
19016
|
+
_enum([
|
|
19017
|
+
"not-found",
|
|
19018
|
+
"read-only",
|
|
19019
|
+
"invalid-variables",
|
|
19020
|
+
"invalid-steps",
|
|
19021
|
+
"not-linked",
|
|
19022
|
+
"busy"
|
|
19023
|
+
]);
|
|
19024
|
+
object({
|
|
19025
|
+
actionId: string(),
|
|
19026
|
+
runId: string(),
|
|
19027
|
+
isRunning: boolean(),
|
|
19028
|
+
/** Set when the run ended. */
|
|
19029
|
+
outcome: AutomationRunOutcomeSchema.optional(),
|
|
19030
|
+
lastRunAt: number().nullable(),
|
|
19031
|
+
lastError: string().nullable()
|
|
19032
|
+
});
|
|
19033
|
+
/**
|
|
19034
|
+
* `addon-pages` — system-scoped singleton aggregator cap. Public-facing
|
|
19035
|
+
* surface that admin-ui consumes through `useAddonPagesListPages()`.
|
|
19036
|
+
*
|
|
19037
|
+
* The provider iterates every `addon-pages-source` (collection) provider
|
|
19038
|
+
* and emits `AddonPageInfo[]` enriched with versioned `bundleUrl` strings
|
|
19039
|
+
* pointing at `/api/addon-pages/<addonId>/<bundle>?v=<mtime>`. The
|
|
19040
|
+
* filesystem `mtime` cache-buster lets the browser pick up addon
|
|
19041
|
+
* rebuilds without manual reload.
|
|
19042
|
+
*
|
|
19043
|
+
* The hub-local builtin `addon-pages-aggregator` (see
|
|
19044
|
+
* `@camstack/system/builtins/addon-pages-aggregator`) registers the
|
|
19045
|
+
* provider. Splitting the public aggregator from the raw collection
|
|
19046
|
+
* keeps both ends in codegen — there's no hand-written
|
|
19047
|
+
* `addon-pages.router.ts` wrapper anymore.
|
|
19048
|
+
*/
|
|
19049
|
+
var AddonPageDeclarationSchema$1 = object({
|
|
19050
|
+
id: string(),
|
|
19051
|
+
label: string(),
|
|
19052
|
+
icon: string(),
|
|
19053
|
+
path: string(),
|
|
19054
|
+
remoteName: string(),
|
|
19055
|
+
bundle: string(),
|
|
19056
|
+
section: string().optional(),
|
|
19057
|
+
sectionLabel: string().optional()
|
|
19058
|
+
});
|
|
19059
|
+
var AddonPageInfoSchema = object({
|
|
19060
|
+
addonId: string(),
|
|
19061
|
+
page: AddonPageDeclarationSchema$1,
|
|
19062
|
+
bundleUrl: string()
|
|
19063
|
+
});
|
|
19064
|
+
method(_void(), array(AddonPageInfoSchema).readonly());
|
|
19065
|
+
/**
|
|
19066
|
+
* `addon-pages-source` — collection cap exposing per-provider raw page
|
|
19067
|
+
* declarations. Every addon that contributes a UI page registers a
|
|
19068
|
+
* provider here. The hub-side singleton aggregator (`addon-pages` cap,
|
|
19069
|
+
* see `addon-pages.cap.ts`) walks this collection, stamps versioned
|
|
19070
|
+
* `bundleUrl` values, and returns the enriched `AddonPageInfo[]` list
|
|
19071
|
+
* that admin-ui consumes.
|
|
19072
|
+
*
|
|
19073
|
+
* The split exists because the public listing has a different output
|
|
19074
|
+
* shape than the per-provider raw declarations, and we want both ends
|
|
19075
|
+
* to flow through codegen instead of relying on a hand-written wrapper.
|
|
19076
|
+
*/
|
|
19077
|
+
var AddonPageDeclarationSchema = object({
|
|
19078
|
+
id: string(),
|
|
19079
|
+
label: string(),
|
|
19080
|
+
icon: string(),
|
|
19081
|
+
path: string(),
|
|
19082
|
+
/**
|
|
19083
|
+
* Module Federation remote name — must match the `name` field on the
|
|
19084
|
+
* page addon's `federation()` plugin config. Used by admin-ui's
|
|
19085
|
+
* `<AddonPageLoader>` to call `loadRemote('<remoteName>/page')`.
|
|
19086
|
+
* Conventionally `addon_<id>_page` (snake_case; MF names cannot
|
|
19087
|
+
* contain hyphens).
|
|
19088
|
+
*/
|
|
19089
|
+
remoteName: string(),
|
|
19090
|
+
/**
|
|
19091
|
+
* Bundle filename inside the addon's `dist/` dir served at
|
|
19092
|
+
* `/api/addon-pages/<addonId>/<bundle>`. With Module Federation this
|
|
19093
|
+
* is always `'remoteEntry.js'`; the value is kept on the metadata so
|
|
19094
|
+
* the static-file route can compute an mtime-based cache-buster URL
|
|
19095
|
+
* without a separate filesystem stat.
|
|
18357
19096
|
*/
|
|
18358
19097
|
bundle: string(),
|
|
18359
19098
|
/**
|
|
@@ -21342,7 +22081,7 @@ var CompositionEventPlanSchema = object({
|
|
|
21342
22081
|
stateField: string(),
|
|
21343
22082
|
fieldKey: string()
|
|
21344
22083
|
});
|
|
21345
|
-
/** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.
|
|
22084
|
+
/** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.temperature`. */
|
|
21346
22085
|
var CompositionProblemSchema = object({
|
|
21347
22086
|
code: _enum([
|
|
21348
22087
|
"reserved-variant",
|
|
@@ -21661,7 +22400,7 @@ var GROUP_TEMPLATES = [
|
|
|
21661
22400
|
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
21662
22401
|
role: DeviceRole.TemperatureSensor,
|
|
21663
22402
|
outputCap: "temperature-sensor",
|
|
21664
|
-
outputField: "
|
|
22403
|
+
outputField: "temperature",
|
|
21665
22404
|
quantity: "temperature",
|
|
21666
22405
|
defaultAggregate: "mean",
|
|
21667
22406
|
empty: "null",
|
|
@@ -21672,7 +22411,7 @@ var GROUP_TEMPLATES = [
|
|
|
21672
22411
|
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
21673
22412
|
role: DeviceRole.HumiditySensor,
|
|
21674
22413
|
outputCap: "humidity-sensor",
|
|
21675
|
-
outputField: "
|
|
22414
|
+
outputField: "humidity",
|
|
21676
22415
|
quantity: "humidity",
|
|
21677
22416
|
defaultAggregate: "mean",
|
|
21678
22417
|
empty: "null",
|
|
@@ -21683,7 +22422,7 @@ var GROUP_TEMPLATES = [
|
|
|
21683
22422
|
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
21684
22423
|
role: DeviceRole.PressureSensor,
|
|
21685
22424
|
outputCap: "pressure-sensor",
|
|
21686
|
-
outputField: "
|
|
22425
|
+
outputField: "pressure",
|
|
21687
22426
|
quantity: "pressure",
|
|
21688
22427
|
defaultAggregate: "mean",
|
|
21689
22428
|
empty: "null",
|
|
@@ -21694,7 +22433,7 @@ var GROUP_TEMPLATES = [
|
|
|
21694
22433
|
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
21695
22434
|
role: DeviceRole.AmbientLightSensor,
|
|
21696
22435
|
outputCap: "ambient-light-sensor",
|
|
21697
|
-
outputField: "
|
|
22436
|
+
outputField: "illuminance",
|
|
21698
22437
|
quantity: "illuminance",
|
|
21699
22438
|
defaultAggregate: "mean",
|
|
21700
22439
|
empty: "null",
|
|
@@ -21705,7 +22444,7 @@ var GROUP_TEMPLATES = [
|
|
|
21705
22444
|
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
21706
22445
|
role: DeviceRole.PowerSensor,
|
|
21707
22446
|
outputCap: "power-meter",
|
|
21708
|
-
outputField: "
|
|
22447
|
+
outputField: "power",
|
|
21709
22448
|
quantity: "power",
|
|
21710
22449
|
defaultAggregate: "sum",
|
|
21711
22450
|
empty: "omit",
|
|
@@ -21716,7 +22455,7 @@ var GROUP_TEMPLATES = [
|
|
|
21716
22455
|
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
21717
22456
|
role: DeviceRole.EnergySensor,
|
|
21718
22457
|
outputCap: "power-meter",
|
|
21719
|
-
outputField: "
|
|
22458
|
+
outputField: "energy",
|
|
21720
22459
|
quantity: "energy",
|
|
21721
22460
|
defaultAggregate: "sum",
|
|
21722
22461
|
empty: "omit",
|
|
@@ -21727,7 +22466,7 @@ var GROUP_TEMPLATES = [
|
|
|
21727
22466
|
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
21728
22467
|
role: DeviceRole.BatterySensor,
|
|
21729
22468
|
outputCap: "battery",
|
|
21730
|
-
outputField: "
|
|
22469
|
+
outputField: "level",
|
|
21731
22470
|
quantity: "percentage",
|
|
21732
22471
|
defaultAggregate: "mean",
|
|
21733
22472
|
empty: "null",
|
|
@@ -22305,7 +23044,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
|
|
|
22305
23044
|
kind: "mutation",
|
|
22306
23045
|
auth: "admin",
|
|
22307
23046
|
access: "view"
|
|
22308
|
-
})
|
|
23047
|
+
}), method(object({
|
|
23048
|
+
blockId: string().min(1),
|
|
23049
|
+
trace: AutomationRunTraceSchema.optional(),
|
|
23050
|
+
runStartedAt: number().optional(),
|
|
23051
|
+
keepTraces: number().int().min(1).max(100).optional()
|
|
23052
|
+
}), _void(), {
|
|
23053
|
+
kind: "mutation",
|
|
23054
|
+
auth: "admin"
|
|
23055
|
+
}), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
|
|
23056
|
+
traces: array(AutomationRunTraceSchema),
|
|
23057
|
+
lastError: string().nullable()
|
|
23058
|
+
}), { auth: "admin" });
|
|
22309
23059
|
/**
|
|
22310
23060
|
* `custom-model-registry` — collection cap exposing operator-registered
|
|
22311
23061
|
* custom detection models. Each provider (today: `addon-model-studio`)
|
|
@@ -47158,732 +47908,365 @@ method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _v
|
|
|
47158
47908
|
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
47159
47909
|
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
47160
47910
|
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
47161
|
-
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
47162
|
-
* alternative would fork the UI per addon and cannot host the
|
|
47163
|
-
* discovery→adopt flow.
|
|
47164
|
-
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
47165
|
-
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
47166
|
-
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
47167
|
-
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
47168
|
-
* `addonId` the generated collection router extracts from the call input.
|
|
47169
|
-
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
47170
|
-
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
47171
|
-
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
47172
|
-
* base64 fallback needed.
|
|
47173
|
-
*
|
|
47174
|
-
* TODO (deferred, closed-set change — separate decision): add
|
|
47175
|
-
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
47176
|
-
* admin "Integrations" page.
|
|
47177
|
-
*/
|
|
47178
|
-
/**
|
|
47179
|
-
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
47180
|
-
* adapter picks what it supports and the degrade engine filters the rest.
|
|
47181
|
-
*/
|
|
47182
|
-
var AttachmentMediaTypeSchema = _enum([
|
|
47183
|
-
"image",
|
|
47184
|
-
"video",
|
|
47185
|
-
"gif",
|
|
47186
|
-
"audio",
|
|
47187
|
-
"icon"
|
|
47188
|
-
]);
|
|
47189
|
-
/**
|
|
47190
|
-
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
47191
|
-
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
47192
|
-
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
47193
|
-
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
47194
|
-
*/
|
|
47195
|
-
var AttachmentSchema = object({
|
|
47196
|
-
mediaType: AttachmentMediaTypeSchema,
|
|
47197
|
-
url: string().optional(),
|
|
47198
|
-
bytes: _instanceof(Uint8Array).optional(),
|
|
47199
|
-
mime: string().optional(),
|
|
47200
|
-
name: string().optional()
|
|
47201
|
-
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
47202
|
-
var NotificationFormatSchema = _enum([
|
|
47203
|
-
"text",
|
|
47204
|
-
"markdown",
|
|
47205
|
-
"html"
|
|
47206
|
-
]);
|
|
47207
|
-
/**
|
|
47208
|
-
* The CLOSED icon vocabulary an action button may use.
|
|
47209
|
-
*
|
|
47210
|
-
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
47211
|
-
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
47212
|
-
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
47213
|
-
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
47214
|
-
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
47215
|
-
*
|
|
47216
|
-
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
47217
|
-
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
47218
|
-
* differently.
|
|
47219
|
-
*
|
|
47220
|
-
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
47221
|
-
*
|
|
47222
|
-
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
47223
|
-
* the whole set onto its own renderer's vocabulary through a
|
|
47224
|
-
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
47225
|
-
* fallback, so adding a member here fails every adapter's build until someone
|
|
47226
|
-
* decides its glyph, which is the only place that decision can be made
|
|
47227
|
-
* honestly.
|
|
47228
|
-
*
|
|
47229
|
-
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
47230
|
-
* `disarm` straight through; iOS feeds that string to
|
|
47231
|
-
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
47232
|
-
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
47233
|
-
* mapping, and "the field is documented" is not "the value renders".
|
|
47234
|
-
*
|
|
47235
|
-
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
47236
|
-
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
47237
|
-
* so an addon that emits a token the running hub does not know does not lose an
|
|
47238
|
-
* icon — its whole `send` fails Zod validation and the notification never
|
|
47239
|
-
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
47240
|
-
*/
|
|
47241
|
-
var NotificationActionIconSchema = _enum([
|
|
47242
|
-
"acknowledge",
|
|
47243
|
-
"dismiss",
|
|
47244
|
-
"silence",
|
|
47245
|
-
"snooze",
|
|
47246
|
-
"view",
|
|
47247
|
-
"play",
|
|
47248
|
-
"open",
|
|
47249
|
-
"close",
|
|
47250
|
-
"lock",
|
|
47251
|
-
"unlock",
|
|
47252
|
-
"arm",
|
|
47253
|
-
"arm-home",
|
|
47254
|
-
"arm-away",
|
|
47255
|
-
"arm-night",
|
|
47256
|
-
"disarm",
|
|
47257
|
-
"light",
|
|
47258
|
-
"alert",
|
|
47259
|
-
"camera"
|
|
47260
|
-
]);
|
|
47261
|
-
/** A single tap-through action button. */
|
|
47262
|
-
var NotificationActionSchema = object({
|
|
47263
|
-
id: string(),
|
|
47264
|
-
label: string(),
|
|
47265
|
-
url: string().optional(),
|
|
47266
|
-
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
47267
|
-
icon: NotificationActionIconSchema.optional(),
|
|
47268
|
-
/**
|
|
47269
|
-
* Renders in a warning style where the notifier supports it.
|
|
47270
|
-
*
|
|
47271
|
-
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
47272
|
-
* else — see `notification-center/action-token.ts` for what that does and
|
|
47273
|
-
* does not buy.
|
|
47274
|
-
*/
|
|
47275
|
-
destructive: boolean().optional(),
|
|
47276
|
-
/**
|
|
47277
|
-
* How the tap should REACH the url.
|
|
47278
|
-
*
|
|
47279
|
-
* `navigate` (absent, and every button authored before this field) opens it:
|
|
47280
|
-
* the phone leaves the notification and shows whatever the callback returns.
|
|
47281
|
-
* That is right for a button whose answer the operator wants to read.
|
|
47282
|
-
*
|
|
47283
|
-
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
47284
|
-
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
47285
|
-
* an answer to the notification, and being thrown into a browser tab to
|
|
47286
|
-
* confirm it costs more attention than the notification did. A backend that
|
|
47287
|
-
* cannot do a background call renders it as an ordinary link (the adapters
|
|
47288
|
-
* fall back rather than dropping the button), so this is a preference, never
|
|
47289
|
-
* a requirement.
|
|
47290
|
-
*/
|
|
47291
|
-
mode: _enum(["navigate", "background"]).optional()
|
|
47292
|
-
});
|
|
47293
|
-
/**
|
|
47294
|
-
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
47295
|
-
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
47296
|
-
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
47297
|
-
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
47298
|
-
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
47299
|
-
* `priority` for that one target.
|
|
47300
|
-
*/
|
|
47301
|
-
var NotificationSchema = object({
|
|
47302
|
-
body: string(),
|
|
47303
|
-
title: string().optional(),
|
|
47304
|
-
format: NotificationFormatSchema.default("text"),
|
|
47305
|
-
priority: number().int().min(1).max(5).default(3),
|
|
47306
|
-
level: string().optional(),
|
|
47307
|
-
attachments: array(AttachmentSchema).optional(),
|
|
47308
|
-
clickUrl: string().optional(),
|
|
47309
|
-
actions: array(NotificationActionSchema).optional(),
|
|
47310
|
-
sound: string().optional(),
|
|
47311
|
-
ttl: number().optional(),
|
|
47312
|
-
tag: string().optional(),
|
|
47313
|
-
deviceId: number().optional(),
|
|
47314
|
-
eventId: string().optional(),
|
|
47315
|
-
metadata: record(string(), unknown()).optional()
|
|
47316
|
-
});
|
|
47317
|
-
/** One declared native severity/priority level for a kind. */
|
|
47318
|
-
var TargetKindLevelSchema = object({
|
|
47319
|
-
id: string(),
|
|
47320
|
-
label: string(),
|
|
47321
|
-
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
47322
|
-
ordinal: number().int().min(1).max(5).nullable(),
|
|
47323
|
-
flags: object({
|
|
47324
|
-
critical: boolean().optional(),
|
|
47325
|
-
silent: boolean().optional(),
|
|
47326
|
-
noPush: boolean().optional()
|
|
47327
|
-
}).optional(),
|
|
47328
|
-
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
47329
|
-
requires: array(string()).optional(),
|
|
47330
|
-
description: string().optional()
|
|
47331
|
-
});
|
|
47332
|
-
/** The full capability block consulted before dispatch. */
|
|
47333
|
-
var TargetKindCapsSchema = object({
|
|
47334
|
-
attachments: object({
|
|
47335
|
-
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
47336
|
-
mode: _enum([
|
|
47337
|
-
"url",
|
|
47338
|
-
"bytes",
|
|
47339
|
-
"both"
|
|
47340
|
-
]),
|
|
47341
|
-
max: number().int().nonnegative(),
|
|
47342
|
-
maxBytes: number().int().positive().optional()
|
|
47343
|
-
}),
|
|
47344
|
-
/** Max action buttons (0 = none). */
|
|
47345
|
-
actions: number().int().nonnegative(),
|
|
47346
|
-
/**
|
|
47347
|
-
* Whether this kind renders a per-action ICON.
|
|
47348
|
-
*
|
|
47349
|
-
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
47350
|
-
* run on the addon cap path — three production failures in one day taught
|
|
47351
|
-
* this repo that once. Absent is read as false by the degrade engine, which
|
|
47352
|
-
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
47353
|
-
* assumed and dropped costs the operator's trust in the field.
|
|
47354
|
-
*/
|
|
47355
|
-
actionIcons: boolean().optional(),
|
|
47356
|
-
levels: array(TargetKindLevelSchema),
|
|
47357
|
-
format: array(NotificationFormatSchema),
|
|
47358
|
-
clickUrl: boolean(),
|
|
47359
|
-
sound: boolean(),
|
|
47360
|
-
ttl: boolean(),
|
|
47361
|
-
bodyMaxLen: number().int().positive()
|
|
47362
|
-
});
|
|
47363
|
-
/**
|
|
47364
|
-
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
47365
|
-
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
47366
|
-
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
47367
|
-
* the union is large and not meant for runtime validation here; the exported
|
|
47368
|
-
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
47369
|
-
*/
|
|
47370
|
-
var ConfigSchemaPassthrough$2 = unknown();
|
|
47371
|
-
var TargetKindSchema = object({
|
|
47372
|
-
kind: string(),
|
|
47373
|
-
label: string(),
|
|
47374
|
-
icon: string(),
|
|
47375
|
-
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
47376
|
-
addonId: string(),
|
|
47377
|
-
/**
|
|
47378
|
-
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
47379
|
-
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
47380
|
-
* when the addon bundles no icon for that kind — the client then falls back
|
|
47381
|
-
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
47382
|
-
*
|
|
47383
|
-
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
47384
|
-
* client, and a native client joins it onto its own hub base.
|
|
47385
|
-
*
|
|
47386
|
-
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
47387
|
-
* field that survived only because the runtime cap-router forwards provider
|
|
47388
|
-
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
47389
|
-
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
47390
|
-
* broken silently the moment output validation was tightened anywhere.
|
|
47391
|
-
*/
|
|
47392
|
-
iconUrl: string().optional(),
|
|
47393
|
-
/**
|
|
47394
|
-
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
47395
|
-
*
|
|
47396
|
-
* The server knows this and therefore says it, because the client cannot
|
|
47397
|
-
* safely guess: a React-Native client renders SVG and raster through two
|
|
47398
|
-
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
47399
|
-
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
47400
|
-
* placeholder glyph for every vector icon while the web build looked fine.
|
|
47401
|
-
*
|
|
47402
|
-
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
47403
|
-
* not been updated — a client that cannot determine the type should prefer
|
|
47404
|
-
* its raster path, which is the safe default for an unknown image.
|
|
47405
|
-
*/
|
|
47406
|
-
iconMediaType: string().optional(),
|
|
47407
|
-
configSchema: ConfigSchemaPassthrough$2,
|
|
47408
|
-
/**
|
|
47409
|
-
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
47410
|
-
* base URL, instance, chat, recipient). A save that changes any of them
|
|
47411
|
-
* while leaving a secret redacted is refused by the provider (D634), so an
|
|
47412
|
-
* editor uses this to ask for the secret on exactly those edits instead of
|
|
47413
|
-
* on every edit.
|
|
47414
|
-
*
|
|
47415
|
-
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
47416
|
-
* kinds) and from a provider older than this field — an editor that finds
|
|
47417
|
-
* it absent must assume ANY edit may need the secret.
|
|
47418
|
-
*/
|
|
47419
|
-
destinationKeys: array(string()).optional(),
|
|
47420
|
-
supportsDiscovery: boolean(),
|
|
47421
|
-
caps: TargetKindCapsSchema
|
|
47422
|
-
});
|
|
47423
|
-
/**
|
|
47424
|
-
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
47425
|
-
* (return a presence marker only) when serving `listTargets` — never
|
|
47426
|
-
* round-trip a stored secret to the UI.
|
|
47427
|
-
*/
|
|
47428
|
-
var TargetSchema = object({
|
|
47429
|
-
id: string(),
|
|
47430
|
-
name: string(),
|
|
47431
|
-
kind: string(),
|
|
47432
|
-
addonId: string(),
|
|
47433
|
-
enabled: boolean(),
|
|
47434
|
-
config: record(string(), unknown())
|
|
47435
|
-
});
|
|
47436
|
-
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
47437
|
-
var DiscoveredTargetSchema = object({
|
|
47438
|
-
kind: string(),
|
|
47439
|
-
suggestedName: string(),
|
|
47440
|
-
config: record(string(), unknown())
|
|
47441
|
-
});
|
|
47442
|
-
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
47443
|
-
var RenderedAsSchema = object({
|
|
47444
|
-
level: string(),
|
|
47445
|
-
format: NotificationFormatSchema,
|
|
47446
|
-
attachmentsSent: number().int().nonnegative(),
|
|
47447
|
-
actionsSent: number().int().nonnegative(),
|
|
47448
|
-
truncated: boolean(),
|
|
47449
|
-
dropped: array(string())
|
|
47450
|
-
});
|
|
47451
|
-
var SendResultSchema = object({
|
|
47452
|
-
success: boolean(),
|
|
47453
|
-
error: string().optional(),
|
|
47454
|
-
renderedAs: RenderedAsSchema.optional()
|
|
47455
|
-
});
|
|
47456
|
-
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
47457
|
-
var TestResultSchema = SendResultSchema;
|
|
47458
|
-
/**
|
|
47459
|
-
* Pre-save credential probe against a partial (unsaved) target config.
|
|
47460
|
-
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
47461
|
-
*/
|
|
47462
|
-
var ProbeTargetConfigResultSchema = object({
|
|
47463
|
-
ok: boolean(),
|
|
47464
|
-
resolvedUrl: string(),
|
|
47465
|
-
httpStatus: number().int().optional(),
|
|
47466
|
-
stateInstance: string().optional(),
|
|
47467
|
-
error: string().optional()
|
|
47468
|
-
});
|
|
47469
|
-
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema), { auth: "admin" }), method(object({ targetId: string() }), TargetSchema, { auth: "admin" }), method(object({
|
|
47470
|
-
kind: string(),
|
|
47471
|
-
config: record(string(), unknown()).optional(),
|
|
47472
|
-
/**
|
|
47473
|
-
* When editing / duplicating, the blank password field never round-trips
|
|
47474
|
-
* the stored token. Pass the source target id so the provider can restore
|
|
47475
|
-
* secrets server-side before dialling (same merge as upsert).
|
|
47476
|
-
*/
|
|
47477
|
-
targetId: string().optional()
|
|
47478
|
-
}), array(DiscoveredTargetSchema), { auth: "admin" }), method(object({
|
|
47479
|
-
kind: string(),
|
|
47480
|
-
config: record(string(), unknown()),
|
|
47481
|
-
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
47482
|
-
targetId: string().optional()
|
|
47483
|
-
}), ProbeTargetConfigResultSchema, {
|
|
47484
|
-
kind: "mutation",
|
|
47485
|
-
auth: "admin"
|
|
47486
|
-
}), method(object({
|
|
47487
|
-
targetId: string(),
|
|
47488
|
-
notification: NotificationSchema
|
|
47489
|
-
}), SendResultSchema, {
|
|
47490
|
-
kind: "mutation",
|
|
47491
|
-
auth: "admin"
|
|
47492
|
-
}), method(object({
|
|
47493
|
-
targetId: string(),
|
|
47494
|
-
sample: NotificationSchema.optional()
|
|
47495
|
-
}), TestResultSchema, {
|
|
47496
|
-
kind: "mutation",
|
|
47497
|
-
auth: "admin"
|
|
47498
|
-
}), method(object({
|
|
47499
|
-
target: TargetSchema,
|
|
47500
|
-
/**
|
|
47501
|
-
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
47502
|
-
* existing row. The UI never holds the stored token; blank / redacted
|
|
47503
|
-
* password fields are restored from this source (D634 still applies if
|
|
47504
|
-
* destinations diverge without a re-typed secret).
|
|
47505
|
-
*/
|
|
47506
|
-
cloneSecretsFrom: string().optional()
|
|
47507
|
-
}), TargetSchema, {
|
|
47508
|
-
kind: "mutation",
|
|
47509
|
-
auth: "admin"
|
|
47510
|
-
}), method(object({ targetId: string() }), _void(), {
|
|
47511
|
-
kind: "mutation",
|
|
47512
|
-
auth: "admin"
|
|
47513
|
-
}), method(object({
|
|
47514
|
-
targetId: string(),
|
|
47515
|
-
enabled: boolean()
|
|
47516
|
-
}), _void(), {
|
|
47517
|
-
kind: "mutation",
|
|
47518
|
-
auth: "admin"
|
|
47519
|
-
});
|
|
47520
|
-
var COCO_80_LABELS = [
|
|
47521
|
-
{
|
|
47522
|
-
id: "person",
|
|
47523
|
-
name: "Person"
|
|
47524
|
-
},
|
|
47525
|
-
{
|
|
47526
|
-
id: "bicycle",
|
|
47527
|
-
name: "Bicycle"
|
|
47528
|
-
},
|
|
47529
|
-
{
|
|
47530
|
-
id: "car",
|
|
47531
|
-
name: "Car"
|
|
47532
|
-
},
|
|
47533
|
-
{
|
|
47534
|
-
id: "motorcycle",
|
|
47535
|
-
name: "Motorcycle"
|
|
47536
|
-
},
|
|
47537
|
-
{
|
|
47538
|
-
id: "airplane",
|
|
47539
|
-
name: "Airplane"
|
|
47540
|
-
},
|
|
47541
|
-
{
|
|
47542
|
-
id: "bus",
|
|
47543
|
-
name: "Bus"
|
|
47544
|
-
},
|
|
47545
|
-
{
|
|
47546
|
-
id: "train",
|
|
47547
|
-
name: "Train"
|
|
47548
|
-
},
|
|
47549
|
-
{
|
|
47550
|
-
id: "truck",
|
|
47551
|
-
name: "Truck"
|
|
47552
|
-
},
|
|
47553
|
-
{
|
|
47554
|
-
id: "boat",
|
|
47555
|
-
name: "Boat"
|
|
47556
|
-
},
|
|
47557
|
-
{
|
|
47558
|
-
id: "traffic light",
|
|
47559
|
-
name: "Traffic Light"
|
|
47560
|
-
},
|
|
47561
|
-
{
|
|
47562
|
-
id: "fire hydrant",
|
|
47563
|
-
name: "Fire Hydrant"
|
|
47564
|
-
},
|
|
47565
|
-
{
|
|
47566
|
-
id: "stop sign",
|
|
47567
|
-
name: "Stop Sign"
|
|
47568
|
-
},
|
|
47569
|
-
{
|
|
47570
|
-
id: "parking meter",
|
|
47571
|
-
name: "Parking Meter"
|
|
47572
|
-
},
|
|
47573
|
-
{
|
|
47574
|
-
id: "bench",
|
|
47575
|
-
name: "Bench"
|
|
47576
|
-
},
|
|
47577
|
-
{
|
|
47578
|
-
id: "bird",
|
|
47579
|
-
name: "Bird"
|
|
47580
|
-
},
|
|
47581
|
-
{
|
|
47582
|
-
id: "cat",
|
|
47583
|
-
name: "Cat"
|
|
47584
|
-
},
|
|
47585
|
-
{
|
|
47586
|
-
id: "dog",
|
|
47587
|
-
name: "Dog"
|
|
47588
|
-
},
|
|
47589
|
-
{
|
|
47590
|
-
id: "horse",
|
|
47591
|
-
name: "Horse"
|
|
47592
|
-
},
|
|
47593
|
-
{
|
|
47594
|
-
id: "sheep",
|
|
47595
|
-
name: "Sheep"
|
|
47596
|
-
},
|
|
47597
|
-
{
|
|
47598
|
-
id: "cow",
|
|
47599
|
-
name: "Cow"
|
|
47600
|
-
},
|
|
47601
|
-
{
|
|
47602
|
-
id: "elephant",
|
|
47603
|
-
name: "Elephant"
|
|
47604
|
-
},
|
|
47605
|
-
{
|
|
47606
|
-
id: "bear",
|
|
47607
|
-
name: "Bear"
|
|
47608
|
-
},
|
|
47609
|
-
{
|
|
47610
|
-
id: "zebra",
|
|
47611
|
-
name: "Zebra"
|
|
47612
|
-
},
|
|
47613
|
-
{
|
|
47614
|
-
id: "giraffe",
|
|
47615
|
-
name: "Giraffe"
|
|
47616
|
-
},
|
|
47617
|
-
{
|
|
47618
|
-
id: "backpack",
|
|
47619
|
-
name: "Backpack"
|
|
47620
|
-
},
|
|
47621
|
-
{
|
|
47622
|
-
id: "umbrella",
|
|
47623
|
-
name: "Umbrella"
|
|
47624
|
-
},
|
|
47625
|
-
{
|
|
47626
|
-
id: "handbag",
|
|
47627
|
-
name: "Handbag"
|
|
47628
|
-
},
|
|
47629
|
-
{
|
|
47630
|
-
id: "tie",
|
|
47631
|
-
name: "Tie"
|
|
47632
|
-
},
|
|
47633
|
-
{
|
|
47634
|
-
id: "suitcase",
|
|
47635
|
-
name: "Suitcase"
|
|
47636
|
-
},
|
|
47637
|
-
{
|
|
47638
|
-
id: "frisbee",
|
|
47639
|
-
name: "Frisbee"
|
|
47640
|
-
},
|
|
47641
|
-
{
|
|
47642
|
-
id: "skis",
|
|
47643
|
-
name: "Skis"
|
|
47644
|
-
},
|
|
47645
|
-
{
|
|
47646
|
-
id: "snowboard",
|
|
47647
|
-
name: "Snowboard"
|
|
47648
|
-
},
|
|
47649
|
-
{
|
|
47650
|
-
id: "sports ball",
|
|
47651
|
-
name: "Sports Ball"
|
|
47652
|
-
},
|
|
47653
|
-
{
|
|
47654
|
-
id: "kite",
|
|
47655
|
-
name: "Kite"
|
|
47656
|
-
},
|
|
47657
|
-
{
|
|
47658
|
-
id: "baseball bat",
|
|
47659
|
-
name: "Baseball Bat"
|
|
47660
|
-
},
|
|
47661
|
-
{
|
|
47662
|
-
id: "baseball glove",
|
|
47663
|
-
name: "Baseball Glove"
|
|
47664
|
-
},
|
|
47665
|
-
{
|
|
47666
|
-
id: "skateboard",
|
|
47667
|
-
name: "Skateboard"
|
|
47668
|
-
},
|
|
47669
|
-
{
|
|
47670
|
-
id: "surfboard",
|
|
47671
|
-
name: "Surfboard"
|
|
47672
|
-
},
|
|
47673
|
-
{
|
|
47674
|
-
id: "tennis racket",
|
|
47675
|
-
name: "Tennis Racket"
|
|
47676
|
-
},
|
|
47677
|
-
{
|
|
47678
|
-
id: "bottle",
|
|
47679
|
-
name: "Bottle"
|
|
47680
|
-
},
|
|
47681
|
-
{
|
|
47682
|
-
id: "wine glass",
|
|
47683
|
-
name: "Wine Glass"
|
|
47684
|
-
},
|
|
47685
|
-
{
|
|
47686
|
-
id: "cup",
|
|
47687
|
-
name: "Cup"
|
|
47688
|
-
},
|
|
47689
|
-
{
|
|
47690
|
-
id: "fork",
|
|
47691
|
-
name: "Fork"
|
|
47692
|
-
},
|
|
47693
|
-
{
|
|
47694
|
-
id: "knife",
|
|
47695
|
-
name: "Knife"
|
|
47696
|
-
},
|
|
47697
|
-
{
|
|
47698
|
-
id: "spoon",
|
|
47699
|
-
name: "Spoon"
|
|
47700
|
-
},
|
|
47701
|
-
{
|
|
47702
|
-
id: "bowl",
|
|
47703
|
-
name: "Bowl"
|
|
47704
|
-
},
|
|
47705
|
-
{
|
|
47706
|
-
id: "banana",
|
|
47707
|
-
name: "Banana"
|
|
47708
|
-
},
|
|
47709
|
-
{
|
|
47710
|
-
id: "apple",
|
|
47711
|
-
name: "Apple"
|
|
47712
|
-
},
|
|
47713
|
-
{
|
|
47714
|
-
id: "sandwich",
|
|
47715
|
-
name: "Sandwich"
|
|
47716
|
-
},
|
|
47717
|
-
{
|
|
47718
|
-
id: "orange",
|
|
47719
|
-
name: "Orange"
|
|
47720
|
-
},
|
|
47721
|
-
{
|
|
47722
|
-
id: "broccoli",
|
|
47723
|
-
name: "Broccoli"
|
|
47724
|
-
},
|
|
47725
|
-
{
|
|
47726
|
-
id: "carrot",
|
|
47727
|
-
name: "Carrot"
|
|
47728
|
-
},
|
|
47729
|
-
{
|
|
47730
|
-
id: "hot dog",
|
|
47731
|
-
name: "Hot Dog"
|
|
47732
|
-
},
|
|
47733
|
-
{
|
|
47734
|
-
id: "pizza",
|
|
47735
|
-
name: "Pizza"
|
|
47736
|
-
},
|
|
47737
|
-
{
|
|
47738
|
-
id: "donut",
|
|
47739
|
-
name: "Donut"
|
|
47740
|
-
},
|
|
47741
|
-
{
|
|
47742
|
-
id: "cake",
|
|
47743
|
-
name: "Cake"
|
|
47744
|
-
},
|
|
47745
|
-
{
|
|
47746
|
-
id: "chair",
|
|
47747
|
-
name: "Chair"
|
|
47748
|
-
},
|
|
47749
|
-
{
|
|
47750
|
-
id: "couch",
|
|
47751
|
-
name: "Couch"
|
|
47752
|
-
},
|
|
47753
|
-
{
|
|
47754
|
-
id: "potted plant",
|
|
47755
|
-
name: "Potted Plant"
|
|
47756
|
-
},
|
|
47757
|
-
{
|
|
47758
|
-
id: "bed",
|
|
47759
|
-
name: "Bed"
|
|
47760
|
-
},
|
|
47761
|
-
{
|
|
47762
|
-
id: "dining table",
|
|
47763
|
-
name: "Dining Table"
|
|
47764
|
-
},
|
|
47765
|
-
{
|
|
47766
|
-
id: "toilet",
|
|
47767
|
-
name: "Toilet"
|
|
47768
|
-
},
|
|
47769
|
-
{
|
|
47770
|
-
id: "tv",
|
|
47771
|
-
name: "TV"
|
|
47772
|
-
},
|
|
47773
|
-
{
|
|
47774
|
-
id: "laptop",
|
|
47775
|
-
name: "Laptop"
|
|
47776
|
-
},
|
|
47777
|
-
{
|
|
47778
|
-
id: "mouse",
|
|
47779
|
-
name: "Mouse"
|
|
47780
|
-
},
|
|
47781
|
-
{
|
|
47782
|
-
id: "remote",
|
|
47783
|
-
name: "Remote"
|
|
47784
|
-
},
|
|
47785
|
-
{
|
|
47786
|
-
id: "keyboard",
|
|
47787
|
-
name: "Keyboard"
|
|
47788
|
-
},
|
|
47789
|
-
{
|
|
47790
|
-
id: "cell phone",
|
|
47791
|
-
name: "Cell Phone"
|
|
47792
|
-
},
|
|
47793
|
-
{
|
|
47794
|
-
id: "microwave",
|
|
47795
|
-
name: "Microwave"
|
|
47796
|
-
},
|
|
47797
|
-
{
|
|
47798
|
-
id: "oven",
|
|
47799
|
-
name: "Oven"
|
|
47800
|
-
},
|
|
47801
|
-
{
|
|
47802
|
-
id: "toaster",
|
|
47803
|
-
name: "Toaster"
|
|
47804
|
-
},
|
|
47805
|
-
{
|
|
47806
|
-
id: "sink",
|
|
47807
|
-
name: "Sink"
|
|
47808
|
-
},
|
|
47809
|
-
{
|
|
47810
|
-
id: "refrigerator",
|
|
47811
|
-
name: "Refrigerator"
|
|
47812
|
-
},
|
|
47813
|
-
{
|
|
47814
|
-
id: "book",
|
|
47815
|
-
name: "Book"
|
|
47816
|
-
},
|
|
47817
|
-
{
|
|
47818
|
-
id: "clock",
|
|
47819
|
-
name: "Clock"
|
|
47820
|
-
},
|
|
47821
|
-
{
|
|
47822
|
-
id: "vase",
|
|
47823
|
-
name: "Vase"
|
|
47824
|
-
},
|
|
47825
|
-
{
|
|
47826
|
-
id: "scissors",
|
|
47827
|
-
name: "Scissors"
|
|
47828
|
-
},
|
|
47829
|
-
{
|
|
47830
|
-
id: "teddy bear",
|
|
47831
|
-
name: "Teddy Bear"
|
|
47832
|
-
},
|
|
47833
|
-
{
|
|
47834
|
-
id: "hair drier",
|
|
47835
|
-
name: "Hair Drier"
|
|
47836
|
-
},
|
|
47837
|
-
{
|
|
47838
|
-
id: "toothbrush",
|
|
47839
|
-
name: "Toothbrush"
|
|
47840
|
-
}
|
|
47841
|
-
];
|
|
47842
|
-
new Set([
|
|
47843
|
-
{
|
|
47844
|
-
id: "person",
|
|
47845
|
-
name: "Person"
|
|
47846
|
-
},
|
|
47847
|
-
{
|
|
47848
|
-
id: "vehicle",
|
|
47849
|
-
name: "Vehicle"
|
|
47850
|
-
},
|
|
47851
|
-
{
|
|
47852
|
-
id: "animal",
|
|
47853
|
-
name: "Animal"
|
|
47854
|
-
},
|
|
47855
|
-
{
|
|
47856
|
-
id: "package",
|
|
47857
|
-
name: "Package"
|
|
47858
|
-
}
|
|
47859
|
-
].map((l) => l.id));
|
|
47860
|
-
var COCO_TO_MACRO = {
|
|
47861
|
-
mapping: {
|
|
47862
|
-
person: "person",
|
|
47863
|
-
bicycle: "vehicle",
|
|
47864
|
-
car: "vehicle",
|
|
47865
|
-
motorcycle: "vehicle",
|
|
47866
|
-
airplane: "vehicle",
|
|
47867
|
-
bus: "vehicle",
|
|
47868
|
-
train: "vehicle",
|
|
47869
|
-
truck: "vehicle",
|
|
47870
|
-
boat: "vehicle",
|
|
47871
|
-
bird: "animal",
|
|
47872
|
-
cat: "animal",
|
|
47873
|
-
dog: "animal",
|
|
47874
|
-
horse: "animal",
|
|
47875
|
-
sheep: "animal",
|
|
47876
|
-
cow: "animal",
|
|
47877
|
-
elephant: "animal",
|
|
47878
|
-
bear: "animal",
|
|
47879
|
-
zebra: "animal",
|
|
47880
|
-
giraffe: "animal",
|
|
47881
|
-
suitcase: "package",
|
|
47882
|
-
backpack: "package",
|
|
47883
|
-
handbag: "package"
|
|
47884
|
-
},
|
|
47885
|
-
preserveOriginal: false
|
|
47886
|
-
};
|
|
47911
|
+
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
47912
|
+
* alternative would fork the UI per addon and cannot host the
|
|
47913
|
+
* discovery→adopt flow.
|
|
47914
|
+
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
47915
|
+
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
47916
|
+
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
47917
|
+
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
47918
|
+
* `addonId` the generated collection router extracts from the call input.
|
|
47919
|
+
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
47920
|
+
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
47921
|
+
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
47922
|
+
* base64 fallback needed.
|
|
47923
|
+
*
|
|
47924
|
+
* TODO (deferred, closed-set change — separate decision): add
|
|
47925
|
+
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
47926
|
+
* admin "Integrations" page.
|
|
47927
|
+
*/
|
|
47928
|
+
/**
|
|
47929
|
+
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
47930
|
+
* adapter picks what it supports and the degrade engine filters the rest.
|
|
47931
|
+
*/
|
|
47932
|
+
var AttachmentMediaTypeSchema = _enum([
|
|
47933
|
+
"image",
|
|
47934
|
+
"video",
|
|
47935
|
+
"gif",
|
|
47936
|
+
"audio",
|
|
47937
|
+
"icon"
|
|
47938
|
+
]);
|
|
47939
|
+
/**
|
|
47940
|
+
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
47941
|
+
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
47942
|
+
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
47943
|
+
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
47944
|
+
*/
|
|
47945
|
+
var AttachmentSchema = object({
|
|
47946
|
+
mediaType: AttachmentMediaTypeSchema,
|
|
47947
|
+
url: string().optional(),
|
|
47948
|
+
bytes: _instanceof(Uint8Array).optional(),
|
|
47949
|
+
mime: string().optional(),
|
|
47950
|
+
name: string().optional()
|
|
47951
|
+
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
47952
|
+
var NotificationFormatSchema = _enum([
|
|
47953
|
+
"text",
|
|
47954
|
+
"markdown",
|
|
47955
|
+
"html"
|
|
47956
|
+
]);
|
|
47957
|
+
/**
|
|
47958
|
+
* The CLOSED icon vocabulary an action button may use.
|
|
47959
|
+
*
|
|
47960
|
+
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
47961
|
+
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
47962
|
+
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
47963
|
+
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
47964
|
+
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
47965
|
+
*
|
|
47966
|
+
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
47967
|
+
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
47968
|
+
* differently.
|
|
47969
|
+
*
|
|
47970
|
+
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
47971
|
+
*
|
|
47972
|
+
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
47973
|
+
* the whole set onto its own renderer's vocabulary through a
|
|
47974
|
+
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
47975
|
+
* fallback, so adding a member here fails every adapter's build until someone
|
|
47976
|
+
* decides its glyph, which is the only place that decision can be made
|
|
47977
|
+
* honestly.
|
|
47978
|
+
*
|
|
47979
|
+
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
47980
|
+
* `disarm` straight through; iOS feeds that string to
|
|
47981
|
+
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
47982
|
+
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
47983
|
+
* mapping, and "the field is documented" is not "the value renders".
|
|
47984
|
+
*
|
|
47985
|
+
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
47986
|
+
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
47987
|
+
* so an addon that emits a token the running hub does not know does not lose an
|
|
47988
|
+
* icon — its whole `send` fails Zod validation and the notification never
|
|
47989
|
+
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
47990
|
+
*/
|
|
47991
|
+
var NotificationActionIconSchema = _enum([
|
|
47992
|
+
"acknowledge",
|
|
47993
|
+
"dismiss",
|
|
47994
|
+
"silence",
|
|
47995
|
+
"snooze",
|
|
47996
|
+
"view",
|
|
47997
|
+
"play",
|
|
47998
|
+
"open",
|
|
47999
|
+
"close",
|
|
48000
|
+
"lock",
|
|
48001
|
+
"unlock",
|
|
48002
|
+
"arm",
|
|
48003
|
+
"arm-home",
|
|
48004
|
+
"arm-away",
|
|
48005
|
+
"arm-night",
|
|
48006
|
+
"disarm",
|
|
48007
|
+
"light",
|
|
48008
|
+
"alert",
|
|
48009
|
+
"camera"
|
|
48010
|
+
]);
|
|
48011
|
+
/** A single tap-through action button. */
|
|
48012
|
+
var NotificationActionSchema = object({
|
|
48013
|
+
id: string(),
|
|
48014
|
+
label: string(),
|
|
48015
|
+
url: string().optional(),
|
|
48016
|
+
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
48017
|
+
icon: NotificationActionIconSchema.optional(),
|
|
48018
|
+
/**
|
|
48019
|
+
* Renders in a warning style where the notifier supports it.
|
|
48020
|
+
*
|
|
48021
|
+
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
48022
|
+
* else — see `notification-center/action-token.ts` for what that does and
|
|
48023
|
+
* does not buy.
|
|
48024
|
+
*/
|
|
48025
|
+
destructive: boolean().optional(),
|
|
48026
|
+
/**
|
|
48027
|
+
* How the tap should REACH the url.
|
|
48028
|
+
*
|
|
48029
|
+
* `navigate` (absent, and every button authored before this field) opens it:
|
|
48030
|
+
* the phone leaves the notification and shows whatever the callback returns.
|
|
48031
|
+
* That is right for a button whose answer the operator wants to read.
|
|
48032
|
+
*
|
|
48033
|
+
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
48034
|
+
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
48035
|
+
* an answer to the notification, and being thrown into a browser tab to
|
|
48036
|
+
* confirm it costs more attention than the notification did. A backend that
|
|
48037
|
+
* cannot do a background call renders it as an ordinary link (the adapters
|
|
48038
|
+
* fall back rather than dropping the button), so this is a preference, never
|
|
48039
|
+
* a requirement.
|
|
48040
|
+
*/
|
|
48041
|
+
mode: _enum(["navigate", "background"]).optional()
|
|
48042
|
+
});
|
|
48043
|
+
/**
|
|
48044
|
+
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
48045
|
+
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
48046
|
+
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
48047
|
+
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
48048
|
+
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
48049
|
+
* `priority` for that one target.
|
|
48050
|
+
*/
|
|
48051
|
+
var NotificationSchema = object({
|
|
48052
|
+
body: string(),
|
|
48053
|
+
title: string().optional(),
|
|
48054
|
+
format: NotificationFormatSchema.default("text"),
|
|
48055
|
+
priority: number().int().min(1).max(5).default(3),
|
|
48056
|
+
level: string().optional(),
|
|
48057
|
+
attachments: array(AttachmentSchema).optional(),
|
|
48058
|
+
clickUrl: string().optional(),
|
|
48059
|
+
actions: array(NotificationActionSchema).optional(),
|
|
48060
|
+
sound: string().optional(),
|
|
48061
|
+
ttl: number().optional(),
|
|
48062
|
+
tag: string().optional(),
|
|
48063
|
+
deviceId: number().optional(),
|
|
48064
|
+
eventId: string().optional(),
|
|
48065
|
+
metadata: record(string(), unknown()).optional()
|
|
48066
|
+
});
|
|
48067
|
+
/** One declared native severity/priority level for a kind. */
|
|
48068
|
+
var TargetKindLevelSchema = object({
|
|
48069
|
+
id: string(),
|
|
48070
|
+
label: string(),
|
|
48071
|
+
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
48072
|
+
ordinal: number().int().min(1).max(5).nullable(),
|
|
48073
|
+
flags: object({
|
|
48074
|
+
critical: boolean().optional(),
|
|
48075
|
+
silent: boolean().optional(),
|
|
48076
|
+
noPush: boolean().optional()
|
|
48077
|
+
}).optional(),
|
|
48078
|
+
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
48079
|
+
requires: array(string()).optional(),
|
|
48080
|
+
description: string().optional()
|
|
48081
|
+
});
|
|
48082
|
+
/** The full capability block consulted before dispatch. */
|
|
48083
|
+
var TargetKindCapsSchema = object({
|
|
48084
|
+
attachments: object({
|
|
48085
|
+
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
48086
|
+
mode: _enum([
|
|
48087
|
+
"url",
|
|
48088
|
+
"bytes",
|
|
48089
|
+
"both"
|
|
48090
|
+
]),
|
|
48091
|
+
max: number().int().nonnegative(),
|
|
48092
|
+
maxBytes: number().int().positive().optional()
|
|
48093
|
+
}),
|
|
48094
|
+
/** Max action buttons (0 = none). */
|
|
48095
|
+
actions: number().int().nonnegative(),
|
|
48096
|
+
/**
|
|
48097
|
+
* Whether this kind renders a per-action ICON.
|
|
48098
|
+
*
|
|
48099
|
+
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
48100
|
+
* run on the addon cap path — three production failures in one day taught
|
|
48101
|
+
* this repo that once. Absent is read as false by the degrade engine, which
|
|
48102
|
+
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
48103
|
+
* assumed and dropped costs the operator's trust in the field.
|
|
48104
|
+
*/
|
|
48105
|
+
actionIcons: boolean().optional(),
|
|
48106
|
+
levels: array(TargetKindLevelSchema),
|
|
48107
|
+
format: array(NotificationFormatSchema),
|
|
48108
|
+
clickUrl: boolean(),
|
|
48109
|
+
sound: boolean(),
|
|
48110
|
+
ttl: boolean(),
|
|
48111
|
+
bodyMaxLen: number().int().positive()
|
|
48112
|
+
});
|
|
48113
|
+
/**
|
|
48114
|
+
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
48115
|
+
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
48116
|
+
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
48117
|
+
* the union is large and not meant for runtime validation here; the exported
|
|
48118
|
+
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
48119
|
+
*/
|
|
48120
|
+
var ConfigSchemaPassthrough$2 = unknown();
|
|
48121
|
+
var TargetKindSchema = object({
|
|
48122
|
+
kind: string(),
|
|
48123
|
+
label: string(),
|
|
48124
|
+
icon: string(),
|
|
48125
|
+
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
48126
|
+
addonId: string(),
|
|
48127
|
+
/**
|
|
48128
|
+
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
48129
|
+
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
48130
|
+
* when the addon bundles no icon for that kind — the client then falls back
|
|
48131
|
+
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
48132
|
+
*
|
|
48133
|
+
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
48134
|
+
* client, and a native client joins it onto its own hub base.
|
|
48135
|
+
*
|
|
48136
|
+
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
48137
|
+
* field that survived only because the runtime cap-router forwards provider
|
|
48138
|
+
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
48139
|
+
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
48140
|
+
* broken silently the moment output validation was tightened anywhere.
|
|
48141
|
+
*/
|
|
48142
|
+
iconUrl: string().optional(),
|
|
48143
|
+
/**
|
|
48144
|
+
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
48145
|
+
*
|
|
48146
|
+
* The server knows this and therefore says it, because the client cannot
|
|
48147
|
+
* safely guess: a React-Native client renders SVG and raster through two
|
|
48148
|
+
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
48149
|
+
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
48150
|
+
* placeholder glyph for every vector icon while the web build looked fine.
|
|
48151
|
+
*
|
|
48152
|
+
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
48153
|
+
* not been updated — a client that cannot determine the type should prefer
|
|
48154
|
+
* its raster path, which is the safe default for an unknown image.
|
|
48155
|
+
*/
|
|
48156
|
+
iconMediaType: string().optional(),
|
|
48157
|
+
configSchema: ConfigSchemaPassthrough$2,
|
|
48158
|
+
/**
|
|
48159
|
+
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
48160
|
+
* base URL, instance, chat, recipient). A save that changes any of them
|
|
48161
|
+
* while leaving a secret redacted is refused by the provider (D634), so an
|
|
48162
|
+
* editor uses this to ask for the secret on exactly those edits instead of
|
|
48163
|
+
* on every edit.
|
|
48164
|
+
*
|
|
48165
|
+
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
48166
|
+
* kinds) and from a provider older than this field — an editor that finds
|
|
48167
|
+
* it absent must assume ANY edit may need the secret.
|
|
48168
|
+
*/
|
|
48169
|
+
destinationKeys: array(string()).optional(),
|
|
48170
|
+
supportsDiscovery: boolean(),
|
|
48171
|
+
caps: TargetKindCapsSchema
|
|
48172
|
+
});
|
|
48173
|
+
/**
|
|
48174
|
+
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
48175
|
+
* (return a presence marker only) when serving `listTargets` — never
|
|
48176
|
+
* round-trip a stored secret to the UI.
|
|
48177
|
+
*/
|
|
48178
|
+
var TargetSchema = object({
|
|
48179
|
+
id: string(),
|
|
48180
|
+
name: string(),
|
|
48181
|
+
kind: string(),
|
|
48182
|
+
addonId: string(),
|
|
48183
|
+
enabled: boolean(),
|
|
48184
|
+
config: record(string(), unknown())
|
|
48185
|
+
});
|
|
48186
|
+
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
48187
|
+
var DiscoveredTargetSchema = object({
|
|
48188
|
+
kind: string(),
|
|
48189
|
+
suggestedName: string(),
|
|
48190
|
+
config: record(string(), unknown())
|
|
48191
|
+
});
|
|
48192
|
+
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
48193
|
+
var RenderedAsSchema = object({
|
|
48194
|
+
level: string(),
|
|
48195
|
+
format: NotificationFormatSchema,
|
|
48196
|
+
attachmentsSent: number().int().nonnegative(),
|
|
48197
|
+
actionsSent: number().int().nonnegative(),
|
|
48198
|
+
truncated: boolean(),
|
|
48199
|
+
dropped: array(string())
|
|
48200
|
+
});
|
|
48201
|
+
var SendResultSchema = object({
|
|
48202
|
+
success: boolean(),
|
|
48203
|
+
error: string().optional(),
|
|
48204
|
+
renderedAs: RenderedAsSchema.optional()
|
|
48205
|
+
});
|
|
48206
|
+
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
48207
|
+
var TestResultSchema = SendResultSchema;
|
|
48208
|
+
/**
|
|
48209
|
+
* Pre-save credential probe against a partial (unsaved) target config.
|
|
48210
|
+
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
48211
|
+
*/
|
|
48212
|
+
var ProbeTargetConfigResultSchema = object({
|
|
48213
|
+
ok: boolean(),
|
|
48214
|
+
resolvedUrl: string(),
|
|
48215
|
+
httpStatus: number().int().optional(),
|
|
48216
|
+
stateInstance: string().optional(),
|
|
48217
|
+
error: string().optional()
|
|
48218
|
+
});
|
|
48219
|
+
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema), { auth: "admin" }), method(object({ targetId: string() }), TargetSchema, { auth: "admin" }), method(object({
|
|
48220
|
+
kind: string(),
|
|
48221
|
+
config: record(string(), unknown()).optional(),
|
|
48222
|
+
/**
|
|
48223
|
+
* When editing / duplicating, the blank password field never round-trips
|
|
48224
|
+
* the stored token. Pass the source target id so the provider can restore
|
|
48225
|
+
* secrets server-side before dialling (same merge as upsert).
|
|
48226
|
+
*/
|
|
48227
|
+
targetId: string().optional()
|
|
48228
|
+
}), array(DiscoveredTargetSchema), { auth: "admin" }), method(object({
|
|
48229
|
+
kind: string(),
|
|
48230
|
+
config: record(string(), unknown()),
|
|
48231
|
+
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
48232
|
+
targetId: string().optional()
|
|
48233
|
+
}), ProbeTargetConfigResultSchema, {
|
|
48234
|
+
kind: "mutation",
|
|
48235
|
+
auth: "admin"
|
|
48236
|
+
}), method(object({
|
|
48237
|
+
targetId: string(),
|
|
48238
|
+
notification: NotificationSchema
|
|
48239
|
+
}), SendResultSchema, {
|
|
48240
|
+
kind: "mutation",
|
|
48241
|
+
auth: "admin"
|
|
48242
|
+
}), method(object({
|
|
48243
|
+
targetId: string(),
|
|
48244
|
+
sample: NotificationSchema.optional()
|
|
48245
|
+
}), TestResultSchema, {
|
|
48246
|
+
kind: "mutation",
|
|
48247
|
+
auth: "admin"
|
|
48248
|
+
}), method(object({
|
|
48249
|
+
target: TargetSchema,
|
|
48250
|
+
/**
|
|
48251
|
+
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
48252
|
+
* existing row. The UI never holds the stored token; blank / redacted
|
|
48253
|
+
* password fields are restored from this source (D634 still applies if
|
|
48254
|
+
* destinations diverge without a re-typed secret).
|
|
48255
|
+
*/
|
|
48256
|
+
cloneSecretsFrom: string().optional()
|
|
48257
|
+
}), TargetSchema, {
|
|
48258
|
+
kind: "mutation",
|
|
48259
|
+
auth: "admin"
|
|
48260
|
+
}), method(object({ targetId: string() }), _void(), {
|
|
48261
|
+
kind: "mutation",
|
|
48262
|
+
auth: "admin"
|
|
48263
|
+
}), method(object({
|
|
48264
|
+
targetId: string(),
|
|
48265
|
+
enabled: boolean()
|
|
48266
|
+
}), _void(), {
|
|
48267
|
+
kind: "mutation",
|
|
48268
|
+
auth: "admin"
|
|
48269
|
+
});
|
|
47887
48270
|
var AUDIO_MACRO_LABELS = [
|
|
47888
48271
|
{
|
|
47889
48272
|
id: "speech",
|
|
@@ -61164,9 +61547,9 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
61164
61547
|
}), LogStreamEntrySchema, { kind: "subscription" });
|
|
61165
61548
|
object({
|
|
61166
61549
|
/** Carbon dioxide concentration in ppm. */
|
|
61167
|
-
|
|
61550
|
+
co2: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
61168
61551
|
/** Total volatile organic compounds in ppb. */
|
|
61169
|
-
|
|
61552
|
+
voc: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
61170
61553
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
61171
61554
|
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
61172
61555
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
@@ -61179,7 +61562,7 @@ object({
|
|
|
61179
61562
|
DeviceType.Sensor;
|
|
61180
61563
|
object({
|
|
61181
61564
|
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
61182
|
-
|
|
61565
|
+
illuminance: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
61183
61566
|
precision: 0,
|
|
61184
61567
|
label: "Illuminance"
|
|
61185
61568
|
})),
|
|
@@ -61276,6 +61659,84 @@ DeviceType.Camera, method(object({ deviceId: number() }), AudioMetricsSnapshotSc
|
|
|
61276
61659
|
* would produce more than `maxPoints` samples. */
|
|
61277
61660
|
sampleEveryMs: number().int().positive().optional()
|
|
61278
61661
|
}), AudioMetricsHistorySchema);
|
|
61662
|
+
method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
|
|
61663
|
+
actionId: string().min(1),
|
|
61664
|
+
variables: record(string(), ActionVariableValueSchema).optional()
|
|
61665
|
+
}), _void(), {
|
|
61666
|
+
kind: "mutation",
|
|
61667
|
+
auth: "admin"
|
|
61668
|
+
}), method(object({ actionId: string().min(1) }), _void(), {
|
|
61669
|
+
kind: "mutation",
|
|
61670
|
+
auth: "admin"
|
|
61671
|
+
});
|
|
61672
|
+
/**
|
|
61673
|
+
* actions — the ONE surface for runnable actions, for the UI and for
|
|
61674
|
+
* automations. Provided by the core-blocks builtin on the hub.
|
|
61675
|
+
*
|
|
61676
|
+
* An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
|
|
61677
|
+
* steps, kept in the hub's `actions` record kind) or declared by an addon over
|
|
61678
|
+
* `action-source`. `list` asks every `action-source` provider LIVE and overlays
|
|
61679
|
+
* the run status from the hub's `runs` ledger; there is no catalog here to
|
|
61680
|
+
* drift (D3).
|
|
61681
|
+
*
|
|
61682
|
+
* **Permissions follow the camera, as linked devices do.** An action is linked
|
|
61683
|
+
* to cameras by the operator (`setLinks`, D356: nothing links itself). A
|
|
61684
|
+
* non-admin may `get` / `run` an action only through a camera they may see that
|
|
61685
|
+
* links it: they name the camera (`deviceId`, a top-level field so the scope
|
|
61686
|
+
* gate sees it) and the provider refuses an action that camera does not link.
|
|
61687
|
+
* An admin, and an in-process caller (an automation block), may run any action.
|
|
61688
|
+
* Every refusal is typed (`[not-linked] …`) and logged.
|
|
61689
|
+
*
|
|
61690
|
+
* A second `run` of an action that is already running is REFUSED — traced and
|
|
61691
|
+
* logged — never queued.
|
|
61692
|
+
*/
|
|
61693
|
+
var ActionIdInput = object({ actionId: string().min(1) });
|
|
61694
|
+
var ActionLinksSchema = object({
|
|
61695
|
+
deviceId: number().int().nonnegative(),
|
|
61696
|
+
actionIds: array(string().min(1)).max(100)
|
|
61697
|
+
});
|
|
61698
|
+
method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
|
|
61699
|
+
actionId: string().min(1),
|
|
61700
|
+
deviceId: number().int().nonnegative().optional()
|
|
61701
|
+
}), object({ action: ActionEntrySchema.nullable() }), {
|
|
61702
|
+
role: "viewer",
|
|
61703
|
+
auth: "protected",
|
|
61704
|
+
kind: "query",
|
|
61705
|
+
caller: "required"
|
|
61706
|
+
}), method(object({
|
|
61707
|
+
actionId: string().min(1),
|
|
61708
|
+
variables: record(string(), ActionVariableValueSchema).optional(),
|
|
61709
|
+
wait: boolean().optional(),
|
|
61710
|
+
origin: ActionRunOriginSchema.optional(),
|
|
61711
|
+
deviceId: number().int().nonnegative().optional()
|
|
61712
|
+
}), ActionRunResultSchema, {
|
|
61713
|
+
role: "viewer",
|
|
61714
|
+
auth: "protected",
|
|
61715
|
+
kind: "mutation",
|
|
61716
|
+
caller: "required"
|
|
61717
|
+
}), method(ActionIdInput, _void(), {
|
|
61718
|
+
kind: "mutation",
|
|
61719
|
+
auth: "admin"
|
|
61720
|
+
}), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
|
|
61721
|
+
kind: "mutation",
|
|
61722
|
+
auth: "admin"
|
|
61723
|
+
}), method(object({
|
|
61724
|
+
actionId: string().min(1),
|
|
61725
|
+
action: ActionInputSchema.partial()
|
|
61726
|
+
}), object({ action: ActionEntrySchema }), {
|
|
61727
|
+
kind: "mutation",
|
|
61728
|
+
auth: "admin"
|
|
61729
|
+
}), method(ActionIdInput, _void(), {
|
|
61730
|
+
kind: "mutation",
|
|
61731
|
+
auth: "admin"
|
|
61732
|
+
}), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
|
|
61733
|
+
role: "viewer",
|
|
61734
|
+
auth: "protected",
|
|
61735
|
+
kind: "query"
|
|
61736
|
+
}), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
|
|
61737
|
+
kind: "mutation",
|
|
61738
|
+
auth: "admin"
|
|
61739
|
+
});
|
|
61279
61740
|
object({
|
|
61280
61741
|
/** Whether the automation is currently enabled. Disabled automations
|
|
61281
61742
|
* ignore their trigger block — manual `trigger` still works. */
|
|
@@ -61329,7 +61790,7 @@ var BatteryStatusSchema = object({
|
|
|
61329
61790
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
61330
61791
|
* declines to band a non-finite reading, which is the correct shape.
|
|
61331
61792
|
*/
|
|
61332
|
-
|
|
61793
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
61333
61794
|
/**
|
|
61334
61795
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
61335
61796
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -61339,7 +61800,7 @@ var BatteryStatusSchema = object({
|
|
|
61339
61800
|
* `'unknown'` is the absence of an answer: the provider has not read the
|
|
61340
61801
|
* power fields yet, or the firmware reported neither. Before it existed,
|
|
61341
61802
|
* two unreadable fields produced `'none'`, and a camera nobody had reached
|
|
61342
|
-
* was drawn "on battery alone" — the same D315 defect `
|
|
61803
|
+
* was drawn "on battery alone" — the same D315 defect `level` closed
|
|
61343
61804
|
* by going nullable. Consumers SKIP it (no charger state published, no
|
|
61344
61805
|
* glyph, no HomeKit ChargingState) rather than coerce it either way.
|
|
61345
61806
|
*/
|
|
@@ -61363,7 +61824,7 @@ var BatteryStatusSchema = object({
|
|
|
61363
61824
|
* that only report charge. A second reading on this cap, not a second
|
|
61364
61825
|
* `numeric-sensor` on the same device.
|
|
61365
61826
|
*/
|
|
61366
|
-
|
|
61827
|
+
voltage: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
61367
61828
|
/**
|
|
61368
61829
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
61369
61830
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -61397,7 +61858,7 @@ var BatteryStatusSchema = object({
|
|
|
61397
61858
|
/**
|
|
61398
61859
|
* True when the source is a BINARY low-battery indicator (HA
|
|
61399
61860
|
* `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
|
|
61400
|
-
* charge level — `
|
|
61861
|
+
* charge level — `level` is then a coarse stand-in (100 = normal,
|
|
61401
61862
|
* sub-threshold = low). UI MUST render "Normal"/"Low" instead of a
|
|
61402
61863
|
* misleading exact percentage. Absent/false → genuine 0–100 % reading.
|
|
61403
61864
|
*/
|
|
@@ -61417,15 +61878,15 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
61417
61878
|
var batteryCustomize = {
|
|
61418
61879
|
version: 1,
|
|
61419
61880
|
targets: [{
|
|
61420
|
-
id: "
|
|
61881
|
+
id: "level",
|
|
61421
61882
|
cardinality: "scalar",
|
|
61422
61883
|
vocabulary: {
|
|
61423
61884
|
cap: "battery",
|
|
61424
|
-
stateField: "
|
|
61885
|
+
stateField: "level"
|
|
61425
61886
|
},
|
|
61426
61887
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
61427
61888
|
apply: "add",
|
|
61428
|
-
path: "
|
|
61889
|
+
path: "level",
|
|
61429
61890
|
sources: [{
|
|
61430
61891
|
kind: "field",
|
|
61431
61892
|
valueKinds: ["number", "string"],
|
|
@@ -61519,7 +61980,7 @@ onStatusChanged: { data: object({
|
|
|
61519
61980
|
schema: BatteryStatusSchema,
|
|
61520
61981
|
kind: "push",
|
|
61521
61982
|
empty: {
|
|
61522
|
-
|
|
61983
|
+
level: null,
|
|
61523
61984
|
charging: "unknown",
|
|
61524
61985
|
sleeping: false,
|
|
61525
61986
|
lastUpdated: 0
|
|
@@ -61546,11 +62007,11 @@ onStatusChanged: { data: object({
|
|
|
61546
62007
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
61547
62008
|
*/
|
|
61548
62009
|
history: { fields: {
|
|
61549
|
-
|
|
62010
|
+
level: {
|
|
61550
62011
|
kind: "gauge",
|
|
61551
62012
|
unit: "%"
|
|
61552
62013
|
},
|
|
61553
|
-
|
|
62014
|
+
voltage: {
|
|
61554
62015
|
kind: "gauge",
|
|
61555
62016
|
unit: "V"
|
|
61556
62017
|
}
|
|
@@ -61568,19 +62029,19 @@ object({
|
|
|
61568
62029
|
DeviceType.Sensor;
|
|
61569
62030
|
object({
|
|
61570
62031
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
61571
|
-
|
|
62032
|
+
level: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
61572
62033
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
61573
62034
|
lastChangedAt: number()
|
|
61574
62035
|
});
|
|
61575
62036
|
DeviceType.Light, method(object({
|
|
61576
62037
|
deviceId: number().int().nonnegative(),
|
|
61577
|
-
|
|
62038
|
+
level: number().min(0).max(100)
|
|
61578
62039
|
}), _void(), {
|
|
61579
62040
|
kind: "mutation",
|
|
61580
62041
|
auth: "protected"
|
|
61581
62042
|
}), object({
|
|
61582
62043
|
deviceId: number(),
|
|
61583
|
-
|
|
62044
|
+
level: number().min(0).max(100),
|
|
61584
62045
|
lastChangedAt: number()
|
|
61585
62046
|
});
|
|
61586
62047
|
DeviceType.Button, method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
@@ -62081,11 +62542,11 @@ var ColorInputSchema = discriminatedUnion("mode", [
|
|
|
62081
62542
|
}),
|
|
62082
62543
|
object({
|
|
62083
62544
|
mode: literal("mired"),
|
|
62084
|
-
|
|
62545
|
+
colorTemperature: number().int().min(50).max(1e3)
|
|
62085
62546
|
})
|
|
62086
62547
|
]);
|
|
62087
62548
|
object({
|
|
62088
|
-
/** Active color mode — which of `rgb` / `hsv` / `
|
|
62549
|
+
/** Active color mode — which of `rgb` / `hsv` / `colorTemperature` reflects
|
|
62089
62550
|
* the bulb's current state. */
|
|
62090
62551
|
mode: _enum([
|
|
62091
62552
|
"rgb",
|
|
@@ -62097,7 +62558,7 @@ object({
|
|
|
62097
62558
|
/** Populated when `mode === 'hsv'`. */
|
|
62098
62559
|
hsv: HsvTripletSchema.optional(),
|
|
62099
62560
|
/** Populated when `mode === 'mired'`. */
|
|
62100
|
-
|
|
62561
|
+
colorTemperature: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
62101
62562
|
/** Ms epoch of the last operator-driven change. */
|
|
62102
62563
|
lastChangedAt: number()
|
|
62103
62564
|
});
|
|
@@ -62116,7 +62577,7 @@ DeviceType.Light, method(object({
|
|
|
62116
62577
|
]),
|
|
62117
62578
|
rgb: RgbTripletSchema.optional(),
|
|
62118
62579
|
hsv: HsvTripletSchema.optional(),
|
|
62119
|
-
|
|
62580
|
+
colorTemperature: number().int().optional(),
|
|
62120
62581
|
lastChangedAt: number()
|
|
62121
62582
|
});
|
|
62122
62583
|
var ConnectionTestOutcomeSchema = discriminatedUnion("outcome", [
|
|
@@ -62542,11 +63003,11 @@ object({
|
|
|
62542
63003
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
62543
63004
|
availablePrograms: array(string()),
|
|
62544
63005
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
62545
|
-
|
|
63006
|
+
remaining: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
62546
63007
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
62547
|
-
|
|
63008
|
+
delayedStart: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
62548
63009
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
62549
|
-
|
|
63010
|
+
progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62550
63011
|
/** True when the door is reported open; null when the door state is not known. */
|
|
62551
63012
|
doorOpen: boolean().nullable(),
|
|
62552
63013
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -63164,7 +63625,7 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
63164
63625
|
object({
|
|
63165
63626
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
63166
63627
|
* speed surface (single-speed fan). */
|
|
63167
|
-
|
|
63628
|
+
speed: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63168
63629
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
63169
63630
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
63170
63631
|
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
@@ -63184,7 +63645,7 @@ object({
|
|
|
63184
63645
|
});
|
|
63185
63646
|
DeviceType.Fan, method(object({
|
|
63186
63647
|
deviceId: number().int().nonnegative(),
|
|
63187
|
-
|
|
63648
|
+
speed: number().min(0).max(100)
|
|
63188
63649
|
}), _void(), {
|
|
63189
63650
|
kind: "mutation",
|
|
63190
63651
|
auth: "protected"
|
|
@@ -63367,7 +63828,7 @@ DeviceType.Humidifier, method(object({
|
|
|
63367
63828
|
});
|
|
63368
63829
|
object({
|
|
63369
63830
|
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
63370
|
-
|
|
63831
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
63371
63832
|
precision: 0,
|
|
63372
63833
|
label: "Humidity"
|
|
63373
63834
|
})),
|
|
@@ -63810,7 +64271,7 @@ object({
|
|
|
63810
64271
|
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63811
64272
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
63812
64273
|
* task is active / progress is unavailable. */
|
|
63813
|
-
|
|
64274
|
+
progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63814
64275
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
63815
64276
|
* or null when unknown. */
|
|
63816
64277
|
currentCode: number().nullable().meta(readingMeta("none")),
|
|
@@ -64300,10 +64761,10 @@ object({
|
|
|
64300
64761
|
currentMedia: MediaInfoSchema.nullable(),
|
|
64301
64762
|
/** Current playback position in ms. Null when not seekable or
|
|
64302
64763
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
64303
|
-
|
|
64764
|
+
position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
64304
64765
|
/** Total duration of the current media in ms. Null when unknown
|
|
64305
64766
|
* (live stream) or nothing is playing. */
|
|
64306
|
-
|
|
64767
|
+
duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
64307
64768
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
64308
64769
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
64309
64770
|
shuffle: boolean().nullable(),
|
|
@@ -64330,7 +64791,7 @@ DeviceType.MediaPlayer, method(object({ deviceId: number().int().nonnegative() }
|
|
|
64330
64791
|
auth: "protected"
|
|
64331
64792
|
}), method(object({
|
|
64332
64793
|
deviceId: number().int().nonnegative(),
|
|
64333
|
-
|
|
64794
|
+
position: number().int().nonnegative()
|
|
64334
64795
|
}), _void(), {
|
|
64335
64796
|
kind: "mutation",
|
|
64336
64797
|
auth: "protected"
|
|
@@ -65003,9 +65464,9 @@ var NetworkLinkStatusSchema = object({
|
|
|
65003
65464
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
65004
65465
|
* SKIP a null rather than coerce it.
|
|
65005
65466
|
*/
|
|
65006
|
-
|
|
65467
|
+
signal: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
65007
65468
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
65008
|
-
|
|
65469
|
+
rssi: number().optional().meta(readingMeta("signal-level")),
|
|
65009
65470
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
65010
65471
|
ssid: string().optional(),
|
|
65011
65472
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
@@ -65666,10 +66127,20 @@ var PetFeederDeviceStatusSchema = _enum([
|
|
|
65666
66127
|
]);
|
|
65667
66128
|
var gramsPortion = number().int().min(4).max(200);
|
|
65668
66129
|
object({
|
|
65669
|
-
/** Food
|
|
65670
|
-
*
|
|
65671
|
-
* bowl
|
|
66130
|
+
/** Food in the TANK (hopper), as the feeder's own sensor reports it
|
|
66131
|
+
* (`state.food`). A coarse level code, not grams — `0` is empty. The
|
|
66132
|
+
* amount in the bowl is `bowlFood`. On dual-hopper models this is the
|
|
66133
|
+
* combined reading; per-hopper levels live in `food1`/`food2`. Null when
|
|
66134
|
+
* the device has not reported yet. */
|
|
65672
66135
|
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
66136
|
+
/** Food in the BOWL as the feeder reports it (`state.bowl`), in the
|
|
66137
|
+
* feeder's own units. Null when the model reports none. */
|
|
66138
|
+
bowlFood: number().nullable().meta(readingMeta("none")),
|
|
66139
|
+
/** True while the pet is eating (`state.eating`). */
|
|
66140
|
+
eating: boolean(),
|
|
66141
|
+
/** Whether `markFoodReplenished` does anything on this model. When false
|
|
66142
|
+
* the client must not offer it. */
|
|
66143
|
+
supportsMarkRefilled: boolean(),
|
|
65673
66144
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
65674
66145
|
* single-hopper models. */
|
|
65675
66146
|
food1: number().nullable().meta(readingMeta("none")),
|
|
@@ -65677,8 +66148,8 @@ object({
|
|
|
65677
66148
|
* single-hopper models. */
|
|
65678
66149
|
food2: number().nullable().meta(readingMeta("none")),
|
|
65679
66150
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
65680
|
-
* (`device_class: problem`, on = low). True when the
|
|
65681
|
-
*
|
|
66151
|
+
* (`device_class: problem`, on = low). True when the tank reports empty,
|
|
66152
|
+
* or, on a dual-hopper model, when EITHER hopper is empty. */
|
|
65682
66153
|
lowFood: boolean(),
|
|
65683
66154
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
65684
66155
|
* device has no battery reading. */
|
|
@@ -66145,16 +66616,16 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
66145
66616
|
auth: "admin"
|
|
66146
66617
|
});
|
|
66147
66618
|
object({
|
|
66148
|
-
/** Instantaneous power draw
|
|
66149
|
-
|
|
66619
|
+
/** Instantaneous power draw (watts). */
|
|
66620
|
+
power: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
66150
66621
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
66151
|
-
|
|
66152
|
-
/** Voltage
|
|
66153
|
-
|
|
66622
|
+
energy: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
66623
|
+
/** Voltage (volts). */
|
|
66624
|
+
voltage: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
66154
66625
|
/** Current in amperes. */
|
|
66155
|
-
|
|
66626
|
+
current: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
66156
66627
|
/** Apparent power in volt-amperes. */
|
|
66157
|
-
|
|
66628
|
+
apparentPower: number().optional().meta(readingMeta("apparent-power")),
|
|
66158
66629
|
/** Power factor (0..1) if reported. */
|
|
66159
66630
|
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
66160
66631
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -66209,16 +66680,13 @@ object({
|
|
|
66209
66680
|
location: string().nullable(),
|
|
66210
66681
|
/** GPS coordinates when available. Null otherwise. */
|
|
66211
66682
|
gps: GpsLocationSchema.nullable(),
|
|
66212
|
-
/** Optional battery level of the tracking device (0..100). Null
|
|
66213
|
-
* when not reported. */
|
|
66214
|
-
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
66215
66683
|
/** Ms epoch when the slice was last updated. */
|
|
66216
66684
|
lastChangedAt: number()
|
|
66217
66685
|
});
|
|
66218
66686
|
DeviceType.Presence;
|
|
66219
66687
|
object({
|
|
66220
66688
|
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
66221
|
-
|
|
66689
|
+
pressure: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
66222
66690
|
/** Ms epoch when the slice was last updated. */
|
|
66223
66691
|
lastFetchedAt: number()
|
|
66224
66692
|
});
|
|
@@ -69745,7 +70213,7 @@ object({
|
|
|
69745
70213
|
DeviceType.Sensor;
|
|
69746
70214
|
object({
|
|
69747
70215
|
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
69748
|
-
|
|
70216
|
+
temperature: number().nullable().meta(readingMeta("temperature", {
|
|
69749
70217
|
precision: 1,
|
|
69750
70218
|
label: "Temperature"
|
|
69751
70219
|
})),
|
|
@@ -70009,7 +70477,7 @@ object({
|
|
|
70009
70477
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
70010
70478
|
availableFanSpeeds: array(string()),
|
|
70011
70479
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
70012
|
-
|
|
70480
|
+
progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
70013
70481
|
/** Current error code (0 / null = no error). */
|
|
70014
70482
|
errorCode: number().nullable().meta(readingMeta("none")),
|
|
70015
70483
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
@@ -71008,6 +71476,104 @@ Object.freeze({
|
|
|
71008
71476
|
access: "create",
|
|
71009
71477
|
role: "admin"
|
|
71010
71478
|
},
|
|
71479
|
+
"actions.create": {
|
|
71480
|
+
capName: "actions",
|
|
71481
|
+
capScope: "system",
|
|
71482
|
+
addonId: null,
|
|
71483
|
+
access: "create",
|
|
71484
|
+
role: "admin"
|
|
71485
|
+
},
|
|
71486
|
+
"actions.delete": {
|
|
71487
|
+
capName: "actions",
|
|
71488
|
+
capScope: "system",
|
|
71489
|
+
addonId: null,
|
|
71490
|
+
access: "delete",
|
|
71491
|
+
role: "admin"
|
|
71492
|
+
},
|
|
71493
|
+
"actions.get": {
|
|
71494
|
+
capName: "actions",
|
|
71495
|
+
capScope: "system",
|
|
71496
|
+
addonId: null,
|
|
71497
|
+
access: "view",
|
|
71498
|
+
role: "viewer"
|
|
71499
|
+
},
|
|
71500
|
+
"actions.getLinks": {
|
|
71501
|
+
capName: "actions",
|
|
71502
|
+
capScope: "system",
|
|
71503
|
+
addonId: null,
|
|
71504
|
+
access: "view",
|
|
71505
|
+
role: "admin"
|
|
71506
|
+
},
|
|
71507
|
+
"actions.getTraces": {
|
|
71508
|
+
capName: "actions",
|
|
71509
|
+
capScope: "system",
|
|
71510
|
+
addonId: null,
|
|
71511
|
+
access: "view",
|
|
71512
|
+
role: "admin"
|
|
71513
|
+
},
|
|
71514
|
+
"actions.list": {
|
|
71515
|
+
capName: "actions",
|
|
71516
|
+
capScope: "system",
|
|
71517
|
+
addonId: null,
|
|
71518
|
+
access: "view",
|
|
71519
|
+
role: "admin"
|
|
71520
|
+
},
|
|
71521
|
+
"actions.listForCamera": {
|
|
71522
|
+
capName: "actions",
|
|
71523
|
+
capScope: "system",
|
|
71524
|
+
addonId: null,
|
|
71525
|
+
access: "view",
|
|
71526
|
+
role: "viewer"
|
|
71527
|
+
},
|
|
71528
|
+
"actions.run": {
|
|
71529
|
+
capName: "actions",
|
|
71530
|
+
capScope: "system",
|
|
71531
|
+
addonId: null,
|
|
71532
|
+
access: "create",
|
|
71533
|
+
role: "viewer"
|
|
71534
|
+
},
|
|
71535
|
+
"actions.setLinks": {
|
|
71536
|
+
capName: "actions",
|
|
71537
|
+
capScope: "system",
|
|
71538
|
+
addonId: null,
|
|
71539
|
+
access: "create",
|
|
71540
|
+
role: "admin"
|
|
71541
|
+
},
|
|
71542
|
+
"actions.stop": {
|
|
71543
|
+
capName: "actions",
|
|
71544
|
+
capScope: "system",
|
|
71545
|
+
addonId: null,
|
|
71546
|
+
access: "create",
|
|
71547
|
+
role: "admin"
|
|
71548
|
+
},
|
|
71549
|
+
"actions.update": {
|
|
71550
|
+
capName: "actions",
|
|
71551
|
+
capScope: "system",
|
|
71552
|
+
addonId: null,
|
|
71553
|
+
access: "create",
|
|
71554
|
+
role: "admin"
|
|
71555
|
+
},
|
|
71556
|
+
"actionSource.listActions": {
|
|
71557
|
+
capName: "action-source",
|
|
71558
|
+
capScope: "system",
|
|
71559
|
+
addonId: null,
|
|
71560
|
+
access: "view",
|
|
71561
|
+
role: "admin"
|
|
71562
|
+
},
|
|
71563
|
+
"actionSource.runAction": {
|
|
71564
|
+
capName: "action-source",
|
|
71565
|
+
capScope: "system",
|
|
71566
|
+
addonId: null,
|
|
71567
|
+
access: "create",
|
|
71568
|
+
role: "admin"
|
|
71569
|
+
},
|
|
71570
|
+
"actionSource.stopAction": {
|
|
71571
|
+
capName: "action-source",
|
|
71572
|
+
capScope: "system",
|
|
71573
|
+
addonId: null,
|
|
71574
|
+
access: "create",
|
|
71575
|
+
role: "admin"
|
|
71576
|
+
},
|
|
71011
71577
|
"addonPages.listPages": {
|
|
71012
71578
|
capName: "addon-pages",
|
|
71013
71579
|
capScope: "system",
|
|
@@ -72289,6 +72855,13 @@ Object.freeze({
|
|
|
72289
72855
|
access: "view",
|
|
72290
72856
|
role: "admin"
|
|
72291
72857
|
},
|
|
72858
|
+
"coreBlocks.getAutomationRunState": {
|
|
72859
|
+
capName: "core-blocks",
|
|
72860
|
+
capScope: "system",
|
|
72861
|
+
addonId: null,
|
|
72862
|
+
access: "view",
|
|
72863
|
+
role: "admin"
|
|
72864
|
+
},
|
|
72292
72865
|
"coreBlocks.getBlockSettings": {
|
|
72293
72866
|
capName: "core-blocks",
|
|
72294
72867
|
capScope: "system",
|
|
@@ -72310,6 +72883,13 @@ Object.freeze({
|
|
|
72310
72883
|
access: "view",
|
|
72311
72884
|
role: "admin"
|
|
72312
72885
|
},
|
|
72886
|
+
"coreBlocks.getTraces": {
|
|
72887
|
+
capName: "core-blocks",
|
|
72888
|
+
capScope: "system",
|
|
72889
|
+
addonId: null,
|
|
72890
|
+
access: "view",
|
|
72891
|
+
role: "admin"
|
|
72892
|
+
},
|
|
72313
72893
|
"coreBlocks.getTypeDefs": {
|
|
72314
72894
|
capName: "core-blocks",
|
|
72315
72895
|
capScope: "system",
|
|
@@ -72345,6 +72925,13 @@ Object.freeze({
|
|
|
72345
72925
|
access: "create",
|
|
72346
72926
|
role: "admin"
|
|
72347
72927
|
},
|
|
72928
|
+
"coreBlocks.reportAutomationRun": {
|
|
72929
|
+
capName: "core-blocks",
|
|
72930
|
+
capScope: "system",
|
|
72931
|
+
addonId: null,
|
|
72932
|
+
access: "create",
|
|
72933
|
+
role: "admin"
|
|
72934
|
+
},
|
|
72348
72935
|
"coreBlocks.restart": {
|
|
72349
72936
|
capName: "core-blocks",
|
|
72350
72937
|
capScope: "system",
|
|
@@ -80918,7 +81505,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
80918
81505
|
label: t("Full brightness", "Luminosità massima"),
|
|
80919
81506
|
phrase: t("Set {device} to full brightness", "Porta {device} alla massima luminosità"),
|
|
80920
81507
|
icon: "sun",
|
|
80921
|
-
args: {
|
|
81508
|
+
args: { level: 100 }
|
|
80922
81509
|
},
|
|
80923
81510
|
{
|
|
80924
81511
|
id: "brightness.half",
|
|
@@ -80926,7 +81513,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
80926
81513
|
label: t("Half brightness", "Luminosità a metà"),
|
|
80927
81514
|
phrase: t("Dim {device} to half", "Abbassa {device} a metà luminosità"),
|
|
80928
81515
|
icon: "sun-dim",
|
|
80929
|
-
args: {
|
|
81516
|
+
args: { level: 50 }
|
|
80930
81517
|
},
|
|
80931
81518
|
{
|
|
80932
81519
|
id: "brightness.off",
|
|
@@ -80934,16 +81521,16 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
80934
81521
|
label: t("Brightness off", "Luminosità a zero"),
|
|
80935
81522
|
phrase: t("Dim {device} to zero", "Abbassa {device} a zero"),
|
|
80936
81523
|
icon: "lightbulb-off",
|
|
80937
|
-
args: {
|
|
81524
|
+
args: { level: 0 }
|
|
80938
81525
|
},
|
|
80939
81526
|
{
|
|
80940
81527
|
id: "brightness.set",
|
|
80941
81528
|
method: "setBrightness",
|
|
80942
81529
|
label: t("Set brightness", "Imposta la luminosità"),
|
|
80943
|
-
phrase: t("Set the brightness of {device} to {
|
|
81530
|
+
phrase: t("Set the brightness of {device} to {level}", "Imposta la luminosità di {device} a {level}"),
|
|
80944
81531
|
icon: "sun-medium",
|
|
80945
81532
|
openArgs: [{
|
|
80946
|
-
key: "
|
|
81533
|
+
key: "level",
|
|
80947
81534
|
label: PERCENT,
|
|
80948
81535
|
offer: {
|
|
80949
81536
|
kind: "number",
|
|
@@ -80957,13 +81544,13 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
80957
81544
|
],
|
|
80958
81545
|
state: [{
|
|
80959
81546
|
kind: "numeric",
|
|
80960
|
-
field: "
|
|
81547
|
+
field: "level",
|
|
80961
81548
|
quantity: t("the brightness", "la luminosità"),
|
|
80962
81549
|
label: t("Brightness", "Luminosità"),
|
|
80963
81550
|
unit: "%",
|
|
80964
81551
|
icon: "sun"
|
|
80965
81552
|
}],
|
|
80966
|
-
events: { onBrightnessChanged: { notOperatorFacing: "the `
|
|
81553
|
+
events: { onBrightnessChanged: { notOperatorFacing: "the `level` state trigger reads the same change" } }
|
|
80967
81554
|
},
|
|
80968
81555
|
color: {
|
|
80969
81556
|
scope: "device",
|
|
@@ -80977,7 +81564,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
80977
81564
|
icon: "sun",
|
|
80978
81565
|
args: { color: {
|
|
80979
81566
|
mode: "mired",
|
|
80980
|
-
|
|
81567
|
+
colorTemperature: 370
|
|
80981
81568
|
} }
|
|
80982
81569
|
},
|
|
80983
81570
|
{
|
|
@@ -80988,7 +81575,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
80988
81575
|
icon: "snowflake",
|
|
80989
81576
|
args: { color: {
|
|
80990
81577
|
mode: "mired",
|
|
80991
|
-
|
|
81578
|
+
colorTemperature: 200
|
|
80992
81579
|
} }
|
|
80993
81580
|
},
|
|
80994
81581
|
{
|
|
@@ -81602,7 +82189,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
81602
82189
|
label: t("Fan off", "Ventilatore spento"),
|
|
81603
82190
|
phrase: t("Stop {device}", "Ferma {device}"),
|
|
81604
82191
|
icon: "power-off",
|
|
81605
|
-
args: {
|
|
82192
|
+
args: { speed: 0 }
|
|
81606
82193
|
},
|
|
81607
82194
|
{
|
|
81608
82195
|
id: "fan.full",
|
|
@@ -81610,16 +82197,16 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
81610
82197
|
label: t("Fan full", "Ventilatore al massimo"),
|
|
81611
82198
|
phrase: t("Run {device} at full speed", "Porta {device} alla massima velocità"),
|
|
81612
82199
|
icon: "fan",
|
|
81613
|
-
args: {
|
|
82200
|
+
args: { speed: 100 }
|
|
81614
82201
|
},
|
|
81615
82202
|
{
|
|
81616
82203
|
id: "fan.speed",
|
|
81617
82204
|
method: "setPercentage",
|
|
81618
82205
|
label: t("Set speed", "Imposta la velocità"),
|
|
81619
|
-
phrase: t("Set the speed of {device} to {
|
|
82206
|
+
phrase: t("Set the speed of {device} to {speed}", "Imposta la velocità di {device} al {speed}"),
|
|
81620
82207
|
icon: "fan",
|
|
81621
82208
|
openArgs: [{
|
|
81622
|
-
key: "
|
|
82209
|
+
key: "speed",
|
|
81623
82210
|
label: t("Speed", "Velocità"),
|
|
81624
82211
|
offer: {
|
|
81625
82212
|
kind: "number",
|
|
@@ -81681,7 +82268,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
81681
82268
|
],
|
|
81682
82269
|
state: [{
|
|
81683
82270
|
kind: "numeric",
|
|
81684
|
-
field: "
|
|
82271
|
+
field: "speed",
|
|
81685
82272
|
quantity: t("the speed", "la velocità"),
|
|
81686
82273
|
label: t("Speed", "Velocità"),
|
|
81687
82274
|
unit: "%",
|
|
@@ -82479,7 +83066,7 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
82479
83066
|
},
|
|
82480
83067
|
{
|
|
82481
83068
|
kind: "numeric",
|
|
82482
|
-
field: "
|
|
83069
|
+
field: "progress",
|
|
82483
83070
|
quantity: t("the cycle progress", "l’avanzamento del lavaggio"),
|
|
82484
83071
|
label: t("Progress", "Avanzamento"),
|
|
82485
83072
|
unit: "%",
|
|
@@ -82837,10 +83424,10 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
82837
83424
|
id: "media.seek",
|
|
82838
83425
|
method: "seek",
|
|
82839
83426
|
label: t("Seek", "Vai al punto"),
|
|
82840
|
-
phrase: t("Move {device} to {
|
|
83427
|
+
phrase: t("Move {device} to {position}", "Porta {device} al punto {position}"),
|
|
82841
83428
|
icon: "fast-forward",
|
|
82842
83429
|
openArgs: [{
|
|
82843
|
-
key: "
|
|
83430
|
+
key: "position",
|
|
82844
83431
|
label: t("Position", "Posizione"),
|
|
82845
83432
|
offer: {
|
|
82846
83433
|
kind: "number",
|
|
@@ -83889,7 +84476,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83889
84476
|
state: [
|
|
83890
84477
|
{
|
|
83891
84478
|
kind: "numeric",
|
|
83892
|
-
field: "
|
|
84479
|
+
field: "co2",
|
|
83893
84480
|
quantity: t("the CO₂", "la CO₂"),
|
|
83894
84481
|
label: t("CO₂", "CO₂"),
|
|
83895
84482
|
unit: "ppm",
|
|
@@ -83897,7 +84484,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83897
84484
|
},
|
|
83898
84485
|
{
|
|
83899
84486
|
kind: "numeric",
|
|
83900
|
-
field: "
|
|
84487
|
+
field: "voc",
|
|
83901
84488
|
quantity: t("the VOC level", "il livello di COV"),
|
|
83902
84489
|
label: t("VOC", "COV"),
|
|
83903
84490
|
unit: "ppb",
|
|
@@ -83933,7 +84520,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83933
84520
|
noun: t("Light level", "Luminosità ambiente"),
|
|
83934
84521
|
state: [{
|
|
83935
84522
|
kind: "numeric",
|
|
83936
|
-
field: "
|
|
84523
|
+
field: "illuminance",
|
|
83937
84524
|
quantity: t("the light level", "la luminosità"),
|
|
83938
84525
|
label: t("Illuminance", "Illuminamento"),
|
|
83939
84526
|
unit: "lx",
|
|
@@ -84136,7 +84723,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84136
84723
|
noun: t("Humidity", "Umidità"),
|
|
84137
84724
|
state: [{
|
|
84138
84725
|
kind: "numeric",
|
|
84139
|
-
field: "
|
|
84726
|
+
field: "humidity",
|
|
84140
84727
|
quantity: t("the humidity", "l’umidità"),
|
|
84141
84728
|
label: t("Humidity", "Umidità"),
|
|
84142
84729
|
unit: "%",
|
|
@@ -84184,7 +84771,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84184
84771
|
state: [
|
|
84185
84772
|
{
|
|
84186
84773
|
kind: "numeric",
|
|
84187
|
-
field: "
|
|
84774
|
+
field: "power",
|
|
84188
84775
|
quantity: t("the power draw", "il consumo"),
|
|
84189
84776
|
label: t("Power", "Potenza"),
|
|
84190
84777
|
unit: "W",
|
|
@@ -84192,7 +84779,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84192
84779
|
},
|
|
84193
84780
|
{
|
|
84194
84781
|
kind: "numeric",
|
|
84195
|
-
field: "
|
|
84782
|
+
field: "energy",
|
|
84196
84783
|
quantity: t("the energy used", "l’energia consumata"),
|
|
84197
84784
|
label: t("Energy", "Energia"),
|
|
84198
84785
|
unit: "kWh",
|
|
@@ -84200,7 +84787,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84200
84787
|
},
|
|
84201
84788
|
{
|
|
84202
84789
|
kind: "numeric",
|
|
84203
|
-
field: "
|
|
84790
|
+
field: "voltage",
|
|
84204
84791
|
quantity: t("the voltage", "la tensione"),
|
|
84205
84792
|
label: t("Voltage", "Tensione"),
|
|
84206
84793
|
unit: "V",
|
|
@@ -84208,7 +84795,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84208
84795
|
},
|
|
84209
84796
|
{
|
|
84210
84797
|
kind: "numeric",
|
|
84211
|
-
field: "
|
|
84798
|
+
field: "current",
|
|
84212
84799
|
quantity: t("the current", "la corrente"),
|
|
84213
84800
|
label: t("Current", "Corrente"),
|
|
84214
84801
|
unit: "A",
|
|
@@ -84225,13 +84812,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84225
84812
|
label: t("Where", "Posizione"),
|
|
84226
84813
|
phrase: t("When {device} is at {value}", "Quando {device} è in {value}"),
|
|
84227
84814
|
icon: "map-pin"
|
|
84228
|
-
}, {
|
|
84229
|
-
kind: "numeric",
|
|
84230
|
-
field: "batteryPercent",
|
|
84231
|
-
quantity: t("the phone battery", "la batteria del telefono"),
|
|
84232
|
-
label: t("Battery", "Batteria"),
|
|
84233
|
-
unit: "%",
|
|
84234
|
-
icon: "battery"
|
|
84235
84815
|
}]
|
|
84236
84816
|
},
|
|
84237
84817
|
"pressure-sensor": {
|
|
@@ -84239,7 +84819,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84239
84819
|
noun: t("Pressure", "Pressione"),
|
|
84240
84820
|
state: [{
|
|
84241
84821
|
kind: "numeric",
|
|
84242
|
-
field: "
|
|
84822
|
+
field: "pressure",
|
|
84243
84823
|
quantity: t("the pressure", "la pressione"),
|
|
84244
84824
|
label: t("Pressure", "Pressione"),
|
|
84245
84825
|
unit: "hPa",
|
|
@@ -84275,7 +84855,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84275
84855
|
noun: t("Temperature", "Temperatura"),
|
|
84276
84856
|
state: [{
|
|
84277
84857
|
kind: "numeric",
|
|
84278
|
-
field: "
|
|
84858
|
+
field: "temperature",
|
|
84279
84859
|
quantity: t("the temperature", "la temperatura"),
|
|
84280
84860
|
label: t("Temperature", "Temperatura"),
|
|
84281
84861
|
unit: "°C",
|
|
@@ -84346,7 +84926,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84346
84926
|
state: [
|
|
84347
84927
|
{
|
|
84348
84928
|
kind: "numeric",
|
|
84349
|
-
field: "
|
|
84929
|
+
field: "level",
|
|
84350
84930
|
quantity: t("the battery level", "il livello della batteria"),
|
|
84351
84931
|
label: t("Battery", "Batteria"),
|
|
84352
84932
|
unit: "%",
|
|
@@ -84388,7 +84968,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84388
84968
|
icon: "battery-charging"
|
|
84389
84969
|
}
|
|
84390
84970
|
],
|
|
84391
|
-
events: { onStatusChanged: { notOperatorFacing: "the
|
|
84971
|
+
events: { onStatusChanged: { notOperatorFacing: "the level / sleeping / charging state triggers each read one field of this change" } },
|
|
84392
84972
|
extraEvents: [{
|
|
84393
84973
|
category: EventCategory.DeviceAwake,
|
|
84394
84974
|
label: t("Woke up", "Risvegliato"),
|
|
@@ -84406,7 +84986,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84406
84986
|
noun: t("Network link", "Collegamento di rete"),
|
|
84407
84987
|
state: [{
|
|
84408
84988
|
kind: "numeric",
|
|
84409
|
-
field: "
|
|
84989
|
+
field: "signal",
|
|
84410
84990
|
quantity: t("the signal strength", "l’intensità del segnale"),
|
|
84411
84991
|
label: t("Signal", "Segnale"),
|
|
84412
84992
|
unit: "%",
|
|
@@ -84499,6 +85079,8 @@ var ML = "model and training machinery — no device action";
|
|
|
84499
85079
|
var INTERNAL = "internal plumbing between addons — never operator-facing";
|
|
84500
85080
|
/** Every system-scoped cap, with why it is not a device's vocabulary. */
|
|
84501
85081
|
var SYSTEM_CAP_VOCABULARY = {
|
|
85082
|
+
"action-source": system(INTERNAL),
|
|
85083
|
+
actions: system("declared actions — run from the Actions page and from the cameras that link them"),
|
|
84502
85084
|
"addon-pages": system(UI_PLUMBING),
|
|
84503
85085
|
"addon-pages-source": system(UI_PLUMBING),
|
|
84504
85086
|
"addon-routes": system(UI_PLUMBING),
|
|
@@ -84695,6 +85277,31 @@ Object.freeze({
|
|
|
84695
85277
|
form: "single",
|
|
84696
85278
|
optional: false
|
|
84697
85279
|
}],
|
|
85280
|
+
"actions.get": [{
|
|
85281
|
+
name: "deviceId",
|
|
85282
|
+
form: "single",
|
|
85283
|
+
optional: true
|
|
85284
|
+
}],
|
|
85285
|
+
"actions.getLinks": [{
|
|
85286
|
+
name: "deviceId",
|
|
85287
|
+
form: "single",
|
|
85288
|
+
optional: false
|
|
85289
|
+
}],
|
|
85290
|
+
"actions.listForCamera": [{
|
|
85291
|
+
name: "deviceId",
|
|
85292
|
+
form: "single",
|
|
85293
|
+
optional: false
|
|
85294
|
+
}],
|
|
85295
|
+
"actions.run": [{
|
|
85296
|
+
name: "deviceId",
|
|
85297
|
+
form: "single",
|
|
85298
|
+
optional: true
|
|
85299
|
+
}],
|
|
85300
|
+
"actions.setLinks": [{
|
|
85301
|
+
name: "deviceId",
|
|
85302
|
+
form: "single",
|
|
85303
|
+
optional: false
|
|
85304
|
+
}],
|
|
84698
85305
|
"addonSettings.getDeviceSettings": [{
|
|
84699
85306
|
name: "deviceId",
|
|
84700
85307
|
form: "single",
|
|
@@ -89738,6 +90345,7 @@ var BackgroundRunRegistry = class {
|
|
|
89738
90345
|
}
|
|
89739
90346
|
}
|
|
89740
90347
|
};
|
|
90348
|
+
String.raw`(?<=^|["'(\s>,\[{])`;
|
|
89741
90349
|
var MB = 1024 * 1024;
|
|
89742
90350
|
var DEFAULT_POOL_MEMORY_POLICY = {
|
|
89743
90351
|
sampleIntervalMs: 6e4,
|