@camstack/addon-provider-bosch 0.1.47 → 0.1.48

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.
@@ -802,7 +802,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
802
802
  return EventCategory;
803
803
  }({});
804
804
  //#endregion
805
- //#region ../types/dist/composed-stable-id-DLcPInGv.mjs
805
+ //#region ../types/dist/composed-stable-id-jnvhwGoH.mjs
806
806
  /**
807
807
  import { errMsg } from '@camstack/types'
808
808
  * Extract a human-readable message from an unknown error value.
@@ -1090,6 +1090,10 @@ var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
1090
1090
  /** Robot mower exposes targeted mowing (all-area / zones / edges /
1091
1091
  * spots) — gates the Mow action + map selectors. */
1092
1092
  DeviceFeature["MowerHasTargetedMowing"] = "mower-has-targeted-mowing";
1093
+ /** The device has a drive/navigation surface (`navigation` cap): a robot camera. */
1094
+ DeviceFeature["Navigation"] = "navigation";
1095
+ /** The device has a network-link reading (`network-link` cap). */
1096
+ DeviceFeature["NetworkLink"] = "network-link";
1093
1097
  return DeviceFeature;
1094
1098
  }({});
1095
1099
  /**
@@ -6022,7 +6026,7 @@ var ZodIssueCode = {
6022
6026
  var ZodFirstPartyTypeKind;
6023
6027
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
6024
6028
  //#endregion
6025
- //#region ../types/dist/sleep-B36hHDDz.mjs
6029
+ //#region ../types/dist/sleep-Dz1P6--1.mjs
6026
6030
  /**
6027
6031
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6028
6032
  * window to float samples (D455).
@@ -10109,15 +10113,52 @@ var PeerBytesTicketSchema = object({
10109
10113
  */
10110
10114
  declaredBytes: number$1().int().nonnegative().nullable()
10111
10115
  });
10112
- discriminatedUnion("kind", [object({
10113
- kind: literal("action"),
10114
- actionId: string(),
10115
- runId: string(),
10116
- automationId: string().optional()
10117
- }), object({
10118
- kind: literal("scheduler"),
10119
- schedulerId: string()
10120
- })]);
10116
+ /**
10117
+ * The match a notification rule fired on (D705). Carried as a command origin so an
10118
+ * Action the rule starts can press `alarm-panel.trigger` as that match, not as an
10119
+ * anonymous press (D735). The same fields a rule fire ref freezes.
10120
+ */
10121
+ var RuleFireOriginSchema = object({
10122
+ ruleId: string(),
10123
+ ruleName: string(),
10124
+ deviceId: number$1().int(),
10125
+ sourceDeviceId: number$1().int().optional(),
10126
+ recordId: string(),
10127
+ timestamp: number$1(),
10128
+ trackId: string().optional(),
10129
+ eventId: string().optional(),
10130
+ className: string().optional(),
10131
+ label: string().optional(),
10132
+ zones: array(string()).optional(),
10133
+ confidence: number$1().optional(),
10134
+ sensorChange: object({
10135
+ name: string(),
10136
+ kind: string(),
10137
+ state: string()
10138
+ }).optional(),
10139
+ extraStills: array(object({
10140
+ ownerId: string(),
10141
+ cameraId: number$1().int()
10142
+ })).optional()
10143
+ });
10144
+ discriminatedUnion("kind", [
10145
+ object({
10146
+ kind: literal("action"),
10147
+ actionId: string(),
10148
+ runId: string(),
10149
+ automationId: string().optional(),
10150
+ /** The rule fire that started this run, when one did (D705). */
10151
+ ruleFire: RuleFireOriginSchema.optional()
10152
+ }),
10153
+ object({
10154
+ kind: literal("scheduler"),
10155
+ schedulerId: string()
10156
+ }),
10157
+ object({
10158
+ kind: literal("rule"),
10159
+ fire: RuleFireOriginSchema
10160
+ })
10161
+ ]);
10121
10162
  /**
10122
10163
  * One recorded device transition (D1022): a status field of a device went from
10123
10164
  * one value to another, with who or what asked for it.
@@ -17412,7 +17453,7 @@ Object.freeze({
17412
17453
  }
17413
17454
  });
17414
17455
  //#endregion
17415
- //#region ../types/dist/composition-BFJq1Y88.mjs
17456
+ //#region ../types/dist/implemented-methods-OitwyO1Y.mjs
17416
17457
  /**
17417
17458
  * The ffmpeg build every CamStack node downloads, per platform and arch.
17418
17459
  *
@@ -19352,18 +19393,43 @@ var TargetKindLevelSchema = object({
19352
19393
  requires: array(string()).optional(),
19353
19394
  description: string().optional()
19354
19395
  });
19396
+ /** Attachment capabilities for a kind (drives the degrade engine + test panel). */
19397
+ var TargetKindAttachmentsCapsSchema = object({
19398
+ mediaTypes: array(AttachmentMediaTypeSchema),
19399
+ mode: _enum([
19400
+ "url",
19401
+ "bytes",
19402
+ "both"
19403
+ ]),
19404
+ max: number$1().int().nonnegative(),
19405
+ maxBytes: number$1().int().positive().optional()
19406
+ });
19407
+ /**
19408
+ * Which TEXT fields a kind delivers (#483). Alexa speaks a title and nothing
19409
+ * else; a push service shows both.
19410
+ *
19411
+ * `.optional()` on the caps block, never defaulted: absent = both, which is
19412
+ * what every kind declared before this field meant (D938's rule for a Zod
19413
+ * default on the addon cap path).
19414
+ */
19415
+ var TargetKindTextCapsSchema = object({
19416
+ title: boolean(),
19417
+ body: boolean()
19418
+ });
19419
+ _enum([
19420
+ "title",
19421
+ "body",
19422
+ "attachments",
19423
+ "actions",
19424
+ "priority",
19425
+ "sound",
19426
+ "clickUrl"
19427
+ ]);
19355
19428
  /** The full capability block consulted before dispatch. */
19356
19429
  var TargetKindCapsSchema = object({
19357
- attachments: object({
19358
- mediaTypes: array(AttachmentMediaTypeSchema),
19359
- mode: _enum([
19360
- "url",
19361
- "bytes",
19362
- "both"
19363
- ]),
19364
- max: number$1().int().nonnegative(),
19365
- maxBytes: number$1().int().positive().optional()
19366
- }),
19430
+ /** Text fields this kind delivers (#483). Absent = title AND body. */
19431
+ text: TargetKindTextCapsSchema.optional(),
19432
+ attachments: TargetKindAttachmentsCapsSchema,
19367
19433
  /** Max action buttons (0 = none). */
19368
19434
  actions: number$1().int().nonnegative(),
19369
19435
  /**
@@ -44487,30 +44553,21 @@ function convertLegacyWhen(half) {
44487
44553
  * (instants) and state leaves (durations). It replaces the flat trigger list
44488
44554
  * plus the separate condition tree; the firing rule is in that file and in
44489
44555
  * ADR "one tree".
44490
- * - **Actions** — `NcRuleActionSchema`'s two steps, plus the `{kind:'code'}`
44491
- * fragment of §3.2.2. See {@link AutomationActionSchema} for the ONE place
44492
- * this had to diverge from "verbatim", and why.
44556
+ * - **Actions** — the `wait` and `cap` steps, plus the `{kind:'code'}`
44557
+ * fragment of §3.2.2. See {@link AutomationActionSchema}.
44493
44558
  *
44494
44559
  * A recipe stored in the old shape (`triggers` + `conditions`) still LOADS:
44495
44560
  * {@link AutomationRecipeSchema} (the parse-anywhere schema) converts it on parse. Nothing writes it.
44496
44561
  */
44497
44562
  /**
44498
- * One action step.
44499
- *
44500
- * `wait` and `cap` are `NcRuleActionSchema`'s two members, kept structurally
44501
- * identical so `NcRuleActionRunner` runs them unchanged — its device-scope
44502
- * check, stop-at-first-failure and per-sequence throttle are the whole reason
44503
- * to reuse it, and none of them are re-implemented here.
44563
+ * One action step: `wait`, or a `cap` call.
44504
44564
  *
44505
- * **The one divergence, and it is forced.** `NcRuleActionSchema.cap.deviceId` is
44506
- * a literal `z.number().int()`, and the NC runner's own `RunSequencesInput`
44507
- * documents its subject device as *"for the log tag, never for routing"*. So an
44508
- * NC action can never target the device that triggered it — which is fine for
44509
- * the NC (its rules already scope to a device) and fatal for an automation
44510
- * ("sound the siren of the camera that saw the person"). `deviceId` therefore
44511
- * also accepts `{ $var }`, resolved from the run's `vars` bag BEFORE the runner
44512
- * is called. The runner still receives a number and is untouched; the
44513
- * resolution is the recipe's job, not the runner's.
44565
+ * A cap step's target is who it acts on (D983: `devices`, a `domain`, or a
44566
+ * `{ $var }` resolved from the run's variables); the legacy `deviceId` is still
44567
+ * READ, never written. The step runner (`runSteps`) owns the device-scope
44568
+ * check, the stop-at-first-failure and the variable substitution, once, for
44569
+ * every caller — automations, Actions, and the notification centre, which runs
44570
+ * only Actions (planning#473).
44514
44571
  */
44515
44572
  var AutomationWaitStepSchema = object({
44516
44573
  kind: literal("wait"),
@@ -45128,6 +45185,8 @@ var ActionStatusSchema = object({
45128
45185
  /** The latest run's failure; null on success or when it never ran. */
45129
45186
  lastError: string().nullable()
45130
45187
  });
45188
+ /** The throttle window of an action, in seconds; absent or 0 = no throttle. */
45189
+ var ActionMinDelaySecSchema = number$1().int().min(0).max(86400);
45131
45190
  var ActionEntrySchema = object({
45132
45191
  /** `internal:<uuid>` or `<addonId>:<localId>`. */
45133
45192
  id: string().min(3),
@@ -45140,6 +45199,14 @@ var ActionEntrySchema = object({
45140
45199
  /** Internal only: cap and wait steps. No action-in-action, so no cycles. */
45141
45200
  steps: array(ActionStepSchema).min(1).max(50).optional(),
45142
45201
  variables: array(ActionVariableSchema).max(20).optional(),
45202
+ /**
45203
+ * Internal only: the least time between two run STARTS. A run that begins
45204
+ * inside the window is skipped (`skipped-cooldown`), traced and logged. It
45205
+ * is an actuator's budget — "how often may this gate physically open" —
45206
+ * not a notification cooldown, and it is shared by every caller of the
45207
+ * action (two rules, a button, an automation).
45208
+ */
45209
+ minDelaySec: ActionMinDelaySecSchema.optional(),
45143
45210
  status: ActionStatusSchema
45144
45211
  }).superRefine((entry, ctx) => {
45145
45212
  if (entry.source === "internal") {
@@ -45170,7 +45237,8 @@ var ActionEntrySchema = object({
45170
45237
  var ActionInputSchema = object({
45171
45238
  name: string().min(1).max(120),
45172
45239
  steps: array(ActionStepSchema).min(1).max(50),
45173
- variables: array(ActionVariableSchema).max(20).optional()
45240
+ variables: array(ActionVariableSchema).max(20).optional(),
45241
+ minDelaySec: ActionMinDelaySecSchema.optional()
45174
45242
  });
45175
45243
  /** Who started a run. Absent = the operator pressed it. */
45176
45244
  var ActionRunOriginSchema = object({
@@ -49330,14 +49398,14 @@ var climateControlCapability = {
49330
49398
  kind: "mutation",
49331
49399
  auth: "protected"
49332
49400
  }),
49333
- setFanMode: method(object({
49401
+ setFanMode: optionalMethod(object({
49334
49402
  deviceId: number$1().int().nonnegative(),
49335
49403
  fanMode: string().min(1)
49336
49404
  }), _void(), {
49337
49405
  kind: "mutation",
49338
49406
  auth: "protected"
49339
49407
  }),
49340
- setPreset: method(object({
49408
+ setPreset: optionalMethod(object({
49341
49409
  deviceId: number$1().int().nonnegative(),
49342
49410
  preset: string().min(1)
49343
49411
  }), _void(), {
@@ -49351,7 +49419,7 @@ var climateControlCapability = {
49351
49419
  kind: "mutation",
49352
49420
  auth: "protected"
49353
49421
  }),
49354
- setTargetRange: method(object({
49422
+ setTargetRange: optionalMethod(object({
49355
49423
  deviceId: number$1().int().nonnegative(),
49356
49424
  targetLow: number$1(),
49357
49425
  targetHigh: number$1()
@@ -49359,21 +49427,21 @@ var climateControlCapability = {
49359
49427
  kind: "mutation",
49360
49428
  auth: "protected"
49361
49429
  }),
49362
- setTargetHumidity: method(object({
49430
+ setTargetHumidity: optionalMethod(object({
49363
49431
  deviceId: number$1().int().nonnegative(),
49364
49432
  targetHumidity: number$1().min(0).max(100)
49365
49433
  }), _void(), {
49366
49434
  kind: "mutation",
49367
49435
  auth: "protected"
49368
49436
  }),
49369
- setSwingVertical: method(object({
49437
+ setSwingVertical: optionalMethod(object({
49370
49438
  deviceId: number$1().int().nonnegative(),
49371
49439
  on: boolean()
49372
49440
  }), _void(), {
49373
49441
  kind: "mutation",
49374
49442
  auth: "protected"
49375
49443
  }),
49376
- setSwingHorizontal: method(object({
49444
+ setSwingHorizontal: optionalMethod(object({
49377
49445
  deviceId: number$1().int().nonnegative(),
49378
49446
  on: boolean()
49379
49447
  }), _void(), {
@@ -50632,27 +50700,27 @@ var mediaPlayerCapability = {
50632
50700
  mode: "singleton",
50633
50701
  deviceTypes: [DeviceType.MediaPlayer],
50634
50702
  methods: {
50635
- turnOn: method(deviceOnly, _void(), {
50703
+ turnOn: optionalMethod(deviceOnly, _void(), {
50636
50704
  kind: "mutation",
50637
50705
  auth: "protected"
50638
50706
  }),
50639
- turnOff: method(deviceOnly, _void(), {
50707
+ turnOff: optionalMethod(deviceOnly, _void(), {
50640
50708
  kind: "mutation",
50641
50709
  auth: "protected"
50642
50710
  }),
50643
- volumeUp: method(stepInput, _void(), {
50711
+ volumeUp: optionalMethod(stepInput, _void(), {
50644
50712
  kind: "mutation",
50645
50713
  auth: "protected"
50646
50714
  }),
50647
- volumeDown: method(stepInput, _void(), {
50715
+ volumeDown: optionalMethod(stepInput, _void(), {
50648
50716
  kind: "mutation",
50649
50717
  auth: "protected"
50650
50718
  }),
50651
- channelUp: method(stepInput, _void(), {
50719
+ channelUp: optionalMethod(stepInput, _void(), {
50652
50720
  kind: "mutation",
50653
50721
  auth: "protected"
50654
50722
  }),
50655
- channelDown: method(stepInput, _void(), {
50723
+ channelDown: optionalMethod(stepInput, _void(), {
50656
50724
  kind: "mutation",
50657
50725
  auth: "protected"
50658
50726
  }),
@@ -50664,61 +50732,61 @@ var mediaPlayerCapability = {
50664
50732
  kind: "mutation",
50665
50733
  auth: "protected"
50666
50734
  }),
50667
- stop: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
50735
+ stop: optionalMethod(object({ deviceId: number$1().int().nonnegative() }), _void(), {
50668
50736
  kind: "mutation",
50669
50737
  auth: "protected"
50670
50738
  }),
50671
- next: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
50739
+ next: optionalMethod(object({ deviceId: number$1().int().nonnegative() }), _void(), {
50672
50740
  kind: "mutation",
50673
50741
  auth: "protected"
50674
50742
  }),
50675
- previous: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
50743
+ previous: optionalMethod(object({ deviceId: number$1().int().nonnegative() }), _void(), {
50676
50744
  kind: "mutation",
50677
50745
  auth: "protected"
50678
50746
  }),
50679
- seek: method(object({
50747
+ seek: optionalMethod(object({
50680
50748
  deviceId: number$1().int().nonnegative(),
50681
50749
  position: number$1().int().nonnegative()
50682
50750
  }), _void(), {
50683
50751
  kind: "mutation",
50684
50752
  auth: "protected"
50685
50753
  }),
50686
- setVolume: method(object({
50754
+ setVolume: optionalMethod(object({
50687
50755
  deviceId: number$1().int().nonnegative(),
50688
50756
  volumeLevel: number$1().min(0).max(100)
50689
50757
  }), _void(), {
50690
50758
  kind: "mutation",
50691
50759
  auth: "protected"
50692
50760
  }),
50693
- setMute: method(object({
50761
+ setMute: optionalMethod(object({
50694
50762
  deviceId: number$1().int().nonnegative(),
50695
50763
  muted: boolean()
50696
50764
  }), _void(), {
50697
50765
  kind: "mutation",
50698
50766
  auth: "protected"
50699
50767
  }),
50700
- setShuffle: method(object({
50768
+ setShuffle: optionalMethod(object({
50701
50769
  deviceId: number$1().int().nonnegative(),
50702
50770
  shuffle: boolean()
50703
50771
  }), _void(), {
50704
50772
  kind: "mutation",
50705
50773
  auth: "protected"
50706
50774
  }),
50707
- setRepeat: method(object({
50775
+ setRepeat: optionalMethod(object({
50708
50776
  deviceId: number$1().int().nonnegative(),
50709
50777
  repeat: MediaPlayerRepeatSchema
50710
50778
  }), _void(), {
50711
50779
  kind: "mutation",
50712
50780
  auth: "protected"
50713
50781
  }),
50714
- selectSource: method(object({
50782
+ selectSource: optionalMethod(object({
50715
50783
  deviceId: number$1().int().nonnegative(),
50716
50784
  source: string().min(1)
50717
50785
  }), _void(), {
50718
50786
  kind: "mutation",
50719
50787
  auth: "protected"
50720
50788
  }),
50721
- playMedia: method(object({
50789
+ playMedia: optionalMethod(object({
50722
50790
  deviceId: number$1().int().nonnegative(),
50723
50791
  /** Media identifier / URL. */
50724
50792
  mediaId: string().min(1),
@@ -51740,18 +51808,18 @@ var coverCapability = {
51740
51808
  kind: "mutation",
51741
51809
  auth: "protected"
51742
51810
  }),
51743
- stop: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
51811
+ stop: optionalMethod(object({ deviceId: number$1().int().nonnegative() }), _void(), {
51744
51812
  kind: "mutation",
51745
51813
  auth: "protected"
51746
51814
  }),
51747
- setPosition: method(object({
51815
+ setPosition: optionalMethod(object({
51748
51816
  deviceId: number$1().int().nonnegative(),
51749
51817
  position: number$1().min(0).max(100)
51750
51818
  }), _void(), {
51751
51819
  kind: "mutation",
51752
51820
  auth: "protected"
51753
51821
  }),
51754
- setTiltPosition: method(object({
51822
+ setTiltPosition: optionalMethod(object({
51755
51823
  deviceId: number$1().int().nonnegative(),
51756
51824
  tiltPosition: number$1().min(0).max(100)
51757
51825
  }), _void(), {
@@ -52781,6 +52849,22 @@ method(InstancePinSchema, DeviceExportStatusSchema), method(_void(), array(Expor
52781
52849
  });
52782
52850
  var DeviceAliasSchema = string().max(64).regex(/^[a-z][a-z0-9_]*$/);
52783
52851
  var DeviceTemplateSchema = string().min(1).max(4096);
52852
+ /** One value a caller hands the renderer for `thisDevice`. */
52853
+ var DeviceTemplateValueSchema = union([
52854
+ string(),
52855
+ number$1(),
52856
+ boolean()
52857
+ ]);
52858
+ /**
52859
+ * The device a render is FOR (`camera` in the text) and the values the caller
52860
+ * knows about it that no capability carries, for example `lastPerson` and
52861
+ * `lastPlate`. `values` read as `camera.<name>`; a name a capability also carries
52862
+ * is `ambiguous` and is written `camera.values.<name>`.
52863
+ */
52864
+ var DeviceTemplateThisDeviceSchema = object({
52865
+ deviceId: number$1().int(),
52866
+ values: record(string().min(1).max(64), DeviceTemplateValueSchema).optional()
52867
+ });
52784
52868
  var DeviceTemplateRefusalSchema = object({
52785
52869
  reason: _enum([
52786
52870
  "too-long",
@@ -53412,7 +53496,9 @@ var DeviceBindingsForDeviceSchema = object({
53412
53496
  kind: _enum(["native", "wrapped"]),
53413
53497
  providerAddonId: string(),
53414
53498
  providerNodeId: string(),
53415
- nativeAddonId: string()
53499
+ nativeAddonId: string(),
53500
+ /** The cap's methods the native provider implements; absent = all. */
53501
+ implementedMethods: array(string()).optional()
53416
53502
  }))
53417
53503
  });
53418
53504
  /**
@@ -53655,17 +53741,24 @@ method(object({
53655
53741
  auth: "admin"
53656
53742
  }), method(object({
53657
53743
  templates: array(DeviceTemplateSchema).max(64),
53658
- allowedDeviceIds: array(number$1().int()).optional()
53744
+ allowedDeviceIds: array(number$1().int()).optional(),
53745
+ /** The device `camera` names in the texts, and the values the caller knows of it. */
53746
+ thisDevice: DeviceTemplateThisDeviceSchema.optional()
53659
53747
  }), object({ results: array(DeviceTemplateRenderSchema) }), { auth: "admin" }), method(object({
53660
53748
  templates: array(string()).max(64),
53661
- allowedDeviceIds: array(number$1().int()).optional()
53749
+ allowedDeviceIds: array(number$1().int()).optional(),
53750
+ thisDevice: DeviceTemplateThisDeviceSchema.optional()
53662
53751
  }), object({ results: array(discriminatedUnion("ok", [object({
53663
53752
  ok: literal(true),
53664
53753
  aliases: array(object({
53665
53754
  alias: string(),
53666
53755
  deviceId: number$1().int().nullable(),
53667
- allowed: boolean()
53668
- }))
53756
+ allowed: boolean(),
53757
+ /** The fields the text reads on this alias, as written (`temperature`, `cap.field`). */
53758
+ reads: array(string())
53759
+ })),
53760
+ /** Whether the text reads the clock (`now`): it changes every minute. */
53761
+ readsClock: boolean()
53669
53762
  }), object({
53670
53763
  ok: literal(false),
53671
53764
  refusal: DeviceTemplateRefusalSchema
@@ -56387,28 +56480,28 @@ var fanControlCapability = {
56387
56480
  mode: "singleton",
56388
56481
  deviceTypes: [DeviceType.Fan],
56389
56482
  methods: {
56390
- setPercentage: method(object({
56483
+ setPercentage: optionalMethod(object({
56391
56484
  deviceId: number$1().int().nonnegative(),
56392
56485
  speed: number$1().min(0).max(100)
56393
56486
  }), _void(), {
56394
56487
  kind: "mutation",
56395
56488
  auth: "protected"
56396
56489
  }),
56397
- setPreset: method(object({
56490
+ setPreset: optionalMethod(object({
56398
56491
  deviceId: number$1().int().nonnegative(),
56399
56492
  preset: string().min(1)
56400
56493
  }), _void(), {
56401
56494
  kind: "mutation",
56402
56495
  auth: "protected"
56403
56496
  }),
56404
- setDirection: method(object({
56497
+ setDirection: optionalMethod(object({
56405
56498
  deviceId: number$1().int().nonnegative(),
56406
56499
  direction: FanDirectionSchema
56407
56500
  }), _void(), {
56408
56501
  kind: "mutation",
56409
56502
  auth: "protected"
56410
56503
  }),
56411
- setOscillating: method(object({
56504
+ setOscillating: optionalMethod(object({
56412
56505
  deviceId: number$1().int().nonnegative(),
56413
56506
  oscillating: boolean()
56414
56507
  }), _void(), {
@@ -60513,7 +60606,7 @@ var lockControlCapability = {
60513
60606
  kind: "mutation",
60514
60607
  auth: "protected"
60515
60608
  }),
60516
- open: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
60609
+ open: optionalMethod(object({ deviceId: number$1().int().nonnegative() }), _void(), {
60517
60610
  kind: "mutation",
60518
60611
  auth: "protected"
60519
60612
  })
@@ -61710,7 +61803,7 @@ object({
61710
61803
  deviceId: number$1().int().optional(),
61711
61804
  atBefore: number$1().optional(),
61712
61805
  where: RecordWhereSchema.optional()
61713
- }), object({ count: number$1().int().nonnegative() }), object({}), object({ store: Rows }), object({ patch: Rows }), object({}), object({ keys: array(string().min(1)) }), object({ removed: array(string()) }), object({ refs: array(string()) }), object({ values: record(string(), string().nullable()) }), object({
61806
+ }), object({ count: number$1().int().nonnegative() }), object({}), object({ store: Rows }), object({ patch: Rows }), object({}), object({ keys: array(string().min(1)) }), object({ removed: array(string()) }), object({}), object({ deviceIds: array(number$1().int()) }), object({ deviceIds: array(number$1().int()) }), object({ blobs: record(string(), Rows) }), object({ refs: array(string()) }), object({ values: record(string(), string().nullable()) }), object({
61714
61807
  ref: string().min(1),
61715
61808
  value: string()
61716
61809
  }), object({}), object({ refs: array(string()) }), object({ deleted: number$1().int().nonnegative() }), object({}), object({ integrations: array(MigrationIntegrationSchema) }), object({ id: string().min(1) }), MigrationIntegrationSchema.nullable(), object({
@@ -61721,7 +61814,7 @@ object({
61721
61814
  integrationId: string().nullable(),
61722
61815
  /** Whether the device carries any stored config; its content is not offered. */
61723
61816
  hasConfig: boolean()
61724
- }).nullable(), object({
61817
+ }).nullable(), object({ deviceIds: array(number$1().int()) }), object({ aliases: record(string(), string()) }), object({
61725
61818
  deviceId: number$1().int(),
61726
61819
  integrationId: string().min(1)
61727
61820
  }), object({}), object({}), object({ nodeId: string() }), object({}), object({});
@@ -68999,92 +69092,21 @@ var NcZoneConditionSchema = object({
68999
69092
  * membership lists are OR within the list (spec §2.3).
69000
69093
  */
69001
69094
  /**
69002
- * What a rule may actuate.
69003
- *
69004
- * **No hand-maintained allowlist** (operator decision, and the right one — a
69005
- * written list of methods is a third parallel map to keep aligned, and this
69006
- * repo has paid for those). The boundary instead comes from a property the
69007
- * capabilities already carry: an action may target only a **device-scoped**
69008
- * capability method.
69009
- *
69010
- * That is not decoration. A rule can be authored by a NON-ADMIN — personal
69011
- * rules are a supported flow — and the executor runs with the addon's
69012
- * privileges, so an unbounded action is an arbitrary RPC channel with a
69013
- * privilege escalation attached. Restricting to device scope excludes the
69014
- * system caps (`device-manager.removeDevice` and friends) by construction,
69015
- * costs nothing to maintain, and cannot rot: a cap that stops being
69016
- * device-scoped stops being actuatable in the same change.
69017
- *
69018
- * The executor enforces it; {@link NcRuleActionSchema} carries the intent.
69019
- */
69020
- /**
69021
- * One step of a sequence.
69095
+ * What a rule or a button runs: an **Action** of the `actions` surface
69096
+ * (`internal:<uuid>` or an addon's), by id, and nothing else (planning#473).
69022
69097
  *
69023
- * `wait` is a first-class step rather than a property of the next action: it is
69024
- * what makes a sequence a SEQUENCE and not a list — "unlock, wait 5s, open"
69025
- * cannot be expressed otherwise.
69098
+ * The notification centre has no step vocabulary of its own. The steps, the
69099
+ * device-scope boundary, the stop-at-first-failure, the throttle
69100
+ * (`minDelaySec`), the variables and the runs ledger all belong to the Action;
69101
+ * an operator edits them in ONE place (the Actions page) and a rule points at
69102
+ * the result. A rule can be authored by a non-admin (personal rules), which is
69103
+ * safe for the same reason: it can only name an Action an admin already wrote.
69026
69104
  */
69027
- var NcRuleActionSchema = discriminatedUnion("kind", [object({
69028
- kind: literal("wait"),
69029
- seconds: number$1().min(0).max(300)
69030
- }), object({
69031
- kind: literal("cap"),
69032
- /**
69033
- * WHO the step acts on (D983) — the only shape that is written. A sequence
69034
- * stored before D983 carries `deviceId`; the sequence store reads it as a
69035
- * `devices` target.
69036
- */
69037
- target: ActionTargetSchema.optional(),
69038
- /** The vocabulary action the step performs; required for a `domain` target. */
69039
- actionId: string().min(1).optional(),
69040
- /** @deprecated The pre-D983 single device. Read, never written. */
69041
- deviceId: number$1().int().optional(),
69042
- /** Capability name, e.g. `alarm-panel`. */
69043
- cap: string().min(1),
69044
- /** Method on it. The executor refuses a non-device-scoped cap. */
69045
- method: string().min(1),
69046
- /** Method arguments, minus `deviceId` (the executor injects it). */
69047
- args: record(string(), unknown()).optional()
69048
- }).refine((step) => step.target !== void 0 || step.deviceId !== void 0, {
69049
- message: "a cap step needs a target",
69050
- path: ["target"]
69051
- }).refine((step) => step.target?.kind !== "domain" || step.actionId !== void 0, {
69052
- message: "a domain target needs the vocabulary action it applies to (actionId)",
69053
- path: ["actionId"]
69054
- })]);
69055
- /**
69056
- * A named, ordered run of steps shared across rules, with its own throttle.
69057
- *
69058
- * Sequences live in the notification centre's sequence store — never inline on
69059
- * a rule. A rule binds to one by id ({@link NcActionBindingSchema}), and a
69060
- * button names one the same way. `minDelaySec` exists because a noisy rule
69061
- * otherwise hammers a physical actuator — the rule's own cooldown governs
69062
- * NOTIFICATIONS, which is a different budget from "how often may this gate
69063
- * actually open". The throttle key is the sequence id, so two rules sharing
69064
- * one sequence share its budget.
69065
- */
69066
- var NcSharedSequenceSchema = object({
69067
- id: string().min(1),
69068
- name: string().min(1).max(120),
69069
- minDelaySec: number$1().int().min(0).max(86400).optional(),
69070
- actions: array(NcRuleActionSchema).min(1)
69071
- });
69072
- /** Create / update body — the id is minted by the provider. */
69073
- var NcSharedSequenceInputSchema = object({
69074
- name: string().min(1).max(120),
69075
- minDelaySec: number$1().int().min(0).max(86400).optional(),
69076
- actions: array(NcRuleActionSchema).min(1)
69077
- });
69078
- /** Bindings on one hook edge. Cap keeps a slot from becoming a second sequence editor. */
69079
- var NcHookBindingsSchema = array(discriminatedUnion("kind", [object({
69080
- kind: literal("sequence"),
69081
- sequenceId: string().min(1)
69082
- }), object({
69083
- kind: literal("do"),
69084
- action: NcRuleActionSchema
69085
- })])).max(4);
69105
+ var NcActionIdSchema = string().min(1);
69106
+ /** Action ids one hook edge runs, in order. Capped so a slot never becomes a second editor. */
69107
+ var NcHookActionIdsSchema = array(NcActionIdSchema).max(4);
69086
69108
  /**
69087
- * One button carried by the notification, running a shared sequence on tap.
69109
+ * One button carried by the notification, running an Action on tap.
69088
69110
  *
69089
69111
  * **Read this before adding a button that does something physical.** The tap
69090
69112
  * arrives over a link that travelled through third-party infrastructure — ntfy,
@@ -69099,9 +69121,9 @@ var NcRuleNotificationButtonSchema = object({
69099
69121
  /** Stable id — travels in the callback and identifies the button in logs. */
69100
69122
  id: string().min(1).max(64),
69101
69123
  label: string().min(1).max(40),
69102
- /** Id of a shared sequence. The dispatcher drops a button whose sequence
69103
- * does not exist rather than minting a token for nothing. */
69104
- sequenceId: string().min(1),
69124
+ /** The Action the tap runs. The dispatcher drops a button whose Action does
69125
+ * not exist rather than minting a token for nothing. */
69126
+ actionId: NcActionIdSchema,
69105
69127
  icon: NotificationActionIconSchema.optional(),
69106
69128
  destructive: boolean().optional()
69107
69129
  });
@@ -69116,25 +69138,19 @@ var NcRuleNotificationButtonSchema = object({
69116
69138
  * leave). A delivery with no clear edge never produces this hook.
69117
69139
  */
69118
69140
  var NcRuleActionsSchema = object({
69119
- onActivation: NcHookBindingsSchema.optional(),
69120
- onDeactivation: NcHookBindingsSchema.optional(),
69141
+ onActivation: NcHookActionIdsSchema.optional(),
69142
+ onDeactivation: NcHookActionIdsSchema.optional(),
69121
69143
  /** Runs on a positive / raised match. */
69122
- onTrigger: NcHookBindingsSchema.optional(),
69144
+ onTrigger: NcHookActionIdsSchema.optional(),
69123
69145
  /** Runs on a clear / leave match, when the subject carries one. */
69124
- onTriggerOff: NcHookBindingsSchema.optional(),
69146
+ onTriggerOff: NcHookActionIdsSchema.optional(),
69125
69147
  /**
69126
- * Buttons the NOTIFICATION carries, each running one shared sequence when
69127
- * tapped. Deliberately a REFERENCE — a button that could define its own
69128
- * actions would be a parallel actuation vocabulary.
69148
+ * Buttons the NOTIFICATION carries, each running one Action when tapped.
69149
+ * Deliberately a REFERENCE — a button that could define its own steps would
69150
+ * be a parallel actuation vocabulary.
69129
69151
  */
69130
69152
  buttons: array(NcRuleNotificationButtonSchema).max(8).optional()
69131
69153
  });
69132
- object({
69133
- name: string().min(1).max(120),
69134
- enabled: boolean(),
69135
- minDelaySec: number$1().int().min(0).max(86400).optional(),
69136
- actions: array(NcRuleActionSchema).min(1)
69137
- });
69138
69154
  /**
69139
69155
  * "This rule applies only while `deviceId` is in one of `states`."
69140
69156
  *
@@ -69433,6 +69449,16 @@ var NcRuleTargetSchema = object({
69433
69449
  */
69434
69450
  params: record(string(), unknown()).optional()
69435
69451
  });
69452
+ var NcTargetOverrideSchema = object({
69453
+ template: object({
69454
+ title: string().max(500).optional(),
69455
+ body: string().max(2e3).optional()
69456
+ }).optional(),
69457
+ schedule: NcScheduleSchema.optional(),
69458
+ priority: number$1().int().min(1).max(5).optional()
69459
+ });
69460
+ /** Per-target settings keyed by target id (#487). */
69461
+ var NcTargetOverridesSchema = record(string(), NcTargetOverrideSchema);
69436
69462
  /**
69437
69463
  * WHAT THE NOTIFICATION'S PICTURE IS (D897) — the ONE media choice of a rule.
69438
69464
  *
@@ -69714,6 +69740,13 @@ var NcRuleInputSchema = object({
69714
69740
  * targets.
69715
69741
  */
69716
69742
  targetUsers: array(string()).optional(),
69743
+ /**
69744
+ * Per-target settings keyed by target id (#487): texts, schedule, priority.
69745
+ * Absent (and an absent entry) = the rule's own values. A patch that omits
69746
+ * the key keeps the stored map; a patch that names it REPLACES it whole —
69747
+ * `{}` empties it.
69748
+ */
69749
+ targetOverrides: NcTargetOverridesSchema.optional(),
69717
69750
  /** Absent = the kind's default picture (`resolveNcMediaImage`): the subject crop for a
69718
69751
  * detection, the clean scene for a sensor or a sound. Set explicitly on save (D897). */
69719
69752
  media: NcMediaPolicySchema.default({}),
@@ -70815,18 +70848,6 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
70815
70848
  }), object({ success: literal(true) }), {
70816
70849
  kind: "mutation",
70817
70850
  auth: "admin"
70818
- }), method(object({}), object({ sequences: array(NcSharedSequenceSchema) }), { auth: "admin" }), method(object({ sequenceId: string().min(1) }), object({ sequence: NcSharedSequenceSchema.nullable() }), { auth: "admin" }), method(object({ sequence: NcSharedSequenceInputSchema }), object({ sequence: NcSharedSequenceSchema }), {
70819
- kind: "mutation",
70820
- auth: "admin"
70821
- }), method(object({
70822
- sequenceId: string().min(1),
70823
- sequence: NcSharedSequenceInputSchema
70824
- }), object({ sequence: NcSharedSequenceSchema }), {
70825
- kind: "mutation",
70826
- auth: "admin"
70827
- }), method(object({ sequenceId: string().min(1) }), object({ success: literal(true) }), {
70828
- kind: "mutation",
70829
- auth: "admin"
70830
70851
  }), method(object({}), NcClipRetentionPlanSchema, { auth: "admin" }), method(object({}), object({ mutedDeviceIds: array(number$1().int()).readonly() }), { auth: "admin" }), method(object({
70831
70852
  deviceId: number$1().int(),
70832
70853
  muted: boolean()
@@ -71265,53 +71286,41 @@ DeviceType.Camera, method(object({
71265
71286
  deviceId: number$1(),
71266
71287
  status: OsdStatusSchema
71267
71288
  });
71268
- _enum([
71269
- "value",
71270
- "unit",
71271
- "full"
71272
- ]);
71273
- _enum([
71274
- "value+unit",
71275
- "value",
71276
- "unit"
71277
- ]);
71278
71289
  /**
71279
- * How the operator reached the leaf device. `deviceId` is ALWAYS the
71280
- * OSD-supported leaf that is read; `containerId` is set when the pick
71281
- * went through a container (gateway) first.
71290
+ * `osd-manager` — the ORCHESTRATOR over the device-scope `osd` cap.
71291
+ *
71292
+ * The `osd` cap is the firmware contract: it probes a camera's overlay
71293
+ * SLOTS and writes literal text into one. It has no idea WHERE that text
71294
+ * comes from, and it must not — a driver that grew a "show the temperature
71295
+ * here" feature would grow it once per vendor.
71296
+ *
71297
+ * This cap owns the other half: a per-(camera, slot) BINDING that says
71298
+ * which value feeds the slot, how it is formatted, and under which
71299
+ * conditions it is shown at all. Named TEMPLATES combine many device
71300
+ * fields into one overlay string (plugin catalog OSD Manager parity).
71282
71301
  */
71283
- var OsdTemplatePickSchema = object({
71284
- containerId: number$1().int().optional(),
71285
- deviceId: number$1().int()
71286
- });
71287
71302
  /**
71288
- * One named binding inside a multi-device template: device path + unit
71289
- * selection + precision. The parser expands `{alias}`, `{alias.value}`,
71290
- * `{alias.unit}`, or `{alias.full}` from the same binding — there is no
71291
- * per-binding format lock.
71303
+ * The text of a named template: a device template (D1021) —
71304
+ * `{{ camera.temperature | round(1) }}`, `{{ now | time('HH:mm') }}`,
71305
+ * `{% if camera.motion %}MOTION{% endif %}` — rendered by the ONE hub renderer
71306
+ * (`device-manager.renderDeviceTemplates`), never by this addon.
71307
+ *
71308
+ * Two names belong to the render rather than to a device:
71309
+ * - `now` is the clock; `time('HH:mm')` prints it in the server's zone.
71310
+ * - `camera` is the camera the overlay is on, so one template serves every
71311
+ * camera. `camera.lastPerson` and `camera.lastPlate` are the most recent
71312
+ * recognition persisted for it (empty text until there is one, with
71313
+ * `| default('')`).
71292
71314
  */
71293
- var OsdTemplateBindingSchema = object({
71294
- /** Token stem in the parser, e.g. `t` → `{t}` / `{t.value}`. Unique within the template. */
71295
- alias: string().min(1).max(32).regex(/^[A-Za-z][A-Za-z0-9_-]*$/, "alias must start with a letter"),
71296
- pick: OsdTemplatePickSchema,
71297
- capName: string().min(1).max(64),
71298
- valuePath: string().min(1).max(64),
71299
- /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
71300
- displayUnit: string().max(16).optional(),
71301
- maxDecimals: number$1().int().min(0).max(4).default(1),
71302
- /** Raw value → display text (same shape as slot binding). Empty string hides. */
71303
- valueMap: record(string(), string()).optional()
71304
- });
71315
+ var OSD_TEMPLATE_TEXT_MAX = 1024;
71305
71316
  /**
71306
- * A named template: bindings (alias → leaf field) + a parser that
71307
- * references `{alias}` / `{alias.value}` / `{alias.unit}` / `{alias.full}`.
71317
+ * A named template: the unit of reuse. A slot points at one by id; editing it
71318
+ * changes every slot that points at it, on every camera.
71308
71319
  */
71309
71320
  var OsdNamedTemplateSchema = object({
71310
71321
  id: string().min(1).max(64),
71311
71322
  name: string().min(1).max(64),
71312
- bindings: array(OsdTemplateBindingSchema).max(32).default([]),
71313
- /** Parser with alias placeholders, e.g. `{t.value} {t.unit} / {h}`. */
71314
- parser: string().max(256).default("")
71323
+ text: string().max(OSD_TEMPLATE_TEXT_MAX).default("")
71315
71324
  });
71316
71325
  /** Where a slot's value comes from. */
71317
71326
  var OsdSourceSchema = discriminatedUnion("kind", [
@@ -71320,26 +71329,6 @@ var OsdSourceSchema = discriminatedUnion("kind", [
71320
71329
  kind: literal("static"),
71321
71330
  text: string().max(64)
71322
71331
  }),
71323
- object({
71324
- kind: literal("clock"),
71325
- /** Token pattern: `YYYY MM DD HH mm ss`. Everything else is literal. */
71326
- pattern: string().min(1).max(32).default("HH:mm"),
71327
- /** IANA zone. Omitted = the server's zone. */
71328
- timezone: string().min(1).max(64).optional()
71329
- }),
71330
- object({
71331
- kind: literal("device-state"),
71332
- deviceId: number$1().int().optional(),
71333
- capName: string().min(1).max(64),
71334
- /** Dot path inside the slice, e.g. `detected`, `value`, `mode`. */
71335
- valuePath: string().min(1).max(64),
71336
- /** Convert TO this unit at render. Absent = no conversion. */
71337
- displayUnit: string().max(16).optional()
71338
- }),
71339
- object({
71340
- kind: literal("latest-recognition"),
71341
- recognition: _enum(["person", "plate"])
71342
- }),
71343
71332
  object({
71344
71333
  kind: literal("template"),
71345
71334
  templateId: string().min(1).max(64)
@@ -71349,15 +71338,6 @@ var OsdSlotBindingSchema = object({
71349
71338
  /** Off = the manager stops driving this slot. It does NOT clear it. */
71350
71339
  enabled: boolean().default(true),
71351
71340
  source: OsdSourceSchema,
71352
- /** `${value}` and `${unit}` are substituted; every occurrence. */
71353
- template: string().max(96).default("${value}"),
71354
- /**
71355
- * Decimal places for a numeric value. `0` yields an integer — the
71356
- * documented workaround for firmwares that reject `.` in overlay text.
71357
- */
71358
- maxDecimals: number$1().int().min(0).max(4).default(1),
71359
- /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
71360
- valueMap: record(string(), string()).optional(),
71361
71341
  /** Time windows in which the slot is shown. Absent = always. */
71362
71342
  schedule: NcScheduleSchema.optional(),
71363
71343
  /**
@@ -71399,31 +71379,21 @@ var OsdRenderResultSchema = object({
71399
71379
  /** Why, whenever the outcome is not a plain write. Never silent. */
71400
71380
  reason: string().optional()
71401
71381
  });
71402
- var OsdSourceValueTypeEnum = _enum([
71403
- "number",
71404
- "boolean",
71405
- "string",
71406
- "enum"
71407
- ]);
71408
71382
  /**
71409
- * One bindable value, derived from a cap's `runtimeState` schema — never
71410
- * hand-listed. The editor renders from this, so a cap that ships a new
71411
- * state field becomes bindable with no UI change.
71383
+ * A template rendered for one camera without being saved: what the editor
71384
+ * previews. `text` is what the overlay would carry; a refused render has a
71385
+ * `reason` and an empty text.
71412
71386
  */
71413
- var OsdSourceOptionSchema = object({
71414
- deviceId: number$1().int(),
71415
- deviceName: string(),
71416
- capName: string(),
71417
- valuePath: string(),
71418
- label: string(),
71419
- valueType: OsdSourceValueTypeEnum,
71420
- /** Present for `enum`; the editor offers these as `valueMap` keys. */
71421
- enumValues: array(string()).readonly().optional()
71387
+ var OsdTemplatePreviewSchema = object({
71388
+ ok: boolean(),
71389
+ text: string(),
71390
+ /** The refusal, or `ref: reason` per value that printed `—`. */
71391
+ notes: array(string())
71422
71392
  });
71423
71393
  method(object({ deviceId: number$1().int() }), object({
71424
71394
  supported: boolean(),
71425
71395
  slots: array(OsdSlotViewSchema)
71426
- }), { auth: "admin" }), method(object({ deviceId: number$1().int() }), object({ sources: array(OsdSourceOptionSchema) }), { auth: "admin" }), method(object({}), object({
71396
+ }), { auth: "admin" }), method(object({}), object({
71427
71397
  supported: array(string()),
71428
71398
  catalog: array(NcConditionDescriptorSchema)
71429
71399
  }), { auth: "admin" }), method(object({
@@ -71465,6 +71435,12 @@ method(object({ deviceId: number$1().int() }), object({
71465
71435
  }), OsdRenderResultSchema, {
71466
71436
  kind: "mutation",
71467
71437
  auth: "admin"
71438
+ }), method(object({
71439
+ deviceId: number$1().int(),
71440
+ text: string().max(OSD_TEMPLATE_TEXT_MAX)
71441
+ }), OsdTemplatePreviewSchema, {
71442
+ kind: "mutation",
71443
+ auth: "admin"
71468
71444
  }), method(object({ deviceId: number$1().int() }), object({ results: array(OsdRenderResultSchema) }), {
71469
71445
  kind: "mutation",
71470
71446
  auth: "admin"
@@ -81064,7 +81040,7 @@ var valveCapability = {
81064
81040
  kind: "mutation",
81065
81041
  auth: "protected"
81066
81042
  }),
81067
- setPosition: method(object({
81043
+ setPosition: optionalMethod(object({
81068
81044
  deviceId: number$1().int().nonnegative(),
81069
81045
  position: number$1().min(0).max(100)
81070
81046
  }), _void(), {
@@ -92369,13 +92345,6 @@ Object.freeze({
92369
92345
  access: "create",
92370
92346
  role: "admin"
92371
92347
  },
92372
- "notificationRules.createSequence": {
92373
- capName: "notification-rules",
92374
- capScope: "system",
92375
- addonId: null,
92376
- access: "create",
92377
- role: "admin"
92378
- },
92379
92348
  "notificationRules.createSnooze": {
92380
92349
  capName: "notification-rules",
92381
92350
  capScope: "system",
@@ -92397,13 +92366,6 @@ Object.freeze({
92397
92366
  access: "delete",
92398
92367
  role: "admin"
92399
92368
  },
92400
- "notificationRules.deleteSequence": {
92401
- capName: "notification-rules",
92402
- capScope: "system",
92403
- addonId: null,
92404
- access: "delete",
92405
- role: "admin"
92406
- },
92407
92369
  "notificationRules.getAlarmConfig": {
92408
92370
  capName: "notification-rules",
92409
92371
  capScope: "system",
@@ -92453,13 +92415,6 @@ Object.freeze({
92453
92415
  access: "view",
92454
92416
  role: "admin"
92455
92417
  },
92456
- "notificationRules.getSequence": {
92457
- capName: "notification-rules",
92458
- capScope: "system",
92459
- addonId: null,
92460
- access: "view",
92461
- role: "admin"
92462
- },
92463
92418
  "notificationRules.getTemplateCatalog": {
92464
92419
  capName: "notification-rules",
92465
92420
  capScope: "system",
@@ -92481,13 +92436,6 @@ Object.freeze({
92481
92436
  access: "view",
92482
92437
  role: "admin"
92483
92438
  },
92484
- "notificationRules.listSequences": {
92485
- capName: "notification-rules",
92486
- capScope: "system",
92487
- addonId: null,
92488
- access: "view",
92489
- role: "admin"
92490
- },
92491
92439
  "notificationRules.listSnoozes": {
92492
92440
  capName: "notification-rules",
92493
92441
  capScope: "system",
@@ -92558,13 +92506,6 @@ Object.freeze({
92558
92506
  access: "create",
92559
92507
  role: "admin"
92560
92508
  },
92561
- "notificationRules.updateSequence": {
92562
- capName: "notification-rules",
92563
- capScope: "system",
92564
- addonId: null,
92565
- access: "create",
92566
- role: "admin"
92567
- },
92568
92509
  "notifier.cancel": {
92569
92510
  capName: "notifier",
92570
92511
  capScope: "device",
@@ -92649,21 +92590,21 @@ Object.freeze({
92649
92590
  access: "view",
92650
92591
  role: "admin"
92651
92592
  },
92652
- "osdManager.getSourceCatalog": {
92593
+ "osdManager.listTemplates": {
92653
92594
  capName: "osd-manager",
92654
92595
  capScope: "system",
92655
92596
  addonId: null,
92656
92597
  access: "view",
92657
92598
  role: "admin"
92658
92599
  },
92659
- "osdManager.listTemplates": {
92600
+ "osdManager.previewSlot": {
92660
92601
  capName: "osd-manager",
92661
92602
  capScope: "system",
92662
92603
  addonId: null,
92663
- access: "view",
92604
+ access: "create",
92664
92605
  role: "admin"
92665
92606
  },
92666
- "osdManager.previewSlot": {
92607
+ "osdManager.previewTemplate": {
92667
92608
  capName: "osd-manager",
92668
92609
  capScope: "system",
92669
92610
  addonId: null,
@@ -97453,6 +97394,24 @@ function projectAction(cap, action) {
97453
97394
  Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
97454
97395
  DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.HeatPump, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.PetFountain, DeviceType.Heater, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Gateway;
97455
97396
  DeviceFeature.BatteryOperated;
97397
+ function bound(cap, methods = [], authority = "reported") {
97398
+ return {
97399
+ kind: "cap",
97400
+ cap,
97401
+ methods,
97402
+ authority
97403
+ };
97404
+ }
97405
+ function derived(cap, methods = []) {
97406
+ return bound(cap, methods, "derived");
97407
+ }
97408
+ DeviceFeature.BatteryOperated, DeviceFeature.Rebootable, derived("reboot", ["reboot"]), DeviceFeature.Resyncable, DeviceFeature.NativeSnapshot, DeviceFeature.DoorbellButton, derived("doorbell"), DeviceFeature.TwoWayAudio, derived("intercom", [
97409
+ "startTalkSession",
97410
+ "pushTalkAudio",
97411
+ "endTalkSession"
97412
+ ]), DeviceFeature.PanTiltZoom, derived("ptz"), DeviceFeature.PtzAutotrack, derived("ptz-autotrack"), DeviceFeature.MotionTrigger, derived("motion-trigger", ["setMotionTrigger"]), DeviceFeature.TimedRun, derived("timed-run", ["runFor"]), DeviceFeature.Switch, DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired, DeviceFeature.ClimateDualSetpoint, DeviceFeature.ClimateHumidity, DeviceFeature.ClimateFanMode, DeviceFeature.ClimatePreset, DeviceFeature.ClimateSwingVertical, DeviceFeature.ClimateSwingHorizontal, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.CoverStoppable, DeviceFeature.ValvePositionable, DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.LockPinRequired, DeviceFeature.LockOpen, DeviceFeature.MediaPlayerSeek, DeviceFeature.MediaPlayerVolume, DeviceFeature.MediaPlayerMute, DeviceFeature.MediaPlayerShuffle, DeviceFeature.MediaPlayerRepeat, DeviceFeature.MediaPlayerSelectSource, DeviceFeature.MediaPlayerPlayMedia, DeviceFeature.MediaPlayerNext, DeviceFeature.MediaPlayerPrevious, DeviceFeature.MediaPlayerStop, DeviceFeature.MediaPlayerVolumeStep, DeviceFeature.MediaPlayerChannelStep, DeviceFeature.MediaPlayerPower, DeviceFeature.AlarmPinRequired, DeviceFeature.PresenceGps, DeviceFeature.NotifierImage, DeviceFeature.NotifierPriority, DeviceFeature.NotifierData, DeviceFeature.NotifierActions, DeviceFeature.NotifierRecipients, DeviceFeature.ScriptVariables, DeviceFeature.AutomationSkipCondition, DeviceFeature.VacuumHasMap, DeviceFeature.VacuumHasAi, DeviceFeature.MowerHasMap, DeviceFeature.MowerHasTargetedMowing, DeviceFeature.Navigation, derived("navigation"), DeviceFeature.NetworkLink, derived("network-link");
97413
+ var ALL_FEATURES = Object.values(DeviceFeature);
97414
+ new Set(ALL_FEATURES);
97456
97415
  DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
97457
97416
  var HA_AS = "a power sensor (device_class power). Home Assistant has no laundry domain. running-state stays unexported until a null reading can be published as unavailable.";
97458
97417
  var HOMEKIT_REASON = "HomeKit has no laundry-appliance service. The export tab would pair an accessory with nothing on it: running-state is withheld until a null reading can be unavailable, and power is not a HomeKit service this export honours.";
@@ -99108,12 +99067,12 @@ Object.freeze({
99108
99067
  form: "single",
99109
99068
  optional: false
99110
99069
  }],
99111
- "osdManager.getSourceCatalog": [{
99070
+ "osdManager.previewSlot": [{
99112
99071
  name: "deviceId",
99113
99072
  form: "single",
99114
99073
  optional: false
99115
99074
  }],
99116
- "osdManager.previewSlot": [{
99075
+ "osdManager.previewTemplate": [{
99117
99076
  name: "deviceId",
99118
99077
  form: "single",
99119
99078
  optional: false