@camstack/addon-agent-ui 1.2.317 → 1.2.318

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/addon.js CHANGED
@@ -786,7 +786,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
786
786
  return EventCategory;
787
787
  }({});
788
788
  //#endregion
789
- //#region ../types/dist/device-type-CfHw_quR.mjs
789
+ //#region ../types/dist/device-type-D1fH5kaC.mjs
790
790
  /**
791
791
  import { errMsg } from '@camstack/types'
792
792
  * Extract a human-readable message from an unknown error value.
@@ -1017,6 +1017,12 @@ var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
1017
1017
  DeviceFeature["MediaPlayerPrevious"] = "media-player-previous";
1018
1018
  /** Media player exposes stop distinct from pause. */
1019
1019
  DeviceFeature["MediaPlayerStop"] = "media-player-stop";
1020
+ /** Media player exposes volume up / down in steps (an infrared TV has no level). */
1021
+ DeviceFeature["MediaPlayerVolumeStep"] = "media-player-volume-step";
1022
+ /** Media player exposes channel up / down in steps. */
1023
+ DeviceFeature["MediaPlayerChannelStep"] = "media-player-channel-step";
1024
+ /** Media player exposes power on / off. */
1025
+ DeviceFeature["MediaPlayerPower"] = "media-player-power";
1020
1026
  /** Alarm panel requires a PIN code on arm/disarm. */
1021
1027
  DeviceFeature["AlarmPinRequired"] = "alarm-pin-required";
1022
1028
  /** Presence device carries GPS coordinates (lat/lng/accuracy) in
@@ -5843,7 +5849,7 @@ var ZodIssueCode = {
5843
5849
  var ZodFirstPartyTypeKind;
5844
5850
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5845
5851
  //#endregion
5846
- //#region ../types/dist/sleep-hmSP-eJt.mjs
5852
+ //#region ../types/dist/sleep-BKClVk0K.mjs
5847
5853
  /**
5848
5854
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5849
5855
  * window to float samples (D455).
@@ -5922,6 +5928,22 @@ function buildAlawTable() {
5922
5928
  }
5923
5929
  buildUlawTable();
5924
5930
  buildAlawTable();
5931
+ /**
5932
+ * An addon whose own migrations did not apply refuses to initialise (D987). The error is typed
5933
+ * so a runner hosting several addons can tell "this addon is blocked" from a crash and keep its
5934
+ * co-located siblings running. Recognised by NAME and shape, never `instanceof`: a forked addon
5935
+ * bundles its own copy of this module, so the class the runner sees is not the one that threw.
5936
+ */
5937
+ var MIGRATIONS_BLOCKED_ERROR_NAME = "AddonMigrationsBlockedError";
5938
+ var AddonMigrationsBlockedError = class extends Error {
5939
+ /** The ledger ids that did not apply and block the owner. */
5940
+ migrationIds;
5941
+ constructor(migrationIds) {
5942
+ super(`migration(s) ${migrationIds.join(", ")} did not apply and block this addon — fix or retry them (migrations.retry), then restart it`);
5943
+ this.name = MIGRATIONS_BLOCKED_ERROR_NAME;
5944
+ this.migrationIds = migrationIds;
5945
+ }
5946
+ };
5925
5947
  /** Is this field's stored value a credential? */
5926
5948
  function isSecretConfigField(field) {
5927
5949
  if (field.type === "password") return true;
@@ -7528,7 +7550,7 @@ var BaseAddon = class {
7528
7550
  startMigration: (input) => api.startMigration.mutate(input),
7529
7551
  finishMigration: (input) => api.finishMigration.mutate(input)
7530
7552
  }, migrations, this.ctx.logger);
7531
- if (report.blockOwner.length > 0) throw new Error(`migration(s) ${report.blockOwner.join(", ")} did not apply and block this addon — fix or retry them (migrations.retry), then restart it`);
7553
+ if (report.blockOwner.length > 0) throw new AddonMigrationsBlockedError(report.blockOwner);
7532
7554
  return report;
7533
7555
  }
7534
7556
  /**
@@ -11283,7 +11305,7 @@ object({
11283
11305
  params: record(string(), union([string(), number()])).optional()
11284
11306
  });
11285
11307
  //#endregion
11286
- //#region ../types/dist/composition-Dh3RfMx5.mjs
11308
+ //#region ../types/dist/composition-BodkvOV0.mjs
11287
11309
  /**
11288
11310
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11289
11311
  *
@@ -12420,7 +12442,14 @@ var CompositionForwardCommandSchema = object({
12420
12442
  method: string().min(1),
12421
12443
  args: record(string().min(1), CompositionForwardArgSchema).optional()
12422
12444
  });
12423
- var CompositionCommandTargetSchema = discriminatedUnion("kind", [CompositionForwardCommandSchema, CompositionCodeSourceSchema]);
12445
+ var CompositionCommandTargetSchema = discriminatedUnion("kind", [
12446
+ CompositionForwardCommandSchema,
12447
+ CompositionCodeSourceSchema,
12448
+ object({
12449
+ kind: literal("extension"),
12450
+ target: literal("remote")
12451
+ })
12452
+ ]);
12424
12453
  /** An item key inside an item-array cap (`consumables.items[<key>]`). */
12425
12454
  var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
12426
12455
  /**
@@ -18927,6 +18956,48 @@ var APPLIANCE_CAP_VOCABULARY = {
18927
18956
  scope: "device",
18928
18957
  noun: t("Media player", "Lettore multimediale"),
18929
18958
  actions: [
18959
+ {
18960
+ id: "media.turnOn",
18961
+ method: "turnOn",
18962
+ label: t("Turn on", "Accendi"),
18963
+ phrase: t("Turn on {device}", "Accendi {device}"),
18964
+ icon: "power"
18965
+ },
18966
+ {
18967
+ id: "media.turnOff",
18968
+ method: "turnOff",
18969
+ label: t("Turn off", "Spegni"),
18970
+ phrase: t("Turn off {device}", "Spegni {device}"),
18971
+ icon: "power"
18972
+ },
18973
+ {
18974
+ id: "media.volumeUp",
18975
+ method: "volumeUp",
18976
+ label: t("Volume up", "Alza il volume"),
18977
+ phrase: t("Raise the volume of {device}", "Alza il volume di {device}"),
18978
+ icon: "volume-2"
18979
+ },
18980
+ {
18981
+ id: "media.volumeDown",
18982
+ method: "volumeDown",
18983
+ label: t("Volume down", "Abbassa il volume"),
18984
+ phrase: t("Lower the volume of {device}", "Abbassa il volume di {device}"),
18985
+ icon: "volume-2"
18986
+ },
18987
+ {
18988
+ id: "media.channelUp",
18989
+ method: "channelUp",
18990
+ label: t("Channel up", "Canale successivo"),
18991
+ phrase: t("Go to the next channel on {device}", "Passa al canale successivo su {device}"),
18992
+ icon: "skip-forward"
18993
+ },
18994
+ {
18995
+ id: "media.channelDown",
18996
+ method: "channelDown",
18997
+ label: t("Channel down", "Canale precedente"),
18998
+ phrase: t("Go to the previous channel on {device}", "Torna al canale precedente su {device}"),
18999
+ icon: "skip-back"
19000
+ },
18930
19001
  {
18931
19002
  id: "media.play",
18932
19003
  method: "play",
@@ -47377,6 +47448,188 @@ DeviceType.Control, method(object({
47377
47448
  kind: "mutation",
47378
47449
  auth: "protected"
47379
47450
  });
47451
+ /**
47452
+ * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
47453
+ * Apple TV, Spotify, Roku, generic OTT receivers, …) on
47454
+ * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
47455
+ * surface — those use `DeviceType.Camera` + the broker pipeline.
47456
+ *
47457
+ * The cap declares a wide method surface; not every backend supports
47458
+ * every method. Drivers signal sub-capability via the
47459
+ * `DeviceFeature.MediaPlayerXxx` flags (paired one-to-one with the
47460
+ * corresponding method) so the UI gates buttons without a slice
47461
+ * fetch — same pattern as `PanTiltZoom` for cameras.
47462
+ */
47463
+ var MediaPlayerStateSchema = _enum([
47464
+ "off",
47465
+ "on",
47466
+ "idle",
47467
+ "playing",
47468
+ "paused",
47469
+ "buffering",
47470
+ "standby"
47471
+ ]);
47472
+ var MediaPlayerRepeatSchema = _enum([
47473
+ "off",
47474
+ "all",
47475
+ "one"
47476
+ ]);
47477
+ var MediaInfoSchema = object({
47478
+ /** Free-form media kind (`music`, `tvshow`, `movie`, `app`, `channel`,
47479
+ * `podcast`, …). */
47480
+ type: string(),
47481
+ /** Human-readable title. */
47482
+ title: string(),
47483
+ /** Optional artist / channel / station label. */
47484
+ artist: string().optional(),
47485
+ /** Optional album / season / show name. */
47486
+ album: string().optional(),
47487
+ /** Optional cover-art / thumbnail URL. */
47488
+ imageUrl: string().optional()
47489
+ });
47490
+ /**
47491
+ * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
47492
+ * the device said so. `assumed`: the driver has no feedback (infrared) and
47493
+ * tracks what it last SENT; it moves only after a send was accepted, and a
47494
+ * human at the real remote makes it wrong. A UI shows an assumed value as a
47495
+ * guess, never as a reading.
47496
+ */
47497
+ var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
47498
+ /** The fields of a media-player status a driver can only guess. */
47499
+ var MediaPlayerAssumedFieldSchema = _enum([
47500
+ "state",
47501
+ "volumeLevel",
47502
+ "isMuted",
47503
+ "source"
47504
+ ]);
47505
+ var MediaPlayerStatusSchema = object({
47506
+ /** Playback lifecycle state. */
47507
+ state: MediaPlayerStateSchema,
47508
+ /**
47509
+ * Whether the state fields are readings or the driver's own bookkeeping.
47510
+ * A slice written before this field existed parses as `reported`.
47511
+ */
47512
+ stateSource: MediaPlayerStateSourceSchema.default("reported"),
47513
+ /**
47514
+ * Which fields are the driver's own guess. `stateSource` is `assumed` when
47515
+ * this is not empty; a field not listed here is a reading even then (power
47516
+ * from a running-state source, mute guessed from the last send).
47517
+ */
47518
+ assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
47519
+ /** Volume as 0..100 inclusive. Null when the device has no volume
47520
+ * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
47521
+ volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
47522
+ /** Mute toggle distinct from volume=0. Null when no mute surface.
47523
+ * Pair with `DeviceFeature.MediaPlayerMute`. */
47524
+ isMuted: boolean().nullable(),
47525
+ /** Active source / input. Empty when no source surface. */
47526
+ source: string(),
47527
+ /** Selectable sources. Empty when no source surface.
47528
+ * Pair with `DeviceFeature.MediaPlayerSelectSource`. */
47529
+ availableSources: array(string()),
47530
+ /** Currently-playing media info. Null when nothing is playing. */
47531
+ currentMedia: MediaInfoSchema.nullable(),
47532
+ /** Current playback position in ms. Null when not seekable or
47533
+ * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
47534
+ position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
47535
+ /** Total duration of the current media in ms. Null when unknown
47536
+ * (live stream) or nothing is playing. */
47537
+ duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
47538
+ /** Shuffle toggle. Null when no shuffle surface.
47539
+ * Pair with `DeviceFeature.MediaPlayerShuffle`. */
47540
+ shuffle: boolean().nullable(),
47541
+ /** Repeat mode. Null when no repeat surface.
47542
+ * Pair with `DeviceFeature.MediaPlayerRepeat`. */
47543
+ repeat: MediaPlayerRepeatSchema.nullable(),
47544
+ /** Ms epoch when the slice was last updated. */
47545
+ lastChangedAt: number()
47546
+ });
47547
+ var stepInput = object({
47548
+ deviceId: number().int().nonnegative(),
47549
+ /** How many presses: the caller's count (Alexa `volumeSteps`, `channelCount`). */
47550
+ steps: number().int().min(1).max(50).default(1)
47551
+ });
47552
+ var deviceOnly = object({ deviceId: number().int().nonnegative() });
47553
+ DeviceType.MediaPlayer, method(deviceOnly, _void(), {
47554
+ kind: "mutation",
47555
+ auth: "protected"
47556
+ }), method(deviceOnly, _void(), {
47557
+ kind: "mutation",
47558
+ auth: "protected"
47559
+ }), method(stepInput, _void(), {
47560
+ kind: "mutation",
47561
+ auth: "protected"
47562
+ }), method(stepInput, _void(), {
47563
+ kind: "mutation",
47564
+ auth: "protected"
47565
+ }), method(stepInput, _void(), {
47566
+ kind: "mutation",
47567
+ auth: "protected"
47568
+ }), method(stepInput, _void(), {
47569
+ kind: "mutation",
47570
+ auth: "protected"
47571
+ }), method(object({ deviceId: number().int().nonnegative() }), _void(), {
47572
+ kind: "mutation",
47573
+ auth: "protected"
47574
+ }), method(object({ deviceId: number().int().nonnegative() }), _void(), {
47575
+ kind: "mutation",
47576
+ auth: "protected"
47577
+ }), method(object({ deviceId: number().int().nonnegative() }), _void(), {
47578
+ kind: "mutation",
47579
+ auth: "protected"
47580
+ }), method(object({ deviceId: number().int().nonnegative() }), _void(), {
47581
+ kind: "mutation",
47582
+ auth: "protected"
47583
+ }), method(object({ deviceId: number().int().nonnegative() }), _void(), {
47584
+ kind: "mutation",
47585
+ auth: "protected"
47586
+ }), method(object({
47587
+ deviceId: number().int().nonnegative(),
47588
+ position: number().int().nonnegative()
47589
+ }), _void(), {
47590
+ kind: "mutation",
47591
+ auth: "protected"
47592
+ }), method(object({
47593
+ deviceId: number().int().nonnegative(),
47594
+ volumeLevel: number().min(0).max(100)
47595
+ }), _void(), {
47596
+ kind: "mutation",
47597
+ auth: "protected"
47598
+ }), method(object({
47599
+ deviceId: number().int().nonnegative(),
47600
+ muted: boolean()
47601
+ }), _void(), {
47602
+ kind: "mutation",
47603
+ auth: "protected"
47604
+ }), method(object({
47605
+ deviceId: number().int().nonnegative(),
47606
+ shuffle: boolean()
47607
+ }), _void(), {
47608
+ kind: "mutation",
47609
+ auth: "protected"
47610
+ }), method(object({
47611
+ deviceId: number().int().nonnegative(),
47612
+ repeat: MediaPlayerRepeatSchema
47613
+ }), _void(), {
47614
+ kind: "mutation",
47615
+ auth: "protected"
47616
+ }), method(object({
47617
+ deviceId: number().int().nonnegative(),
47618
+ source: string().min(1)
47619
+ }), _void(), {
47620
+ kind: "mutation",
47621
+ auth: "protected"
47622
+ }), method(object({
47623
+ deviceId: number().int().nonnegative(),
47624
+ /** Media identifier / URL. */
47625
+ mediaId: string().min(1),
47626
+ /** Media kind (`music`, `tvshow`, `movie`, `app`, …) — provider
47627
+ * passes it through to the upstream service. */
47628
+ mediaType: string().min(1)
47629
+ }), _void(), {
47630
+ kind: "mutation",
47631
+ auth: "protected"
47632
+ });
47380
47633
  DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Heater, DeviceType.Dryer, DeviceType.Gateway, DeviceType.Camera, DeviceType.Fan, DeviceType.Lock, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Gateway, DeviceType.Hub, DeviceType.Camera, DeviceType.Sensor, DeviceType.MediaPlayer, DeviceType.Vacuum, DeviceType.Generic, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.PetFountain, DeviceType.Fan, DeviceType.Humidifier, DeviceType.Climate, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder, DeviceType.Heater;
47381
47634
  var NUMBER = {
47382
47635
  kind: "fixed",
@@ -54859,164 +55112,6 @@ var LoginMethodContributionSchema = discriminatedUnion("kind", [
54859
55112
  ]);
54860
55113
  method(_void(), array(LoginMethodContributionSchema).readonly());
54861
55114
  /**
54862
- * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
54863
- * Apple TV, Spotify, Roku, generic OTT receivers, …) on
54864
- * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
54865
- * surface — those use `DeviceType.Camera` + the broker pipeline.
54866
- *
54867
- * The cap declares a wide method surface; not every backend supports
54868
- * every method. Drivers signal sub-capability via the
54869
- * `DeviceFeature.MediaPlayerXxx` flags (paired one-to-one with the
54870
- * corresponding method) so the UI gates buttons without a slice
54871
- * fetch — same pattern as `PanTiltZoom` for cameras.
54872
- */
54873
- var MediaPlayerStateSchema = _enum([
54874
- "off",
54875
- "on",
54876
- "idle",
54877
- "playing",
54878
- "paused",
54879
- "buffering",
54880
- "standby"
54881
- ]);
54882
- var MediaPlayerRepeatSchema = _enum([
54883
- "off",
54884
- "all",
54885
- "one"
54886
- ]);
54887
- var MediaInfoSchema = object({
54888
- /** Free-form media kind (`music`, `tvshow`, `movie`, `app`, `channel`,
54889
- * `podcast`, …). */
54890
- type: string(),
54891
- /** Human-readable title. */
54892
- title: string(),
54893
- /** Optional artist / channel / station label. */
54894
- artist: string().optional(),
54895
- /** Optional album / season / show name. */
54896
- album: string().optional(),
54897
- /** Optional cover-art / thumbnail URL. */
54898
- imageUrl: string().optional()
54899
- });
54900
- /**
54901
- * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
54902
- * the device said so. `assumed`: the driver has no feedback (infrared) and
54903
- * tracks what it last SENT; it moves only after a send was accepted, and a
54904
- * human at the real remote makes it wrong. A UI shows an assumed value as a
54905
- * guess, never as a reading.
54906
- */
54907
- var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
54908
- /** The fields of a media-player status a driver can only guess. */
54909
- var MediaPlayerAssumedFieldSchema = _enum([
54910
- "state",
54911
- "volumeLevel",
54912
- "isMuted",
54913
- "source"
54914
- ]);
54915
- object({
54916
- /** Playback lifecycle state. */
54917
- state: MediaPlayerStateSchema,
54918
- /**
54919
- * Whether the state fields are readings or the driver's own bookkeeping.
54920
- * A slice written before this field existed parses as `reported`.
54921
- */
54922
- stateSource: MediaPlayerStateSourceSchema.default("reported"),
54923
- /**
54924
- * Which fields are the driver's own guess. `stateSource` is `assumed` when
54925
- * this is not empty; a field not listed here is a reading even then (power
54926
- * from a running-state source, mute guessed from the last send).
54927
- */
54928
- assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
54929
- /** Volume as 0..100 inclusive. Null when the device has no volume
54930
- * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
54931
- volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
54932
- /** Mute toggle distinct from volume=0. Null when no mute surface.
54933
- * Pair with `DeviceFeature.MediaPlayerMute`. */
54934
- isMuted: boolean().nullable(),
54935
- /** Active source / input. Empty when no source surface. */
54936
- source: string(),
54937
- /** Selectable sources. Empty when no source surface.
54938
- * Pair with `DeviceFeature.MediaPlayerSelectSource`. */
54939
- availableSources: array(string()),
54940
- /** Currently-playing media info. Null when nothing is playing. */
54941
- currentMedia: MediaInfoSchema.nullable(),
54942
- /** Current playback position in ms. Null when not seekable or
54943
- * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
54944
- position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
54945
- /** Total duration of the current media in ms. Null when unknown
54946
- * (live stream) or nothing is playing. */
54947
- duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
54948
- /** Shuffle toggle. Null when no shuffle surface.
54949
- * Pair with `DeviceFeature.MediaPlayerShuffle`. */
54950
- shuffle: boolean().nullable(),
54951
- /** Repeat mode. Null when no repeat surface.
54952
- * Pair with `DeviceFeature.MediaPlayerRepeat`. */
54953
- repeat: MediaPlayerRepeatSchema.nullable(),
54954
- /** Ms epoch when the slice was last updated. */
54955
- lastChangedAt: number()
54956
- });
54957
- DeviceType.MediaPlayer, method(object({ deviceId: number().int().nonnegative() }), _void(), {
54958
- kind: "mutation",
54959
- auth: "protected"
54960
- }), method(object({ deviceId: number().int().nonnegative() }), _void(), {
54961
- kind: "mutation",
54962
- auth: "protected"
54963
- }), method(object({ deviceId: number().int().nonnegative() }), _void(), {
54964
- kind: "mutation",
54965
- auth: "protected"
54966
- }), method(object({ deviceId: number().int().nonnegative() }), _void(), {
54967
- kind: "mutation",
54968
- auth: "protected"
54969
- }), method(object({ deviceId: number().int().nonnegative() }), _void(), {
54970
- kind: "mutation",
54971
- auth: "protected"
54972
- }), method(object({
54973
- deviceId: number().int().nonnegative(),
54974
- position: number().int().nonnegative()
54975
- }), _void(), {
54976
- kind: "mutation",
54977
- auth: "protected"
54978
- }), method(object({
54979
- deviceId: number().int().nonnegative(),
54980
- volumeLevel: number().min(0).max(100)
54981
- }), _void(), {
54982
- kind: "mutation",
54983
- auth: "protected"
54984
- }), method(object({
54985
- deviceId: number().int().nonnegative(),
54986
- muted: boolean()
54987
- }), _void(), {
54988
- kind: "mutation",
54989
- auth: "protected"
54990
- }), method(object({
54991
- deviceId: number().int().nonnegative(),
54992
- shuffle: boolean()
54993
- }), _void(), {
54994
- kind: "mutation",
54995
- auth: "protected"
54996
- }), method(object({
54997
- deviceId: number().int().nonnegative(),
54998
- repeat: MediaPlayerRepeatSchema
54999
- }), _void(), {
55000
- kind: "mutation",
55001
- auth: "protected"
55002
- }), method(object({
55003
- deviceId: number().int().nonnegative(),
55004
- source: string().min(1)
55005
- }), _void(), {
55006
- kind: "mutation",
55007
- auth: "protected"
55008
- }), method(object({
55009
- deviceId: number().int().nonnegative(),
55010
- /** Media identifier / URL. */
55011
- mediaId: string().min(1),
55012
- /** Media kind (`music`, `tvshow`, `movie`, `app`, …) — provider
55013
- * passes it through to the upstream service. */
55014
- mediaType: string().min(1)
55015
- }), _void(), {
55016
- kind: "mutation",
55017
- auth: "protected"
55018
- });
55019
- /**
55020
55115
  * mesh-network — collection cap for mesh-VPN providers.
55021
55116
  *
55022
55117
  * Different shape from `network-access` (public tunnels):
@@ -63309,6 +63404,21 @@ var NcTemplateVarKindSchema = _enum([
63309
63404
  "sound",
63310
63405
  "system"
63311
63406
  ]);
63407
+ /**
63408
+ * The default title/body a rule of one SITUATION is delivered with when the
63409
+ * operator wrote no template — served so an editor can pre-fill it (and the
63410
+ * operator can rebuild it from placeholders) instead of starting from a blank
63411
+ * box that, once saved, silently replaces it. `id` names the situation inside
63412
+ * a rule `kind`: `appliance-cycle` is a `sensor` rule whose device is an
63413
+ * appliance finishing a cycle. Texts are raw templates (`{{var}}` intact), in
63414
+ * the hub's current language and with its overrides applied.
63415
+ */
63416
+ var NcTemplateDefaultSchema = object({
63417
+ id: _enum(["appliance-cycle"]),
63418
+ kind: NcRuleKindSchema,
63419
+ title: string(),
63420
+ body: string()
63421
+ });
63312
63422
  /** Which producer renders a template: an ordinary rule, a timelapse, a digest. */
63313
63423
  var NcTemplateFamilySchema = _enum([
63314
63424
  "rule",
@@ -64164,7 +64274,11 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
64164
64274
  }), method(object({}), object({
64165
64275
  catalog: array(NcConditionDescriptorSchema),
64166
64276
  taxonomy: NcTaxonomySchema.optional()
64167
- })), method(object({}), object({ vars: array(NcTemplateVarDescriptorSchema) })), method(NcTemplatePreviewInputSchema, NcTemplatePreviewSchema, {
64277
+ })), method(object({}), object({
64278
+ vars: array(NcTemplateVarDescriptorSchema),
64279
+ /** Per-situation default texts; absent on a hub that predates them. */
64280
+ defaults: array(NcTemplateDefaultSchema)
64281
+ })), method(NcTemplatePreviewInputSchema, NcTemplatePreviewSchema, {
64168
64282
  kind: "mutation",
64169
64283
  access: "view"
64170
64284
  }), method(object({ filter: NcHistoryFilterSchema.default({ limit: 100 }) }), object({ entries: array(NcHistoryEntrySchema) }), { auth: "admin" }), method(object({}), NcRuleLastRunsSchema, { auth: "admin" }), method(object({ artifactId: string().min(1) }), object({ url: string().nullable() }), { auth: "admin" }), method(object({}), object({ snoozes: array(NcSnoozeSchema) }), { caller: "required" }), method(object({ snooze: NcSnoozeInputSchema }), object({ snooze: NcSnoozeSchema }), {
@@ -69636,7 +69750,13 @@ var RemoteMediaCommandSchema = _enum([
69636
69750
  "next",
69637
69751
  "previous",
69638
69752
  "setMute",
69639
- "selectSource"
69753
+ "selectSource",
69754
+ "turnOn",
69755
+ "turnOff",
69756
+ "volumeUp",
69757
+ "volumeDown",
69758
+ "channelUp",
69759
+ "channelDown"
69640
69760
  ]);
69641
69761
  /** A send result, or `not-routed`: the role is not bound, so the native cap answers. */
69642
69762
  var RemoteMediaCommandResultSchema = discriminatedUnion("status", [...RemoteSendResultSchema.options, object({ status: literal("not-routed") })]);
@@ -69657,7 +69777,7 @@ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.e
69657
69777
  }), RemoteSendResultSchema, {
69658
69778
  kind: "mutation",
69659
69779
  auth: "protected"
69660
- }), method(deviceInput.extend({
69780
+ }), method(deviceInput, MediaPlayerStatusSchema.nullable(), { auth: "protected" }), method(deviceInput.extend({
69661
69781
  command: RemoteMediaCommandSchema,
69662
69782
  muted: boolean().optional(),
69663
69783
  source: string().optional(),
@@ -71485,7 +71605,11 @@ object({
71485
71605
  });
71486
71606
  Object.values(DeviceType), method(_void(), array(StreamSignalSchema).readonly());
71487
71607
  object({
71488
- on: boolean().meta({ label: "On" }),
71608
+ /**
71609
+ * `null` = the device has never reported its state (a measurement that
71610
+ * has not happened is unknown, never `false`).
71611
+ */
71612
+ on: boolean().nullable().meta({ label: "On" }),
71489
71613
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
71490
71614
  lastChangedAt: number()
71491
71615
  });
@@ -71497,7 +71621,7 @@ DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceTyp
71497
71621
  auth: "protected"
71498
71622
  }), object({
71499
71623
  deviceId: number(),
71500
- on: boolean(),
71624
+ on: boolean().nullable(),
71501
71625
  lastChangedAt: number()
71502
71626
  });
71503
71627
  /** C0 controls, DEL and the C1 range: none of them belongs in a name. */
@@ -74509,6 +74633,7 @@ function buildDescriptor(capName, kind) {
74509
74633
  * contributes one entry per bound cap present in this map.
74510
74634
  */
74511
74635
  var EVENT_KIND_BY_CAP = Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
74636
+ DeviceFeature.MediaPlayerPower, DeviceFeature.MediaPlayerVolumeStep, DeviceFeature.MediaPlayerChannelStep, DeviceFeature.MediaPlayerMute, DeviceFeature.MediaPlayerStop, DeviceFeature.MediaPlayerNext, DeviceFeature.MediaPlayerPrevious;
74512
74637
  var btn = (idSuffix, row, col, init) => ({
74513
74638
  idSuffix,
74514
74639
  row,
@@ -79123,6 +79248,20 @@ Object.freeze({
79123
79248
  access: "view",
79124
79249
  role: "admin"
79125
79250
  },
79251
+ "mediaPlayer.channelDown": {
79252
+ capName: "media-player",
79253
+ capScope: "device",
79254
+ addonId: null,
79255
+ access: "create",
79256
+ role: "viewer"
79257
+ },
79258
+ "mediaPlayer.channelUp": {
79259
+ capName: "media-player",
79260
+ capScope: "device",
79261
+ addonId: null,
79262
+ access: "create",
79263
+ role: "viewer"
79264
+ },
79126
79265
  "mediaPlayer.getStatus": {
79127
79266
  capName: "media-player",
79128
79267
  capScope: "device",
@@ -79214,6 +79353,34 @@ Object.freeze({
79214
79353
  access: "create",
79215
79354
  role: "viewer"
79216
79355
  },
79356
+ "mediaPlayer.turnOff": {
79357
+ capName: "media-player",
79358
+ capScope: "device",
79359
+ addonId: null,
79360
+ access: "create",
79361
+ role: "viewer"
79362
+ },
79363
+ "mediaPlayer.turnOn": {
79364
+ capName: "media-player",
79365
+ capScope: "device",
79366
+ addonId: null,
79367
+ access: "create",
79368
+ role: "viewer"
79369
+ },
79370
+ "mediaPlayer.volumeDown": {
79371
+ capName: "media-player",
79372
+ capScope: "device",
79373
+ addonId: null,
79374
+ access: "create",
79375
+ role: "viewer"
79376
+ },
79377
+ "mediaPlayer.volumeUp": {
79378
+ capName: "media-player",
79379
+ capScope: "device",
79380
+ addonId: null,
79381
+ access: "create",
79382
+ role: "viewer"
79383
+ },
79217
79384
  "meshNetwork.getStatus": {
79218
79385
  capName: "mesh-network",
79219
79386
  capScope: "system",
@@ -82770,6 +82937,13 @@ Object.freeze({
82770
82937
  access: "create",
82771
82938
  role: "admin"
82772
82939
  },
82940
+ "remote.getAssumedStatus": {
82941
+ capName: "remote",
82942
+ capScope: "system",
82943
+ addonId: null,
82944
+ access: "view",
82945
+ role: "admin"
82946
+ },
82773
82947
  "remote.getConfig": {
82774
82948
  capName: "remote",
82775
82949
  capScope: "system",
@@ -86436,6 +86610,16 @@ Object.freeze({
86436
86610
  form: "single",
86437
86611
  optional: true
86438
86612
  }],
86613
+ "mediaPlayer.channelDown": [{
86614
+ name: "deviceId",
86615
+ form: "single",
86616
+ optional: false
86617
+ }],
86618
+ "mediaPlayer.channelUp": [{
86619
+ name: "deviceId",
86620
+ form: "single",
86621
+ optional: false
86622
+ }],
86439
86623
  "mediaPlayer.getStatus": [{
86440
86624
  name: "deviceId",
86441
86625
  form: "single",
@@ -86501,6 +86685,26 @@ Object.freeze({
86501
86685
  form: "single",
86502
86686
  optional: false
86503
86687
  }],
86688
+ "mediaPlayer.turnOff": [{
86689
+ name: "deviceId",
86690
+ form: "single",
86691
+ optional: false
86692
+ }],
86693
+ "mediaPlayer.turnOn": [{
86694
+ name: "deviceId",
86695
+ form: "single",
86696
+ optional: false
86697
+ }],
86698
+ "mediaPlayer.volumeDown": [{
86699
+ name: "deviceId",
86700
+ form: "single",
86701
+ optional: false
86702
+ }],
86703
+ "mediaPlayer.volumeUp": [{
86704
+ name: "deviceId",
86705
+ form: "single",
86706
+ optional: false
86707
+ }],
86504
86708
  "meter.getStatus": [{
86505
86709
  name: "deviceId",
86506
86710
  form: "single",
@@ -87666,6 +87870,11 @@ Object.freeze({
87666
87870
  form: "single",
87667
87871
  optional: true
87668
87872
  }],
87873
+ "remote.getAssumedStatus": [{
87874
+ name: "deviceId",
87875
+ form: "single",
87876
+ optional: false
87877
+ }],
87669
87878
  "remote.getConfig": [{
87670
87879
  name: "deviceId",
87671
87880
  form: "single",
@@ -88921,6 +89130,7 @@ var STATE_SUMMARY_VARS = [
88921
89130
  [...RULE_TEXT],
88922
89131
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
88923
89132
  ([...RULE_TEXT], [...COMBINED_ALARM]),
89133
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
88924
89134
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
88925
89135
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
88926
89136
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -89656,7 +89866,7 @@ var AgentUIAddon = class extends BaseAddon {
89656
89866
  capability: adminUiCapability,
89657
89867
  provider: {
89658
89868
  getStaticDir: async () => ({ staticDir: path.resolve(__dirname) }),
89659
- getVersion: async () => ({ version: "1.2.317" })
89869
+ getVersion: async () => ({ version: "1.2.318" })
89660
89870
  }
89661
89871
  }];
89662
89872
  }