@camstack/addon-pipeline 1.2.632 → 1.2.634

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/audio-analyzer/index.js +3 -3
  3. package/dist/audio-analyzer/index.mjs +3 -3
  4. package/dist/{custom-model-catalog-B2w26VBG.mjs → custom-model-catalog-BjkdcgOE.mjs} +2 -2
  5. package/dist/{custom-model-catalog-DN4xBVQE.js → custom-model-catalog-CgSsz_wK.js} +2 -2
  6. package/dist/detection-pipeline/index.js +4 -4
  7. package/dist/detection-pipeline/index.mjs +4 -4
  8. package/dist/{dist-CLo3QHtG.js → dist-C5sQVajZ.js} +685 -13
  9. package/dist/{dist-DWkdwtle.mjs → dist-DlB7gVjz.mjs} +685 -13
  10. package/dist/{model-catalogs-DIviCtiQ.js → model-catalogs-D6iqJdhC.js} +1 -1
  11. package/dist/{model-catalogs-rs7okKyp.mjs → model-catalogs-XdVK-cpH.mjs} +1 -1
  12. package/dist/motion-wasm/index.js +1 -1
  13. package/dist/motion-wasm/index.mjs +1 -1
  14. package/dist/{node-CAJ1Dal-.mjs → node-DI6cJT3H.mjs} +1 -1
  15. package/dist/{node-CPqDCFas.js → node-DqynP4Sn.js} +1 -1
  16. package/dist/pipeline-runner/index.js +3 -3
  17. package/dist/pipeline-runner/index.mjs +3 -3
  18. package/dist/{process-memory-BrKzYxim.js → process-memory-BWsvhswo.js} +1 -1
  19. package/dist/{process-memory-DJWthb6k.mjs → process-memory-CdsO2dxD.mjs} +1 -1
  20. package/dist/recorder/index.js +8 -2
  21. package/dist/recorder/index.mjs +8 -2
  22. package/dist/{segment-demux-js-Bt5bxfyh.js → segment-demux-js-CEqPvaCD.js} +1 -1
  23. package/dist/{segment-demux-js-CZdgio0n.mjs → segment-demux-js-jzhozTBr.mjs} +1 -1
  24. package/dist/stream-broker/_stub.js +2 -2
  25. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CjjdxZUq.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BfutHWHx.mjs} +2 -2
  26. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DfXSkf61.mjs +26 -0
  27. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CGcEN1m1.mjs +26 -0
  28. package/dist/stream-broker/demux-worker-child.js +1 -1
  29. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  30. package/dist/stream-broker/{hostInit-MWvZi8Nq.mjs → hostInit-oZNKK5YV.mjs} +2 -2
  31. package/dist/stream-broker/index.js +115 -19
  32. package/dist/stream-broker/index.mjs +115 -19
  33. package/dist/stream-broker/remoteEntry.js +1 -1
  34. package/package.json +1 -1
  35. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DZmxw-we.mjs +0 -26
  36. 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 +0 -26
@@ -5580,7 +5580,7 @@ var ZodIssueCode = {
5580
5580
  var ZodFirstPartyTypeKind;
5581
5581
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5582
5582
  //#endregion
5583
- //#region ../types/dist/sleep-Crlmu_tO.mjs
5583
+ //#region ../types/dist/sleep-DJws6ho7.mjs
5584
5584
  /**
5585
5585
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5586
5586
  * window to float samples (D455).
@@ -9124,6 +9124,7 @@ var CAP_NAMES = Object.freeze([
9124
9124
  "image-settings",
9125
9125
  "integrations",
9126
9126
  "intercom",
9127
+ "ir-transmitter",
9127
9128
  "keychain",
9128
9129
  "keychain-admin",
9129
9130
  "lawn-mower-control",
@@ -9182,6 +9183,7 @@ var CAP_NAMES = Object.freeze([
9182
9183
  "recording-onboard",
9183
9184
  "recording-signal",
9184
9185
  "records",
9186
+ "remote",
9185
9187
  "running-state",
9186
9188
  "scene-monitor",
9187
9189
  "script-runner",
@@ -9205,6 +9207,7 @@ var CAP_NAMES = Object.freeze([
9205
9207
  "system",
9206
9208
  "tamper",
9207
9209
  "temperature-sensor",
9210
+ "template",
9208
9211
  "terminal-session",
9209
9212
  "toast",
9210
9213
  "training",
@@ -10145,6 +10148,11 @@ Object.freeze({
10145
10148
  "standby"
10146
10149
  ]
10147
10150
  },
10151
+ {
10152
+ "path": "stateSource",
10153
+ "valueType": "enum",
10154
+ "enumValues": ["reported", "assumed"]
10155
+ },
10148
10156
  {
10149
10157
  "path": "volumeLevel",
10150
10158
  "valueType": "number"
@@ -10371,6 +10379,11 @@ Object.freeze({
10371
10379
  "path": "batteryPower",
10372
10380
  "valueType": "number"
10373
10381
  },
10382
+ {
10383
+ "path": "powerSource",
10384
+ "valueType": "enum",
10385
+ "enumValues": ["mains", "battery"]
10386
+ },
10374
10387
  {
10375
10388
  "path": "desiccantLeftDays",
10376
10389
  "valueType": "number"
@@ -10415,6 +10428,18 @@ Object.freeze({
10415
10428
  {
10416
10429
  "path": "volume",
10417
10430
  "valueType": "number"
10431
+ },
10432
+ {
10433
+ "path": "lastFeedGrams",
10434
+ "valueType": "number"
10435
+ },
10436
+ {
10437
+ "path": "lastFeedHopper1",
10438
+ "valueType": "number"
10439
+ },
10440
+ {
10441
+ "path": "lastFeedHopper2",
10442
+ "valueType": "number"
10418
10443
  }
10419
10444
  ],
10420
10445
  "power-meter": [
@@ -11106,7 +11131,7 @@ function sleep(ms) {
11106
11131
  return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
11107
11132
  }
11108
11133
  //#endregion
11109
- //#region ../types/dist/err-msg-DIorGYeC.mjs
11134
+ //#region ../types/dist/err-msg-BCdlR2Li.mjs
11110
11135
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
11111
11136
  DeviceType["Camera"] = "camera";
11112
11137
  DeviceType["Hub"] = "hub";
@@ -11452,6 +11477,9 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
11452
11477
  /** Fallback when the notifier service name doesn't match a known
11453
11478
  * pattern. */
11454
11479
  DeviceRole["GenericNotifier"] = "generic-notifier";
11480
+ /** Emits a pulse train (infrared or RF) on request — the `ir-transmitter`
11481
+ * cap. A `DeviceType.Generic` device. */
11482
+ DeviceRole["IrTransmitter"] = "ir-transmitter";
11455
11483
  return DeviceRole;
11456
11484
  }({});
11457
11485
  /**
@@ -11465,7 +11493,7 @@ function errMsg(err) {
11465
11493
  return String(err);
11466
11494
  }
11467
11495
  //#endregion
11468
- //#region ../types/dist/composition-CZImLpOI.mjs
11496
+ //#region ../types/dist/composition-bIBW5_13.mjs
11469
11497
  var AUDIO_ENCODER_BY_CODEC = {
11470
11498
  opus: "libopus",
11471
11499
  aac: "aac",
@@ -11923,6 +11951,15 @@ function audioPlanFromEncodeProfile(audio) {
11923
11951
  * plane. Width / height / fps / bitrate in the profile are a downstream BUDGET,
11924
11952
  * not a forced rescale.
11925
11953
  */
11954
+ /**
11955
+ * Probe bound for an input that is one of OUR OWN RTSP restreams. Not zero: a
11956
+ * zero-length probe makes ffmpeg trust the SDP completely, and a restream that
11957
+ * announces a track it never sends would leave the mapping wrong unnoticed.
11958
+ */
11959
+ var RESTREAM_INPUT_PROBE = {
11960
+ analyzeDurationUs: 2e5,
11961
+ probeSizeBytes: 64 * 1024
11962
+ };
11926
11963
  function invocationFromEncodeProfile(input) {
11927
11964
  const v = input.profile.video;
11928
11965
  const shouldCopy = v.codec === "copy" || input.forceReencode !== true && v.codec === input.sourceCodec;
@@ -11960,6 +11997,8 @@ function invocationFromEncodeProfile(input) {
11960
11997
  url: input.sourceUrl,
11961
11998
  rtspTransport: "tcp",
11962
11999
  fflags: ["+discardcorrupt"],
12000
+ analyzeDurationUs: RESTREAM_INPUT_PROBE.analyzeDurationUs,
12001
+ probeSizeBytes: RESTREAM_INPUT_PROBE.probeSizeBytes,
11963
12002
  ...input.profile.inputArgs?.length ? { extraArgs: input.profile.inputArgs } : {}
11964
12003
  },
11965
12004
  video,
@@ -19408,9 +19447,21 @@ var AlertSeveritySchema = _enum([
19408
19447
  "error",
19409
19448
  "critical"
19410
19449
  ]);
19450
+ /**
19451
+ * An action that RUNS something instead of going somewhere: the admin UI calls
19452
+ * the addon's custom action (`addons.custom`) with exactly these fields. The
19453
+ * producer owns the meaning; the UI knows nothing about the addon or the kind.
19454
+ */
19455
+ var AlertActionInvokeSchema = object({
19456
+ addonId: string().min(1),
19457
+ action: string().min(1),
19458
+ input: record(string(), unknown()).optional()
19459
+ });
19460
+ /** An action has `href` (a link) OR `invoke` (a button that runs a custom action). */
19411
19461
  var AlertActionSchema = object({
19412
19462
  label: string(),
19413
19463
  href: string().optional(),
19464
+ invoke: AlertActionInvokeSchema.optional(),
19414
19465
  /**
19415
19466
  * How `href` is followed. Absent / `app`: an admin-ui route (client-side).
19416
19467
  * `server`: a route the HUB serves (an addon HTTP route such as an OAuth
@@ -22363,12 +22414,13 @@ var CHANGED = {
22363
22414
  expr: "now"
22364
22415
  };
22365
22416
  function numeric(input) {
22417
+ const { alsoFrom, ...base } = input;
22366
22418
  return {
22367
- ...input,
22419
+ ...base,
22368
22420
  family: "numeric",
22369
22421
  deviceType: DeviceType.Sensor,
22370
22422
  memberDeviceType: DeviceType.Sensor,
22371
- memberDeviceTypes: [DeviceType.Sensor],
22423
+ memberDeviceTypes: [DeviceType.Sensor, ...alsoFrom?.deviceTypes ?? []],
22372
22424
  activeWhen: void 0,
22373
22425
  commandCaps: [],
22374
22426
  baseUnit: baseUnitOf(input.quantity),
@@ -22376,9 +22428,10 @@ function numeric(input) {
22376
22428
  accept: [{
22377
22429
  cap: input.outputCap,
22378
22430
  fieldPath: input.outputField
22379
- }]
22431
+ }, ...alsoFrom === void 0 ? [] : [alsoFrom.accept]]
22380
22432
  };
22381
22433
  }
22434
+ var CLIMATE_DEVICES = [DeviceType.Thermostat, DeviceType.Climate];
22382
22435
  function binary(input) {
22383
22436
  return {
22384
22437
  ...input,
@@ -22404,7 +22457,14 @@ var GROUP_TEMPLATES = [
22404
22457
  quantity: "temperature",
22405
22458
  defaultAggregate: "mean",
22406
22459
  empty: "null",
22407
- companions: [NOW$2]
22460
+ companions: [NOW$2],
22461
+ alsoFrom: {
22462
+ deviceTypes: CLIMATE_DEVICES,
22463
+ accept: {
22464
+ cap: "climate-control",
22465
+ fieldPath: "currentTemp"
22466
+ }
22467
+ }
22408
22468
  }),
22409
22469
  numeric({
22410
22470
  id: "humidity",
@@ -22415,7 +22475,14 @@ var GROUP_TEMPLATES = [
22415
22475
  quantity: "humidity",
22416
22476
  defaultAggregate: "mean",
22417
22477
  empty: "null",
22418
- companions: [NOW$2]
22478
+ companions: [NOW$2],
22479
+ alsoFrom: {
22480
+ deviceTypes: CLIMATE_DEVICES,
22481
+ accept: {
22482
+ cap: "climate-control",
22483
+ fieldPath: "currentHumidity"
22484
+ }
22485
+ }
22419
22486
  }),
22420
22487
  numeric({
22421
22488
  id: "pressure",
@@ -46700,6 +46767,17 @@ var LlmProfileSchema = object({
46700
46767
  * field in its editor only when its descriptor lists it in `profileFields`. */
46701
46768
  topK: number().int().positive().optional(),
46702
46769
  maxTokens: number().int().positive().optional(),
46770
+ /** How hard the model "thinks" before it answers. Omitted = the model's own
46771
+ * default. `off` matters for structured output: a thinking model can spend
46772
+ * the whole completion on reasoning and return an empty `content`. Carried
46773
+ * only by the wires that have it — a kind offers the field in its editor
46774
+ * only when its descriptor lists it in `profileFields`. */
46775
+ reasoningEffort: _enum([
46776
+ "off",
46777
+ "low",
46778
+ "medium",
46779
+ "high"
46780
+ ]).optional(),
46703
46781
  /** Prompt context window. Advisory for cloud kinds (they enforce their own). */
46704
46782
  contextLength: number().int().positive().optional(),
46705
46783
  /** Default system prompt. A caller's `system` REPLACES it (never appends —
@@ -46738,6 +46816,7 @@ var LlmProfileFieldSchema = _enum([
46738
46816
  "topP",
46739
46817
  "topK",
46740
46818
  "maxTokens",
46819
+ "reasoningEffort",
46741
46820
  "contextLength",
46742
46821
  "systemPrompt",
46743
46822
  "timeoutMs",
@@ -48040,6 +48119,43 @@ var NotificationActionSchema = object({
48040
48119
  */
48041
48120
  mode: _enum(["navigate", "background"]).optional()
48042
48121
  });
48122
+ /** A delivery parameter value: what a notifier declared it takes. */
48123
+ var DeliveryParamValueSchema = union$1([
48124
+ string(),
48125
+ number(),
48126
+ boolean()
48127
+ ]);
48128
+ /**
48129
+ * One extra delivery parameter a notifier KIND declares (D938). A rule that
48130
+ * addresses a target of that kind may set it; a kind that declares nothing is
48131
+ * never handed one. The admin UI derives its control from this descriptor —
48132
+ * no editor knows a service by name.
48133
+ *
48134
+ * Optional fields are `.optional()`, never `.default()` (a Zod default does not
48135
+ * run on the addon cap path).
48136
+ */
48137
+ var DeliveryParamSchema = object({
48138
+ key: string().min(1),
48139
+ label: string(),
48140
+ /** i18n key of the label, resolved by the declaring addon's namespace. */
48141
+ labelKey: string().optional(),
48142
+ type: _enum([
48143
+ "enum",
48144
+ "number",
48145
+ "boolean",
48146
+ "string"
48147
+ ]),
48148
+ /** `enum` only: the closed set of accepted values. */
48149
+ options: array(object({
48150
+ value: string(),
48151
+ label: string()
48152
+ })).optional(),
48153
+ /** `number` only. */
48154
+ min: number().optional(),
48155
+ max: number().optional(),
48156
+ /** What the notifier does when the rule sets nothing; shown as the placeholder. */
48157
+ default: DeliveryParamValueSchema.optional()
48158
+ });
48043
48159
  /**
48044
48160
  * The canonical notification. `body` is the only hard field (Apprise model).
48045
48161
  * `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
@@ -48062,7 +48178,13 @@ var NotificationSchema = object({
48062
48178
  tag: string().optional(),
48063
48179
  deviceId: number().optional(),
48064
48180
  eventId: string().optional(),
48065
- metadata: record(string(), unknown()).optional()
48181
+ metadata: record(string(), unknown()).optional(),
48182
+ /**
48183
+ * Values for the parameters the target's kind DECLARES in
48184
+ * {@link TargetKindSchema} `deliveryParams`. Already validated against the
48185
+ * declaration by the sender; a notifier reads only the keys it declared.
48186
+ */
48187
+ delivery: record(string(), DeliveryParamValueSchema).optional()
48066
48188
  });
48067
48189
  /** One declared native severity/priority level for a kind. */
48068
48190
  var TargetKindLevelSchema = object({
@@ -48168,6 +48290,11 @@ var TargetKindSchema = object({
48168
48290
  */
48169
48291
  destinationKeys: array(string()).optional(),
48170
48292
  supportsDiscovery: boolean(),
48293
+ /**
48294
+ * Extra delivery parameters a rule may set for a target of this kind (D938).
48295
+ * Absent = none; the rule editor then offers nothing.
48296
+ */
48297
+ deliveryParams: array(DeliveryParamSchema).optional(),
48171
48298
  caps: TargetKindCapsSchema
48172
48299
  });
48173
48300
  /**
@@ -61182,7 +61309,9 @@ var ManifestShapeSchema = object({
61182
61309
  icon: string().optional()
61183
61310
  }).optional(),
61184
61311
  protected: boolean().optional(),
61185
- removable: boolean().optional()
61312
+ removable: boolean().optional(),
61313
+ /** Declared Integrations-page block (mirror of `AddonDeclaration.integrationSection`). */
61314
+ integrationSection: _enum(["system", "providers"]).optional()
61186
61315
  });
61187
61316
  var AddonProcessSchema = object({
61188
61317
  pid: number().optional(),
@@ -62044,11 +62173,373 @@ DeviceType.Light, method(object({
62044
62173
  level: number().min(0).max(100),
62045
62174
  lastChangedAt: number()
62046
62175
  });
62176
+ /**
62177
+ * The role vocabulary of a remote (D963): what a button MEANS, independent of
62178
+ * how it is wired. A layout template places buttons by role; a device binds a
62179
+ * role to an action; an exporter asks for a role by name. Roles are shared so
62180
+ * one layout fits every appliance and one voice command fits every binding.
62181
+ *
62182
+ * A role outside this list is `custom:<key>` — the operator's own button (a
62183
+ * SmartIR source, a channel preset). The key is a lowercase slug.
62184
+ */
62185
+ var REMOTE_KNOWN_ROLES = [
62186
+ "power",
62187
+ "power_on",
62188
+ "power_off",
62189
+ "volume_up",
62190
+ "volume_down",
62191
+ "mute",
62192
+ "channel_up",
62193
+ "channel_down",
62194
+ "up",
62195
+ "down",
62196
+ "left",
62197
+ "right",
62198
+ "ok",
62199
+ "back",
62200
+ "home",
62201
+ "menu",
62202
+ "info",
62203
+ "guide",
62204
+ "exit",
62205
+ "input",
62206
+ "play",
62207
+ "pause",
62208
+ "play_pause",
62209
+ "stop",
62210
+ "next",
62211
+ "previous",
62212
+ "fast_forward",
62213
+ "rewind",
62214
+ "digit_0",
62215
+ "digit_1",
62216
+ "digit_2",
62217
+ "digit_3",
62218
+ "digit_4",
62219
+ "digit_5",
62220
+ "digit_6",
62221
+ "digit_7",
62222
+ "digit_8",
62223
+ "digit_9"
62224
+ ];
62225
+ var CUSTOM_KEY_RE = /^[a-z0-9][a-z0-9_]{0,47}$/;
62226
+ var KNOWN_ROLES = new Set(REMOTE_KNOWN_ROLES);
62227
+ function isRemoteKnownRole(value) {
62228
+ return KNOWN_ROLES.has(value);
62229
+ }
62230
+ function isRemoteCustomKey(key) {
62231
+ return CUSTOM_KEY_RE.test(key);
62232
+ }
62233
+ /** The key of a `custom:<key>` role, or null for any other string. */
62234
+ function customKeyOfRole(role) {
62235
+ if (!role.startsWith("custom:")) return null;
62236
+ const key = role.slice(7);
62237
+ return isRemoteCustomKey(key) ? key : null;
62238
+ }
62239
+ function isRemoteRole(value) {
62240
+ return isRemoteKnownRole(value) || customKeyOfRole(value) !== null;
62241
+ }
62242
+ var RemoteRoleSchema = string().refine(isRemoteRole, { message: "a role is one of the known roles or custom:<key> (lowercase letters, digits, _)" });
62243
+ var RemoteBindingSchema = object({ action: AutomationCapStepSchema.extend({ deviceId: number().int().nonnegative() }) });
62244
+ var RemoteCustomButtonSchema = object({
62245
+ /** The slug after `custom:` in the role. */
62246
+ key: string().refine(isRemoteCustomKey, { message: "a lowercase slug" }),
62247
+ /** What the operator calls it, and what a voice command may name. */
62248
+ name: string().min(1).max(60)
62249
+ });
62250
+ var RemotePowerModeSchema = _enum(["toggle", "discrete"]);
62251
+ var RemoteConfigSchema = object({
62252
+ layoutTemplateId: string().min(1).nullable(),
62253
+ /**
62254
+ * The transmitter device new bindings and an import send through. A binding
62255
+ * names its own device, so one command may override it.
62256
+ */
62257
+ defaultTransmitterId: number().int().nonnegative().nullable().default(null),
62258
+ /** Keyed by role. A role with no entry falls back to the native cap. */
62259
+ bindings: record(string(), RemoteBindingSchema),
62260
+ customButtons: array(RemoteCustomButtonSchema).max(100),
62261
+ power: object({ mode: RemotePowerModeSchema })
62262
+ }).superRefine((config, ctx) => {
62263
+ const roles = Object.keys(config.bindings);
62264
+ if (roles.length > 200) ctx.addIssue({
62265
+ code: "custom",
62266
+ message: "too many bindings",
62267
+ path: ["bindings"]
62268
+ });
62269
+ for (const role of roles) if (!isRemoteRole(role)) ctx.addIssue({
62270
+ code: "custom",
62271
+ message: `"${role}" is not a role`,
62272
+ path: ["bindings", role]
62273
+ });
62274
+ const keys = /* @__PURE__ */ new Set();
62275
+ config.customButtons.forEach((button, index) => {
62276
+ if (keys.has(button.key)) ctx.addIssue({
62277
+ code: "custom",
62278
+ message: `custom button "${button.key}" is listed twice`,
62279
+ path: [
62280
+ "customButtons",
62281
+ index,
62282
+ "key"
62283
+ ]
62284
+ });
62285
+ keys.add(button.key);
62286
+ });
62287
+ for (const role of roles) {
62288
+ const key = customKeyOfRole(role);
62289
+ if (key !== null && !keys.has(key)) ctx.addIssue({
62290
+ code: "custom",
62291
+ message: `${role} is bound but has no entry in customButtons`,
62292
+ path: ["bindings", role]
62293
+ });
62294
+ }
62295
+ });
62296
+ object({
62297
+ power: object({
62298
+ state: _enum(["on", "off"]),
62299
+ at: number()
62300
+ }).nullable(),
62301
+ muted: object({
62302
+ value: boolean(),
62303
+ at: number()
62304
+ }).nullable()
62305
+ });
62306
+ var RemoteLayoutButtonSchema = object({
62307
+ id: string().min(1).max(40),
62308
+ /** 0-based grid position. */
62309
+ row: number().int().min(0).max(24),
62310
+ col: number().int().min(0).max(24),
62311
+ rowSpan: number().int().min(1).max(24),
62312
+ colSpan: number().int().min(1).max(24),
62313
+ icon: string().min(1).max(60).optional(),
62314
+ label: string().min(1).max(40).optional(),
62315
+ role: RemoteRoleSchema
62316
+ });
62317
+ object({
62318
+ columns: number().int().min(1).max(24),
62319
+ rows: number().int().min(1).max(24),
62320
+ buttons: array(RemoteLayoutButtonSchema).max(200)
62321
+ }).superRefine((grid, ctx) => {
62322
+ const ids = /* @__PURE__ */ new Set();
62323
+ const taken = /* @__PURE__ */ new Map();
62324
+ grid.buttons.forEach((button, index) => {
62325
+ if (ids.has(button.id)) ctx.addIssue({
62326
+ code: "custom",
62327
+ message: `button id "${button.id}" is used twice`,
62328
+ path: [
62329
+ "buttons",
62330
+ index,
62331
+ "id"
62332
+ ]
62333
+ });
62334
+ ids.add(button.id);
62335
+ if (button.row + button.rowSpan > grid.rows || button.col + button.colSpan > grid.columns) {
62336
+ ctx.addIssue({
62337
+ code: "custom",
62338
+ message: `button "${button.id}" leaves the grid`,
62339
+ path: ["buttons", index]
62340
+ });
62341
+ return;
62342
+ }
62343
+ for (let r = button.row; r < button.row + button.rowSpan; r += 1) for (let c = button.col; c < button.col + button.colSpan; c += 1) {
62344
+ const cell = `${r}:${c}`;
62345
+ const other = taken.get(cell);
62346
+ if (other !== void 0) {
62347
+ ctx.addIssue({
62348
+ code: "custom",
62349
+ message: `buttons "${other}" and "${button.id}" overlap`,
62350
+ path: ["buttons", index]
62351
+ });
62352
+ return;
62353
+ }
62354
+ taken.set(cell, button.id);
62355
+ }
62356
+ });
62357
+ });
62358
+ var RemoteBoundCommandSchema = object({
62359
+ role: RemoteRoleSchema,
62360
+ /** The operator's name for a custom button; absent for a known role. */
62361
+ label: string().optional(),
62362
+ custom: boolean()
62363
+ });
62364
+ var RemoteCommandListSchema = object({
62365
+ layoutTemplateId: string().nullable(),
62366
+ power: object({ mode: RemotePowerModeSchema }),
62367
+ /** Only the roles that are BOUND — the ones a press can reach. */
62368
+ commands: array(RemoteBoundCommandSchema)
62369
+ });
62370
+ var RemoteRefusalReasonSchema = _enum([
62371
+ "no-remote",
62372
+ "unbound-role",
62373
+ "action-failed"
62374
+ ]);
62375
+ var RemoteSendResultSchema = discriminatedUnion("status", [
62376
+ object({
62377
+ status: literal("sent"),
62378
+ /** How many times the action ran. */
62379
+ sends: number().int().min(1)
62380
+ }),
62381
+ object({
62382
+ status: literal("skipped"),
62383
+ reason: literal("already-in-state")
62384
+ }),
62385
+ object({
62386
+ status: literal("refused"),
62387
+ reason: RemoteRefusalReasonSchema,
62388
+ detail: string().optional()
62389
+ })
62390
+ ]);
62391
+ var RemoteMediaCommandSchema = _enum([
62392
+ "play",
62393
+ "pause",
62394
+ "stop",
62395
+ "next",
62396
+ "previous",
62397
+ "setMute",
62398
+ "selectSource"
62399
+ ]);
62400
+ /** A send result, or `not-routed`: the role is not bound, so the native cap answers. */
62401
+ var RemoteMediaCommandResultSchema = discriminatedUnion("status", [...RemoteSendResultSchema.options, object({ status: literal("not-routed") })]);
62402
+ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status: literal("saved") }), object({
62403
+ status: literal("refused"),
62404
+ reason: _enum(["unknown-template", "not-a-media-player"]),
62405
+ detail: string()
62406
+ })]);
62407
+ var deviceInput = object({ deviceId: number().int().nonnegative() });
62408
+ DeviceType.MediaPlayer;
62409
+ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
62410
+ kind: "mutation",
62411
+ auth: "admin"
62412
+ }), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
62413
+ role: RemoteRoleSchema,
62414
+ /** Sends in a row (volume steps). */
62415
+ repeat: number().int().min(1).max(50).default(1)
62416
+ }), RemoteSendResultSchema, {
62417
+ kind: "mutation",
62418
+ auth: "protected"
62419
+ }), method(deviceInput.extend({
62420
+ command: RemoteMediaCommandSchema,
62421
+ muted: boolean().optional(),
62422
+ source: string().optional(),
62423
+ repeat: number().int().min(1).max(50).default(1)
62424
+ }), RemoteMediaCommandResultSchema, {
62425
+ kind: "mutation",
62426
+ auth: "protected"
62427
+ });
62428
+ var TemplateKindSchema = _enum(["remote"]);
62429
+ /**
62430
+ * template — the generic store of reusable, named operator data (D963). A
62431
+ * record is `{ id, kind, name, payload }`; the kinds (today only `remote`, the
62432
+ * button grid of a remote) and the schema each payload must satisfy are
62433
+ * declared by the system in `template-kinds.ts`. Nothing here is specific to a
62434
+ * kind: the engine validates a payload against its kind's schema and, on a
62435
+ * delete, asks the kind's owner whether anything still points at the record.
62436
+ *
62437
+ * Every refusal is a typed result — a UI says "unknown kind" or names the
62438
+ * devices that still use a template, without parsing text.
62439
+ */
62440
+ var TemplateRecordSchema = object({
62441
+ id: string().min(1),
62442
+ kind: TemplateKindSchema,
62443
+ name: string().min(1).max(120),
62444
+ /** Shaped by the kind; `checkTemplatePayload(kind, payload)` reads it. */
62445
+ payload: unknown(),
62446
+ createdAt: number(),
62447
+ updatedAt: number()
62448
+ });
62449
+ var TemplateWriteResultSchema = discriminatedUnion("status", [object({
62450
+ status: literal("saved"),
62451
+ template: TemplateRecordSchema
62452
+ }), object({
62453
+ status: literal("refused"),
62454
+ reason: _enum(["invalid-payload", "not-found"]),
62455
+ detail: string()
62456
+ })]);
62457
+ /** A device still pointing at a template. */
62458
+ var TemplateUserSchema = object({
62459
+ deviceId: number().int().nonnegative(),
62460
+ name: string()
62461
+ });
62462
+ var TemplateDeleteResultSchema = discriminatedUnion("status", [
62463
+ object({ status: literal("deleted") }),
62464
+ object({ status: literal("not-found") }),
62465
+ object({
62466
+ status: literal("in-use"),
62467
+ devices: array(TemplateUserSchema).min(1)
62468
+ })
62469
+ ]);
62470
+ method(object({ kind: TemplateKindSchema.optional() }), array(TemplateRecordSchema), { auth: "protected" }), method(object({ id: string().min(1) }), TemplateRecordSchema.nullable(), { auth: "protected" }), method(object({
62471
+ kind: TemplateKindSchema,
62472
+ name: string().min(1).max(120),
62473
+ payload: unknown()
62474
+ }), TemplateWriteResultSchema, {
62475
+ kind: "mutation",
62476
+ auth: "admin"
62477
+ }), method(object({
62478
+ id: string().min(1),
62479
+ name: string().min(1).max(120).optional(),
62480
+ payload: unknown().optional()
62481
+ }), TemplateWriteResultSchema, {
62482
+ kind: "mutation",
62483
+ auth: "admin"
62484
+ }), method(object({ id: string().min(1) }), TemplateDeleteResultSchema, {
62485
+ kind: "mutation",
62486
+ auth: "admin"
62487
+ });
62047
62488
  DeviceType.Button, method(object({ deviceId: number().int().nonnegative() }), _void(), {
62048
62489
  kind: "mutation",
62049
62490
  auth: "protected"
62050
62491
  });
62051
62492
  /**
62493
+ * A pulse train in signed microseconds: mark (+) first, then space (-), strictly
62494
+ * alternating, no zeros, 2..1024 entries.
62495
+ */
62496
+ var IrTimingsSchema = array(number().int()).min(2).max(1024).superRefine((timings, ctx) => {
62497
+ timings.forEach((value, index) => {
62498
+ const expectMark = index % 2 === 0;
62499
+ if (value === 0 || value > 0 !== expectMark) ctx.addIssue({
62500
+ code: "custom",
62501
+ message: `timing ${index} must be a non-zero ${expectMark ? "mark (positive)" : "space (negative)"}`,
62502
+ path: [index]
62503
+ });
62504
+ });
62505
+ });
62506
+ /** Per-command transmit options. Every key is optional; a transmitter applies what it can. */
62507
+ var TransmitSettingsSchema = object({
62508
+ carrierHz: number().int().positive().optional(),
62509
+ dutyCyclePercent: number().int().min(1).max(100).optional(),
62510
+ repeat: number().int().min(0).max(20).optional(),
62511
+ repeatDelayMs: number().int().min(0).optional()
62512
+ });
62513
+ /** The setting keys a transmitter may declare as settable (`getInfo.settable`). */
62514
+ var TransmitSettingKeySchema = _enum([
62515
+ "carrierHz",
62516
+ "dutyCyclePercent",
62517
+ "repeat",
62518
+ "repeatDelayMs"
62519
+ ]);
62520
+ var IrMediumSchema = _enum(["ir", "rf"]);
62521
+ var IrSendResultSchema = object({
62522
+ ok: literal(true),
62523
+ /** Settings the transmitter could not apply; the train was still sent. */
62524
+ ignoredSettings: array(string())
62525
+ });
62526
+ var IrTransmitterInfoSchema = object({
62527
+ media: array(IrMediumSchema),
62528
+ settable: array(TransmitSettingKeySchema),
62529
+ maxTimings: number().int().positive()
62530
+ });
62531
+ DeviceType.Generic, method(object({
62532
+ deviceId: number().int().nonnegative(),
62533
+ timings: IrTimingsSchema,
62534
+ settings: TransmitSettingsSchema.optional()
62535
+ }), IrSendResultSchema, {
62536
+ kind: "mutation",
62537
+ auth: "protected"
62538
+ }), method(object({ deviceId: number().int().nonnegative() }), IrTransmitterInfoSchema, {
62539
+ kind: "query",
62540
+ auth: "protected"
62541
+ });
62542
+ /**
62052
62543
  * `calendar-source` — collection cap exposing per-provider calendars and
62053
62544
  * their events. Every addon that contributes calendars (Home Assistant,
62054
62545
  * a future Google Calendar addon, …) registers a provider here. The hub
@@ -64743,9 +65234,35 @@ var MediaInfoSchema = object({
64743
65234
  /** Optional cover-art / thumbnail URL. */
64744
65235
  imageUrl: string().optional()
64745
65236
  });
65237
+ /**
65238
+ * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
65239
+ * the device said so. `assumed`: the driver has no feedback (infrared) and
65240
+ * tracks what it last SENT; it moves only after a send was accepted, and a
65241
+ * human at the real remote makes it wrong. A UI shows an assumed value as a
65242
+ * guess, never as a reading.
65243
+ */
65244
+ var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
65245
+ /** The fields of a media-player status a driver can only guess. */
65246
+ var MediaPlayerAssumedFieldSchema = _enum([
65247
+ "state",
65248
+ "volumeLevel",
65249
+ "isMuted",
65250
+ "source"
65251
+ ]);
64746
65252
  object({
64747
65253
  /** Playback lifecycle state. */
64748
65254
  state: MediaPlayerStateSchema,
65255
+ /**
65256
+ * Whether the state fields are readings or the driver's own bookkeeping.
65257
+ * A slice written before this field existed parses as `reported`.
65258
+ */
65259
+ stateSource: MediaPlayerStateSourceSchema.default("reported"),
65260
+ /**
65261
+ * Which fields are the driver's own guess. `stateSource` is `assumed` when
65262
+ * this is not empty; a field not listed here is a reading even then (power
65263
+ * from a running-state source, mute guessed from the last send).
65264
+ */
65265
+ assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
64749
65266
  /** Volume as 0..100 inclusive. Null when the device has no volume
64750
65267
  * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
64751
65268
  volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -66151,9 +66668,14 @@ object({
66151
66668
  * (`device_class: problem`, on = low). True when the tank reports empty,
66152
66669
  * or, on a dual-hopper model, when EITHER hopper is empty. */
66153
66670
  lowFood: boolean(),
66154
- /** Battery charge 0..100 (%). Null on mains-powered models or when the
66155
- * device has no battery reading. */
66671
+ /** Battery charge 0..100 (%). On a feeder running on `mains` this is the
66672
+ * BACKUP battery's charge, not the power source. Null when the device has
66673
+ * no battery reading. */
66156
66674
  batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
66675
+ /** What the feeder is powered from right now: `mains` (plugged in, the
66676
+ * battery is only a backup) or `battery`. Null when the device does not
66677
+ * report it. */
66678
+ powerSource: _enum(["mains", "battery"]).nullable(),
66157
66679
  /**
66158
66680
  * Desiccant life remaining, stored in seconds (duration base, D944).
66159
66681
  * Providers convert from the days the feeder reports. Null when the
@@ -66181,6 +66703,14 @@ object({
66181
66703
  feedSound: boolean(),
66182
66704
  /** Speaker / prompt volume level (device-scaled integer). */
66183
66705
  volume: number().meta(readingMeta("none")),
66706
+ /** Portion (grams) of the last manual feed sent from a single-hopper
66707
+ * stepper — the default the next manual feed starts from. Persisted per
66708
+ * device by the provider; null until a manual feed has been sent. */
66709
+ lastFeedGrams: gramsPortion.nullable(),
66710
+ /** Hopper-1 portion of the last manual feed (dual-hopper); null until sent. */
66711
+ lastFeedHopper1: gramsPortion.nullable(),
66712
+ /** Hopper-2 portion of the last manual feed (dual-hopper); null until sent. */
66713
+ lastFeedHopper2: gramsPortion.nullable(),
66184
66714
  /** Ms epoch when the slice was last refreshed from the cloud. */
66185
66715
  lastFetchedAt: number()
66186
66716
  });
@@ -71346,6 +71876,14 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
71346
71876
  kind: "mutation",
71347
71877
  auth: "admin"
71348
71878
  });
71879
+ discriminatedUnion("kind", [object({
71880
+ kind: literal("raw"),
71881
+ timings: array(number().int()),
71882
+ settings: TransmitSettingsSchema.optional()
71883
+ }), object({
71884
+ kind: literal("pronto"),
71885
+ code: string()
71886
+ })]);
71349
71887
  /**
71350
71888
  * Which of OUR object detections a clip window holds — the ONE overlap rule
71351
71889
  * and the ONE label ranking, for every clip source (D923).
@@ -71388,7 +71926,7 @@ function dominantClipLabels(events) {
71388
71926
  }
71389
71927
  DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
71390
71928
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
71391
- 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.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, 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.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.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.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.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
71929
+ 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.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, 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.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.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.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.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;
71392
71930
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
71393
71931
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
71394
71932
  new Set(CAP_NAMES);
@@ -75011,6 +75549,20 @@ Object.freeze({
75011
75549
  access: "create",
75012
75550
  role: "viewer"
75013
75551
  },
75552
+ "irTransmitter.getInfo": {
75553
+ capName: "ir-transmitter",
75554
+ capScope: "device",
75555
+ addonId: null,
75556
+ access: "view",
75557
+ role: "viewer"
75558
+ },
75559
+ "irTransmitter.send": {
75560
+ capName: "ir-transmitter",
75561
+ capScope: "device",
75562
+ addonId: null,
75563
+ access: "create",
75564
+ role: "viewer"
75565
+ },
75014
75566
  "keychain.delete": {
75015
75567
  capName: "keychain",
75016
75568
  capScope: "system",
@@ -79134,6 +79686,41 @@ Object.freeze({
79134
79686
  access: "create",
79135
79687
  role: "admin"
79136
79688
  },
79689
+ "remote.getConfig": {
79690
+ capName: "remote",
79691
+ capScope: "system",
79692
+ addonId: null,
79693
+ access: "view",
79694
+ role: "admin"
79695
+ },
79696
+ "remote.listCommands": {
79697
+ capName: "remote",
79698
+ capScope: "system",
79699
+ addonId: null,
79700
+ access: "view",
79701
+ role: "admin"
79702
+ },
79703
+ "remote.sendCommand": {
79704
+ capName: "remote",
79705
+ capScope: "system",
79706
+ addonId: null,
79707
+ access: "create",
79708
+ role: "admin"
79709
+ },
79710
+ "remote.sendMediaCommand": {
79711
+ capName: "remote",
79712
+ capScope: "system",
79713
+ addonId: null,
79714
+ access: "create",
79715
+ role: "admin"
79716
+ },
79717
+ "remote.setConfig": {
79718
+ capName: "remote",
79719
+ capScope: "system",
79720
+ addonId: null,
79721
+ access: "create",
79722
+ role: "admin"
79723
+ },
79137
79724
  "runningState.getStatus": {
79138
79725
  capName: "running-state",
79139
79726
  capScope: "device",
@@ -80324,6 +80911,41 @@ Object.freeze({
80324
80911
  access: "view",
80325
80912
  role: "viewer"
80326
80913
  },
80914
+ "template.create": {
80915
+ capName: "template",
80916
+ capScope: "system",
80917
+ addonId: null,
80918
+ access: "create",
80919
+ role: "admin"
80920
+ },
80921
+ "template.delete": {
80922
+ capName: "template",
80923
+ capScope: "system",
80924
+ addonId: null,
80925
+ access: "delete",
80926
+ role: "admin"
80927
+ },
80928
+ "template.get": {
80929
+ capName: "template",
80930
+ capScope: "system",
80931
+ addonId: null,
80932
+ access: "view",
80933
+ role: "admin"
80934
+ },
80935
+ "template.list": {
80936
+ capName: "template",
80937
+ capScope: "system",
80938
+ addonId: null,
80939
+ access: "view",
80940
+ role: "admin"
80941
+ },
80942
+ "template.update": {
80943
+ capName: "template",
80944
+ capScope: "system",
80945
+ addonId: null,
80946
+ access: "create",
80947
+ role: "admin"
80948
+ },
80327
80949
  "terminalSession.adoptLegacyMonitor": {
80328
80950
  capName: "terminal-session",
80329
80951
  capScope: "system",
@@ -82634,6 +83256,11 @@ var ACTUATOR_CAP_VOCABULARY = {
82634
83256
  icon: "circle-dot"
82635
83257
  }]
82636
83258
  },
83259
+ "ir-transmitter": {
83260
+ scope: "device",
83261
+ noun: t("IR / RF transmitter", "Trasmettitore IR / RF"),
83262
+ notOperatorFacing: { send: "a raw pulse train is not something an operator composes in an automation; the remote that owns the command table sends it" }
83263
+ },
82637
83264
  control: {
82638
83265
  scope: "device",
82639
83266
  noun: t("Control", "Controllo"),
@@ -85150,6 +85777,7 @@ var SYSTEM_CAP_VOCABULARY = {
85150
85777
  "recording-archive": system(STORAGE),
85151
85778
  "recording-export": system("recording exports — requested from the timeline, not an automation step"),
85152
85779
  records: system(INTERNAL),
85780
+ remote: system("the per-device remote setup — authored in the Customize remote editor, sent through the remote UI"),
85153
85781
  "server-management": system(CLUSTER),
85154
85782
  "settings-store": system(INTERNAL),
85155
85783
  "smtp-provider": system(INTERNAL),
@@ -85162,6 +85790,7 @@ var SYSTEM_CAP_VOCABULARY = {
85162
85790
  "storage-provider": system(STORAGE),
85163
85791
  "stream-broker": system(PIPELINE),
85164
85792
  system: system(CLUSTER),
85793
+ template: system("operator-authored templates — edited in their own editor, never actuated"),
85165
85794
  "terminal-session": system(CLUSTER),
85166
85795
  toast: system(UI_PLUMBING),
85167
85796
  training: system(ML),
@@ -86353,6 +86982,16 @@ Object.freeze({
86353
86982
  form: "single",
86354
86983
  optional: false
86355
86984
  }],
86985
+ "irTransmitter.getInfo": [{
86986
+ name: "deviceId",
86987
+ form: "single",
86988
+ optional: false
86989
+ }],
86990
+ "irTransmitter.send": [{
86991
+ name: "deviceId",
86992
+ form: "single",
86993
+ optional: false
86994
+ }],
86356
86995
  "keychain.deleteDeviceScope": [{
86357
86996
  name: "deviceId",
86358
86997
  form: "single",
@@ -87578,6 +88217,31 @@ Object.freeze({
87578
88217
  form: "single",
87579
88218
  optional: true
87580
88219
  }],
88220
+ "remote.getConfig": [{
88221
+ name: "deviceId",
88222
+ form: "single",
88223
+ optional: false
88224
+ }],
88225
+ "remote.listCommands": [{
88226
+ name: "deviceId",
88227
+ form: "single",
88228
+ optional: false
88229
+ }],
88230
+ "remote.sendCommand": [{
88231
+ name: "deviceId",
88232
+ form: "single",
88233
+ optional: false
88234
+ }],
88235
+ "remote.sendMediaCommand": [{
88236
+ name: "deviceId",
88237
+ form: "single",
88238
+ optional: false
88239
+ }],
88240
+ "remote.setConfig": [{
88241
+ name: "deviceId",
88242
+ form: "single",
88243
+ optional: false
88244
+ }],
87581
88245
  "runningState.getStatus": [{
87582
88246
  name: "deviceId",
87583
88247
  form: "single",
@@ -91119,5 +91783,13 @@ function armRemovalReconcile(opts) {
91119
91783
  timer.unref?.();
91120
91784
  return () => clearInterval(timer);
91121
91785
  }
91786
+ object({
91787
+ manufacturer: string().optional(),
91788
+ supportedModels: array(string()).optional(),
91789
+ supportedController: string().optional(),
91790
+ commandsEncoding: string(),
91791
+ delay: number().nonnegative().optional(),
91792
+ commands: record(string(), unknown())
91793
+ });
91122
91794
  //#endregion
91123
91795
  export { applyModelBoundSettings as $, defineCustomActions as $n, parseProcStatus as $t, NativeLeaseAdmissionSchema as A, stripRetiredBandPreBufferSec as An, evictionPolicyForMode as At, RECORDING_SOURCE_CAMSTACK as B, isSoftwareDecode as Bn, isFirstLevelMacroClass as Bt, EVENT_PAD_MS as C, runtimeDevices as Cn, record as Cr, dominantClipLabels as Ct, G711_SCALE_CORRECTION_DB as D, storageEvictableCapability as Dn, enumerateInferenceDevices as Dt, FailureCounters as E, stepModelRunsOnFormat as En, EventCategory as Er, egressTransportFromRequest as Et, PIPELINE_RAMP as F, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as Fn, fuseRecoveredDetections as Ft, RecordingSignalStatusSchema as G, BaseAddon as Gn, mapAudioLabelToMacro as Gt, RECOVERY_MOTION_MAX_AGE_MS as H, DeviceType as Hn, linkedStepOf as Ht, PoolMemoryWatchdog as I, Fmp4BoxSplitter as In, gbToBytes as It, VISIT_MERGE_GAP_MS as J, HF_REPO as Jn, memoizePinnedFfmpeg as Jt, RingBuffer as K, CAM_PROFILE_ORDER as Kn, mayReadLocation as Kt, RATE_CONTROL_RELAXED as L, buildFfmpegArgs as Ln, gifDeriveSpeed as Lt, NodeBenchRunnerInputSchema as M, videoclipsCapability as Mn, exportSubjectOf as Mt, OBJECT_DETECTION_STEP_ID as N, webrtcSessionCapability as Nn, failureContributionCapability as Nt, LABEL_SUPPLY_MACRO as O, storageOccupancyCapability as On, evaluateZoneRules as Ot, OpsLogEntrySchema as P, AUDIO_PRESETS as Pn, ffmpegRate as Pt, applyCropClassFloors as Q, customAction as Qn, overlayClusterStepSettings as Qt, RATE_CONTROL_TIGHT as R, evaluateSensorEdge as Rn, gifFromMp4Args as Rt, EVENT_OWNER_TYPES as S, rootSuppliesOf as Sn, preprocess as Sr, deviceRemovalHookCapability as St, ExportRecordSchema as T, startMoverUnderClearance as Tn, union$1 as Tr, egressTranscodeSharingKey as Tt, ROOT_SUPPLIABLE_STEP_IDS as U, errMsg as Un, loadContributionCapability as Ut, RECORDING_SOURCE_CAMSTACK_ADDON as V, DeviceFeature as Vn, linkedLabelStepId as Vt, RecordingConfigSchema as W, BOOT_RECOVERY_BACKOFF_MS as Wn, logChannelsCapability as Wt, addonWidgetsSourceCapability as X, audioChunkBytesPerSample as Xn, modeMayWrite as Xt, YAMNET_TO_MACRO as Y, MODEL_FORMATS as Yn, migrateLegacyDeviceSignalConfig as Yt, allowedSuppliedEffect as Z, createEvent as Zn, motionDetectionCapability as Zt, DEFAULT_DETAIL_CROP_CONVENTION as _, resolveLocationMode as _n, discriminatedUnion as _r, deriveBatteryPresence as _t, BackgroundRunRegistry as a, planMotionCrops as an, isSecretMarker as ar, buildBenchStepTree as at, DEVICE_BACKEND_TO_FORMAT as b, resolveRecordingProfiles as bn, number as br, deriveRootFaceRefineRect as bt, CLIP_STILL_REASON_CODE_HEADER as c, readRecoveryRecipeForSteps as cn, maskUrlCredentials as cr, clipExportFailure as ct, CLUSTER_MODEL_SCOPED_STEPS as d, recordingExportCapability as dn, selectAssignedProfileSlots as dr, containingParentIndex as dt, pickClusterStepSettings as en, defineRecordKinds as er, armRemovalReconcile as et, COCO_80_LABELS as f, recordingSignalCapability as fn, sleep as fr, countRecoverySkips as ft, DEFAULT_CLUSTER_STEP_SETTINGS as g, resolveEgressDecodeHwAccel as gn, boolean as gr, defaultDeviceFor as gt, DEFAULT_AUDIO_ANALYZER_CONFIG as h, resolveCreateExportSubject as hn, array as hr, declareLogChannel as ht, AUDIO_MACRO_LABELS as i, pipelineRunnerCapability as in, isEvent as ir, batteryCapability as it, NativeLeaseSettingsSchema as j, supportedRuntimes as jn, evictionPolicyOfLocation as jt, LABEL_SUPPLY_VOCABULARIES as k, streamBrokerCapability as kn, eventOverlapsClipWindow as kt, CLIP_STILL_REASON_HEADER as l, recordingArchiveCapability as ln, nodePin as lr, clipExportFailureOf as lt, CROP_SUPPLY_SOURCES as m, resolveClusterStepModelId as mn, _enum as mr, createLogChannelsProvider as mt, APPLE_SA_TO_MACRO as n, pickNativeLeaseOverride as nn, hfModelUrl as nr, audioAnalyzerCapability as nt, BatteryStatusSchema as o, planRecoveryCrops as on, makeProfileBrokerId as or, cameraOwnsMotionViaSensor as ot, COCO_TO_MACRO as p, remapCropDetections as pn, userError as pr, createHwAccelCache as pt, VIDEOCLIPS_MAX_OFFER_BYTES as q, CamProfileSchema as qn, mayWriteToLocation as qt, AUDIO_BACKEND_CHOICES as r, pipelineExecutorCapability as rn, hydrateSchema as rr, audioKindId as rt, CLIP_BROKER_PACED_RATES as s, rankStreams as sn, makeSourceBrokerId as sr, cameraStreamsCapability as st, APPEARANCE_BLOCKS as t, pickDetailCropConvention as tn, expandAudioChunkToF32le as tr, audioAnalysisCapability as tt, CLIP_STREAM_TRANSPORT_HEADER as u, recordingCapability as un, parseProfileBrokerId as ur, collectModelBoundKeys as ut, DEFAULT_EVENTS_BAND_BUFFER_SEC as v, resolveModelBoundSetting as vn, lazy as vr, deriveDetailCropRect as vt, EncodeProfileSchema as w, selectRecoveryStep as wn, string as wr, edgetpuDelegateDevice as wt, DEVICE_RAMP as x, resolveRootSupply as xn, object as xr, detectionPipelineCapability as xt, DEFAULT_NATIVE_LEASE_SETTINGS as y, resolvePoolMemoryPolicy as yn, literal as yr, deriveRecordingMode as yt, RECORDING_EXPORT_MAX_READ_BYTES as z, invocationFromEncodeProfile as zn, inferModelProvider as zt };