@camstack/addon-provider-bosch 0.1.52 → 0.1.54

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.
@@ -6044,7 +6044,7 @@ var ZodIssueCode = {
6044
6044
  var ZodFirstPartyTypeKind;
6045
6045
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
6046
6046
  //#endregion
6047
- //#region ../types/dist/sleep-Bn346wCJ.mjs
6047
+ //#region ../types/dist/sleep-D0roI_CZ.mjs
6048
6048
  /**
6049
6049
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6050
6050
  * window to float samples (D455).
@@ -16242,6 +16242,10 @@ Object.freeze({
16242
16242
  "path": "lastEvent.eventType",
16243
16243
  "valueType": "string"
16244
16244
  },
16245
+ {
16246
+ "path": "lastEvent.sourceId",
16247
+ "valueType": "string"
16248
+ },
16245
16249
  {
16246
16250
  "path": "lastEvent.timestamp",
16247
16251
  "valueType": "number"
@@ -44093,6 +44097,51 @@ function macroOnly(macro) {
44093
44097
  };
44094
44098
  }
44095
44099
  }
44100
+ var EventVocabularyKindSchema = _enum([
44101
+ "press",
44102
+ "long-press",
44103
+ "long-press-start",
44104
+ "release",
44105
+ "repeat",
44106
+ "double-press",
44107
+ "other"
44108
+ ]);
44109
+ /** The part of the device an event comes from: a button, a channel. */
44110
+ var EventVocabularySourceSchema = object({
44111
+ id: string().min(1),
44112
+ label: string().min(1)
44113
+ });
44114
+ /** One scalar field of an event's `data`, by dotted path. */
44115
+ var EventVocabularyFieldSchema = object({
44116
+ path: string().min(1),
44117
+ kind: _enum([
44118
+ "string",
44119
+ "number",
44120
+ "boolean",
44121
+ "enum"
44122
+ ]),
44123
+ enumValues: array(string()).optional(),
44124
+ label: string().min(1).optional()
44125
+ });
44126
+ var EventVocabularyEntrySchema = object({
44127
+ /** The native token, verbatim. */
44128
+ id: string().min(1),
44129
+ source: EventVocabularySourceSchema.optional(),
44130
+ label: string().min(1),
44131
+ description: string().optional(),
44132
+ kind: EventVocabularyKindSchema.optional(),
44133
+ payload: array(EventVocabularyFieldSchema).optional()
44134
+ });
44135
+ /**
44136
+ * The vocabulary of a source that declares tokens and nothing else: one
44137
+ * entry per token, labelled with the token itself.
44138
+ */
44139
+ function plainEventVocabulary(eventTypes) {
44140
+ return [...new Set(eventTypes)].filter((eventType) => eventType !== "").map((eventType) => ({
44141
+ id: eventType,
44142
+ label: eventType
44143
+ }));
44144
+ }
44096
44145
  Math.PI / 180;
44097
44146
  /**
44098
44147
  * WHEN something happens, as data (D983) — the one time vocabulary of the
@@ -44300,6 +44349,33 @@ var ScheduleLeafSchema = object({
44300
44349
  /** @deprecated legacy cron — new schedules use `at`. */
44301
44350
  cron: string().min(1).max(120).optional()
44302
44351
  }).refine((leaf) => leaf.at === void 0 !== (leaf.cron === void 0), { message: "a schedule names exactly one of `at` (a time spec) and `cron` (legacy)" }).refine((leaf) => leaf.days === void 0 || leaf.at !== void 0, { message: "`days` goes with `at`; a cron expression carries its own days" });
44352
+ /**
44353
+ * One payload predicate of a `device-fired` row: the value at `path` inside
44354
+ * the fire's `data` (dotted) equals `equals`. Compared strictly, no coercion.
44355
+ */
44356
+ var DeviceFiredMatchSchema = object({
44357
+ path: string().min(1).max(120),
44358
+ equals: union([
44359
+ string(),
44360
+ number$1(),
44361
+ boolean()
44362
+ ])
44363
+ });
44364
+ /**
44365
+ * "fires": one device of the `event-emitter` capability reported an event
44366
+ * (D1045). Every list is an OR, the lists together an AND; an absent list does
44367
+ * not narrow. `eventIds` are the device's own tokens, `sourceIds` the parts of
44368
+ * the device (a button), `kinds` the shared press kinds of its vocabulary.
44369
+ */
44370
+ var DeviceFiredLeafSchema = object({
44371
+ kind: literal("device-fired"),
44372
+ ...eventLeafId,
44373
+ deviceId: number$1().int().nonnegative(),
44374
+ eventIds: array(string().min(1)).min(1).max(64).optional(),
44375
+ sourceIds: array(string().min(1)).min(1).max(64).optional(),
44376
+ kinds: array(EventVocabularyKindSchema).min(1).optional(),
44377
+ match: array(DeviceFiredMatchSchema).min(1).max(8).optional()
44378
+ });
44303
44379
  var ManualLeafSchema = object({
44304
44380
  kind: literal("manual"),
44305
44381
  ...eventLeafId
@@ -44441,6 +44517,7 @@ var AutomationWhenSchema = lazy(() => discriminatedUnion("kind", [
44441
44517
  }),
44442
44518
  DeviceBecomesLeafSchema,
44443
44519
  DeviceEventLeafSchema,
44520
+ DeviceFiredLeafSchema,
44444
44521
  ScheduleLeafSchema,
44445
44522
  ManualLeafSchema,
44446
44523
  IntervalLeafSchema,
@@ -44455,6 +44532,7 @@ var AutomationWhenSchema = lazy(() => discriminatedUnion("kind", [
44455
44532
  var EVENT_KINDS = new Set([
44456
44533
  "device-becomes",
44457
44534
  "device-event",
44535
+ "device-fired",
44458
44536
  "schedule",
44459
44537
  "manual",
44460
44538
  "interval",
@@ -44535,6 +44613,7 @@ function hasEmptyContainer(node) {
44535
44613
  var LEAF_WORDS = {
44536
44614
  "device-becomes": "a device value that becomes",
44537
44615
  "device-event": "a device event",
44616
+ "device-fired": "a device firing an event",
44538
44617
  schedule: "a schedule",
44539
44618
  manual: "a manual run",
44540
44619
  interval: "an interval",
@@ -44800,9 +44879,12 @@ function convertLegacyWhen(half) {
44800
44879
  * every caller — automations, Actions, and the notification centre, which runs
44801
44880
  * only Actions (planning#473).
44802
44881
  */
44882
+ /** The longest one `wait` step lasts. It is cut by a restart of the run and does not survive a hub restart. */
44883
+ var WAIT_MAX_SECONDS = 3600;
44884
+ var WAIT_TOO_LONG = `a wait is at most one hour (${WAIT_MAX_SECONDS} s)`;
44803
44885
  var AutomationWaitStepSchema = object({
44804
44886
  kind: literal("wait"),
44805
- seconds: number$1().min(0).max(300)
44887
+ seconds: number$1().min(0).max(WAIT_MAX_SECONDS, WAIT_TOO_LONG)
44806
44888
  });
44807
44889
  /** The legacy `deviceId` of a cap step: still READ, never written (D983). */
44808
44890
  var LegacyStepDeviceSchema = union([
@@ -44872,39 +44954,227 @@ var elseNeedsIf = {
44872
44954
  path: ["else"]
44873
44955
  };
44874
44956
  var GuardedWaitStepSchema = AutomationWaitStepSchema.extend(stepGuardShape).refine((step) => step.else === void 0 || step.if !== void 0, elseNeedsIf);
44875
- var GuardedCapStepSchema = AutomationCapStepBaseSchema.extend(stepGuardShape).refine((step) => step.target !== void 0 || step.deviceId !== void 0, {
44876
- message: "a cap step needs a target",
44877
- path: ["target"]
44878
- }).refine((step) => step.target?.kind !== "domain" || step.actionId !== void 0, {
44879
- message: "a domain target needs the vocabulary action it applies to (actionId)",
44880
- path: ["actionId"]
44881
- }).refine((step) => step.else === void 0 || step.if !== void 0, elseNeedsIf);
44882
44957
  /**
44883
44958
  * A step of a STANDALONE list (an action, a scheduler point, a preset): the
44884
44959
  * same two step kinds an automation runs, minus a guard that reads the
44885
44960
  * automation's trigger, which such a list does not have.
44886
44961
  */
44887
- var ActionStepSchema = discriminatedUnion("kind", [GuardedWaitStepSchema, GuardedCapStepSchema]).superRefine((step, ctx) => {
44962
+ var ActionStepSchema = discriminatedUnion("kind", [GuardedWaitStepSchema, AutomationCapStepBaseSchema.extend(stepGuardShape).refine((step) => step.target !== void 0 || step.deviceId !== void 0, {
44963
+ message: "a cap step needs a target",
44964
+ path: ["target"]
44965
+ }).refine((step) => step.target?.kind !== "domain" || step.actionId !== void 0, {
44966
+ message: "a domain target needs the vocabulary action it applies to (actionId)",
44967
+ path: ["actionId"]
44968
+ }).refine((step) => step.else === void 0 || step.if !== void 0, elseNeedsIf)]).superRefine((step, ctx) => {
44888
44969
  if (step.if !== void 0 && hasTriggeredByLeaves(step.if)) ctx.addIssue({
44889
44970
  code: "custom",
44890
44971
  message: TRIGGERED_BY_NEEDS_AUTOMATION,
44891
44972
  path: ["if"]
44892
44973
  });
44893
44974
  });
44975
+ /**
44976
+ * Flow control of an AUTOMATION's list (#500). A standalone list (an action, a
44977
+ * scheduler point, a preset) stays `wait` and `cap`: it has no run of its own
44978
+ * to end and no variable bag to write.
44979
+ */
44980
+ var continueOnErrorShape = {
44981
+ /** A failure of this step is traced `failed-continued` and the next step runs. */
44982
+ continueOnError: literal(true).optional() };
44983
+ /** An automation's cap step: the shared guarded cap step, plus `continueOnError`. */
44984
+ var AutomationGuardedCapStepSchema = AutomationCapStepBaseSchema.extend({
44985
+ ...stepGuardShape,
44986
+ ...continueOnErrorShape
44987
+ }).refine((step) => step.target !== void 0 || step.deviceId !== void 0, {
44988
+ message: "a cap step needs a target",
44989
+ path: ["target"]
44990
+ }).refine((step) => step.target?.kind !== "domain" || step.actionId !== void 0, {
44991
+ message: "a domain target needs the vocabulary action it applies to (actionId)",
44992
+ path: ["actionId"]
44993
+ }).refine((step) => step.else === void 0 || step.if !== void 0, elseNeedsIf);
44994
+ /** End the run here, on purpose. `reason` may carry `{{vars.x}}` slots. */
44995
+ var AutomationStopStepSchema = object({
44996
+ kind: literal("stop"),
44997
+ reason: string().min(1, "a stop needs a reason: it is what the run trace shows").max(200),
44998
+ /** `ok`: the run ends as a success. `failed`: it ends as a failure, with the reason. */
44999
+ outcome: _enum(["ok", "failed"]),
45000
+ /** Stop only when this reads true; false or unknown does not stop. */
45001
+ if: AutomationWhenSchema.optional()
45002
+ });
45003
+ var SET_VAR_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]{0,39}$/;
45004
+ /** Names the run itself writes and reads (`leaf` is what `triggered-by` judges): a step may not overwrite them. */
45005
+ var RESERVED_RUN_VARS = [
45006
+ "kind",
45007
+ "leaf",
45008
+ "at"
45009
+ ];
45010
+ /**
45011
+ * Write variables into the run's bag, for the steps after it. SUBSTITUTION
45012
+ * only, never evaluation: a text value may carry `{{vars.x}}` slots.
45013
+ */
45014
+ var AutomationSetStepSchema = object({
45015
+ kind: literal("set"),
45016
+ vars: record(string(), union([
45017
+ string().max(500),
45018
+ number$1(),
45019
+ boolean()
45020
+ ])).refine((vars) => Object.keys(vars).every((name) => SET_VAR_NAME_RE.test(name)), { message: "a variable name is letters, digits and _, not starting with a digit (max 40)" }).refine((vars) => Object.keys(vars).length >= 1, { message: "set needs at least one variable" }).refine((vars) => Object.keys(vars).length <= 20, { message: `set holds at most 20 variables` }).refine((vars) => Object.keys(vars).every((name) => !RESERVED_RUN_VARS.includes(name)), { message: `the names ${RESERVED_RUN_VARS.join(", ")} belong to the run and cannot be set` }),
45021
+ /** Set only when this reads true; false or unknown leaves the bag as it is. */
45022
+ if: AutomationWhenSchema.optional()
45023
+ });
45024
+ var AutomationRunActionStepSchema = object({
45025
+ kind: literal("action"),
45026
+ /** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
45027
+ actionId: string().min(1),
45028
+ /** Values for the action's declared variables; the others take their default. */
45029
+ variables: record(string(), union([
45030
+ string(),
45031
+ number$1(),
45032
+ boolean()
45033
+ ])).optional(),
45034
+ ...continueOnErrorShape
45035
+ });
45036
+ /**
45037
+ * A step INSIDE a branch of a `choose`: a flow step with no condition of its
45038
+ * own (the branch is the condition) and no block inside it. Strict, so an `if`
45039
+ * written on such a step is refused rather than dropped.
45040
+ */
45041
+ /** The longest a `wait-until` may wait: six hours. */
45042
+ var WAIT_UNTIL_TIMEOUT_MAX_S = 21600;
45043
+ /**
45044
+ * Pause the run until a condition is true (#500). The timeout is mandatory: a
45045
+ * run never waits without an end. `onTimeout` says what a wait that ran out
45046
+ * does: `continue` goes on to the next step, `stop` ends the run as a failure.
45047
+ * A condition that cannot be read is not "true": the wait goes on (D49).
45048
+ */
45049
+ var AutomationWaitUntilStepSchema = object({
45050
+ kind: literal("wait-until"),
45051
+ when: AutomationWhenSchema,
45052
+ timeoutS: number$1().int().min(1, "a wait needs a timeout of at least one second").max(WAIT_UNTIL_TIMEOUT_MAX_S, `a wait for a condition is at most six hours (${WAIT_UNTIL_TIMEOUT_MAX_S} s)`),
45053
+ onTimeout: _enum(["continue", "stop"])
45054
+ }).strict();
45055
+ /** The step kinds that hold steps of their own, or pause on a condition: they nest two levels at most. */
45056
+ var BLOCK_STEP_KINDS = [
45057
+ "choose",
45058
+ "repeat",
45059
+ "parallel",
45060
+ "wait-until"
45061
+ ];
45062
+ var NEST_TOO_DEEP = `steps nest two levels at most: a step inside a nested choose or repeat can be a plain step only`;
45063
+ function kindOf(input) {
45064
+ return typeof input === "object" && input !== null ? Reflect.get(input, "kind") : void 0;
45065
+ }
45066
+ /** Where the nesting ends, a block step is refused in words rather than as an unknown kind. */
45067
+ function nestTooDeep(issue) {
45068
+ const kind = kindOf(issue.input);
45069
+ return typeof kind === "string" && BLOCK_STEP_KINDS.includes(kind) ? NEST_TOO_DEEP : void 0;
45070
+ }
45071
+ var plainStepSchemas = [
45072
+ AutomationWaitStepSchema.strict(),
45073
+ AutomationCapStepBaseSchema.extend(continueOnErrorShape).strict().refine((step) => step.target !== void 0 || step.deviceId !== void 0, {
45074
+ message: "a cap step needs a target",
45075
+ path: ["target"]
45076
+ }).refine((step) => step.target?.kind !== "domain" || step.actionId !== void 0, {
45077
+ message: "a domain target needs the vocabulary action it applies to (actionId)",
45078
+ path: ["actionId"]
45079
+ }),
45080
+ AutomationStopStepSchema.omit({ if: true }).strict(),
45081
+ AutomationSetStepSchema.omit({ if: true }).strict(),
45082
+ AutomationRunActionStepSchema.strict()
45083
+ ];
45084
+ /**
45085
+ * A plain step: a flow step with no condition of its own and no step inside
45086
+ * it. The second (last) level of nesting holds these only.
45087
+ */
45088
+ var AutomationBranchStepSchema = discriminatedUnion("kind", plainStepSchemas, { error: nestTooDeep });
45089
+ /** A step that can run beside others: it writes no variable and does not end the run. */
45090
+ var AutomationParallelMemberSchema = AutomationBranchStepSchema.refine((step) => step.kind === "cap" || step.kind === "action" || step.kind === "wait", "a parallel holds device commands, actions and waits only: a set or a stop beside other steps has no order");
45091
+ /**
45092
+ * Several steps at once (#500): all are started together and all are awaited.
45093
+ * A failure fails the run once the others finished, as in a sequence; a member
45094
+ * marked "continue if this fails" does not.
45095
+ */
45096
+ var AutomationParallelStepSchema = object({
45097
+ kind: literal("parallel"),
45098
+ steps: array(AutomationParallelMemberSchema).min(2, "a parallel needs at least two steps").max(5, `a parallel takes at most 5 steps`)
45099
+ }).strict();
45100
+ var REPEAT_NEEDS_MAX = "a repeat on a condition needs a maximum number of iterations";
45101
+ /** A loop on a condition: the bound is mandatory, so a run never loops without an end. */
45102
+ var repeatConditionShape = {
45103
+ when: AutomationWhenSchema,
45104
+ maxIterations: number$1({ error: REPEAT_NEEDS_MAX }).int().min(1, REPEAT_NEEDS_MAX).max(50, `a repeat on a condition runs at most 50 times`),
45105
+ /** A pause between two iterations, never after the last. */
45106
+ waitS: number$1().int().min(1).max(WAIT_MAX_SECONDS, WAIT_TOO_LONG).optional()
45107
+ };
45108
+ /** What decides how many times a `repeat` runs. */
45109
+ var AutomationRepeatLoopSchema = discriminatedUnion("by", [
45110
+ object({
45111
+ by: literal("count"),
45112
+ count: number$1().int().min(1).max(20, `a repeat runs at most 20 times`)
45113
+ }).strict(),
45114
+ object({
45115
+ by: literal("while"),
45116
+ ...repeatConditionShape
45117
+ }).strict(),
45118
+ object({
45119
+ by: literal("until"),
45120
+ ...repeatConditionShape
45121
+ }).strict(),
45122
+ object({
45123
+ by: literal("forEach"),
45124
+ target: object({
45125
+ kind: literal("devices"),
45126
+ ids: array(number$1().int()).min(1, "a repeat over devices needs at least one device").max(50, `a repeat over devices takes at most 50 devices`)
45127
+ }).strict()
45128
+ }).strict()
45129
+ ]);
45130
+ /**
45131
+ * The same steps several times (#500). Every form is bounded at save, so a
45132
+ * run cannot loop without an end. A failure or a `stop` in the steps ends the
45133
+ * loop and the run, as in a sequence.
45134
+ */
45135
+ function repeatSchemaOf(step) {
45136
+ return object({
45137
+ kind: literal("repeat"),
45138
+ loop: AutomationRepeatLoopSchema,
45139
+ steps: array(step).min(1, "a repeat needs at least one step").max(10, `a repeat takes at most 10 steps`)
45140
+ }).strict();
45141
+ }
45142
+ /**
45143
+ * One step, several ways (#500): the branches are read in order and the FIRST
45144
+ * whose condition is true runs; `else` runs when every branch is false. A
45145
+ * branch that cannot be read ends the choice: nothing runs, not the branches
45146
+ * after it and not the else (D49). The #472 `if` / `else` of a wait or cap
45147
+ * step is the one-branch case and stays as it is stored.
45148
+ */
45149
+ function chooseSchemaOf(step) {
45150
+ const steps = array(step).max(10);
45151
+ return object({
45152
+ kind: literal("choose"),
45153
+ branches: array(object({
45154
+ if: AutomationWhenSchema,
45155
+ steps: steps.min(1, "a branch needs at least one step")
45156
+ })).min(1, "a choose needs at least one branch").max(6, `a choose takes at most 6 branches`),
45157
+ else: steps.optional()
45158
+ });
45159
+ }
45160
+ var AutomationBodyStepSchema = discriminatedUnion("kind", [
45161
+ ...plainStepSchemas,
45162
+ AutomationWaitUntilStepSchema,
45163
+ AutomationParallelStepSchema,
45164
+ chooseSchemaOf(AutomationBranchStepSchema),
45165
+ repeatSchemaOf(AutomationBranchStepSchema)
45166
+ ]);
45167
+ var AutomationRepeatStepSchema = repeatSchemaOf(AutomationBodyStepSchema);
44894
45168
  var AutomationActionSchema = discriminatedUnion("kind", [
44895
45169
  GuardedWaitStepSchema,
44896
- GuardedCapStepSchema,
44897
- object({
44898
- kind: literal("action"),
44899
- /** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
44900
- actionId: string().min(1),
44901
- /** Values for the action's declared variables; the others take their default. */
44902
- variables: record(string(), union([
44903
- string(),
44904
- number$1(),
44905
- boolean()
44906
- ])).optional()
44907
- }),
45170
+ AutomationGuardedCapStepSchema,
45171
+ AutomationStopStepSchema,
45172
+ AutomationSetStepSchema,
45173
+ chooseSchemaOf(AutomationBodyStepSchema),
45174
+ AutomationWaitUntilStepSchema,
45175
+ AutomationParallelStepSchema,
45176
+ AutomationRepeatStepSchema,
45177
+ AutomationRunActionStepSchema,
44908
45178
  object({
44909
45179
  kind: literal("code"),
44910
45180
  /** Compiled into the automation's OWN block by esbuild — not a third
@@ -44967,11 +45237,6 @@ function convertLegacyRecipe(legacy) {
44967
45237
  ...rest
44968
45238
  };
44969
45239
  }
44970
- /**
44971
- * Where recipes are PARSED (the core-blocks cap, the MCP tool, the literal a
44972
- * saved block carries): the new shape as it is, or the old shape converted to
44973
- * it. The output type is always the new one.
44974
- */
44975
45240
  var AutomationRecipeSchema = union([CurrentAutomationRecipeSchema, LegacyAutomationRecipeSchema.transform(convertLegacyRecipe)]);
44976
45241
  var DETECTION_DESCRIPTIONS = {
44977
45242
  deviceId: "the camera that saw it",
@@ -44992,6 +45257,16 @@ var BECOMES_DESCRIPTIONS = {
44992
45257
  from: "the value before the change, empty when it is not known",
44993
45258
  to: "the value it changed to"
44994
45259
  };
45260
+ /**
45261
+ * A fire's payload is offered too, as `data.<path>` (`{{vars.data.channel}}`):
45262
+ * those names depend on the device, so they are not in this list.
45263
+ */
45264
+ var FIRED_DESCRIPTIONS = {
45265
+ deviceId: "the device that fired",
45266
+ eventType: "the event, as the device names it",
45267
+ sourceId: "the part of the device that fired (a button), empty when it names none",
45268
+ eventKind: "the kind of press (press, long-press …), empty when the device declares none"
45269
+ };
44995
45270
  function describe$1(descriptions) {
44996
45271
  return Object.entries(descriptions).map(([name, description]) => ({
44997
45272
  name,
@@ -45000,12 +45275,74 @@ function describe$1(descriptions) {
45000
45275
  }
45001
45276
  describe$1(DETECTION_DESCRIPTIONS);
45002
45277
  describe$1(STATIONARY_DESCRIPTIONS);
45278
+ describe$1(FIRED_DESCRIPTIONS).map((v) => v.name === "deviceId" ? {
45279
+ ...v,
45280
+ hintKey: "firedDeviceId"
45281
+ } : v);
45003
45282
  describe$1(BECOMES_DESCRIPTIONS).map((v) => v.name === "deviceId" ? {
45004
45283
  ...v,
45005
45284
  hintKey: "becomesDeviceId"
45006
45285
  } : v);
45007
45286
  new Set(Object.values(COCO_TO_MACRO.mapping));
45008
45287
  /**
45288
+ * Generic stateless event emitter. Installed on a `DeviceType.EventEmitter`
45289
+ * device. Carries the device's EXACT declared event vocabulary verbatim
45290
+ * (NO normalization). Two shapes:
45291
+ * - structured source (HA `event.*` entity) → `vocabulary` is the fixed
45292
+ * declared set (e.g. press_short, press_long, …).
45293
+ * - generic/legacy source (HA bus events, e.g. zha_event) → `vocabulary`
45294
+ * is [] (open) and `lastEvent.data` carries the complex payload.
45295
+ * `vocabulary` (D1044) names each event for a person and types it for a
45296
+ * rule; `eventTypes` is its list of native tokens, kept for older readers.
45297
+ * A fire names the part of the device it came from in `sourceId` when the
45298
+ * vocabulary declares sources (a remote's buttons).
45299
+ * `seq` is monotonic so two identical events still produce distinct slice writes.
45300
+ */
45301
+ var EventFireSchema = object({
45302
+ deviceId: number$1(),
45303
+ eventType: string(),
45304
+ sourceId: string().optional(),
45305
+ data: record(string(), unknown()).nullable(),
45306
+ timestamp: number$1().meta(readingMeta("none")),
45307
+ seq: number$1().meta(readingMeta("count"))
45308
+ });
45309
+ var EventEmitterStatusSchema = object({
45310
+ eventTypes: array(string()),
45311
+ /**
45312
+ * Required of a provider by the type. A status written before the field
45313
+ * existed still parses, as an empty vocabulary: read it through
45314
+ * `readEventVocabulary`, which then answers with the plain tokens.
45315
+ */
45316
+ vocabulary: array(EventVocabularyEntrySchema).default([]),
45317
+ lastEvent: EventFireSchema.nullable(),
45318
+ eventCountSinceStart: number$1().meta(readingMeta("count"))
45319
+ });
45320
+ var eventEmitterCapability = {
45321
+ name: "event-emitter",
45322
+ scope: "device",
45323
+ deviceNative: true,
45324
+ mode: "singleton",
45325
+ deviceTypes: [DeviceType.EventEmitter],
45326
+ methods: {},
45327
+ events: { onEvent: { data: EventFireSchema } },
45328
+ status: {
45329
+ schema: EventEmitterStatusSchema,
45330
+ kind: "push"
45331
+ },
45332
+ runtimeState: EventEmitterStatusSchema,
45333
+ /**
45334
+ * Runtime-state durability: **session** — `eventCountSinceStart` names its own scope.
45335
+ *
45336
+ * See `RuntimeStateDurability`. Enforced by
45337
+ * `scripts/check-runtime-state-durability.ts`.
45338
+ */
45339
+ durability: "session",
45340
+ /**
45341
+ * History (D850): none — `eventCountSinceStart` resets with the addon; events live in ledgers.
45342
+ */
45343
+ history: "none"
45344
+ };
45345
+ /**
45009
45346
  * Schedulers (D983) — an entity that performs actions over the day.
45010
45347
  *
45011
45348
  * A scheduler has profiles; a profile has weekdays and a timeline of POINTS.
@@ -45056,12 +45393,16 @@ var HoldOverrideSchema = discriminatedUnion("mode", [object({ mode: literal("res
45056
45393
  })]);
45057
45394
  /** A missed edge up to this late still runs. */
45058
45395
  var DEFAULT_MAX_LATE_MS = 10 * 6e4;
45396
+ var SchedulerStepSchema = ActionStepSchema.refine((step) => step.kind !== "wait" || step.seconds <= 300, {
45397
+ message: `a scheduler point waits at most five minutes (300 s); put a longer wait in an action`,
45398
+ path: ["seconds"]
45399
+ });
45059
45400
  var SchedulerPointSchema = object({
45060
45401
  id: string().min(1).max(64),
45061
45402
  at: SchedulerTimeSpecSchema,
45062
45403
  mode: SchedulerPointModeSchema,
45063
45404
  /** The actions of an `edge` or `hold`; a `release` has none. */
45064
- steps: array(ActionStepSchema).max(20).default([]),
45405
+ steps: array(SchedulerStepSchema).max(20).default([]),
45065
45406
  /** Checked when the point runs (an edge) or is applied (a hold). */
45066
45407
  conditions: SchedulerStateTreeSchema.optional(),
45067
45408
  /** Hold only; absent means `respect`. */
@@ -45259,6 +45600,7 @@ var AutomationConditionTraceNodeSchema = object({
45259
45600
  "triggered-by",
45260
45601
  "device-becomes",
45261
45602
  "device-event",
45603
+ "device-fired",
45262
45604
  "schedule",
45263
45605
  "interval",
45264
45606
  "manual",
@@ -45329,18 +45671,46 @@ var StepTraceBaseSchema = object({
45329
45671
  ]).optional(),
45330
45672
  /** Why the condition read what it read, in the evaluator's own words. */
45331
45673
  conditionReason: string().optional(),
45332
- /** `empty`: the target resolved to no device, so nothing was done — never silently `ok`. `skipped`: its `if` was false (or unknown) and nothing ran in its place. */
45674
+ /** `empty`: the target resolved to no device, so nothing was done — never silently `ok`. `skipped`: its `if` was false (or unknown) and nothing ran in its place. `failed-continued`: it failed and was marked to be passed over (#500). */
45333
45675
  outcome: _enum([
45334
45676
  "ok",
45335
45677
  "error",
45336
45678
  "not-run",
45337
45679
  "empty",
45338
- "skipped"
45680
+ "skipped",
45681
+ "failed-continued",
45682
+ "timed-out"
45339
45683
  ]),
45340
45684
  message: string().optional()
45341
45685
  });
45686
+ /** What a block step adds to its row: which list ran, what each branch read, how many rounds. */
45687
+ var blockTraceShape = {
45688
+ /** A `choose` step (#500): the list that ran, `branches.<n>` or `else`. Absent when none did. */
45689
+ branch: string().optional(),
45690
+ /** A `choose` step: what each branch read, in order, up to the one that decided. */
45691
+ branchChecks: array(object({
45692
+ condition: _enum([
45693
+ "true",
45694
+ "false",
45695
+ "unknown"
45696
+ ]),
45697
+ conditionReason: string().optional()
45698
+ })).optional(),
45699
+ /** A `repeat` step (#500): how many times its steps ran. */
45700
+ iterations: number$1().int().optional()
45701
+ };
45702
+ /** A step one level down: it may be a block step itself, whose own steps are plain rows (the nesting ends there). */
45703
+ var NestedStepTraceSchema = StepTraceBaseSchema.extend({
45704
+ ...blockTraceShape,
45705
+ steps: array(StepTraceBaseSchema).optional()
45706
+ });
45342
45707
  /** A step trace; the `else` steps that ran are one level of the same shape (the nesting is bounded at one). */
45343
- var AutomationStepTraceSchema = StepTraceBaseSchema.extend({ else: array(StepTraceBaseSchema).optional() });
45708
+ var AutomationStepTraceSchema = StepTraceBaseSchema.extend({
45709
+ else: array(StepTraceBaseSchema).optional(),
45710
+ ...blockTraceShape,
45711
+ /** A `choose` step: the steps of the list that ran. A `parallel`: its members. A `repeat`: the LAST iteration. */
45712
+ steps: array(NestedStepTraceSchema).optional()
45713
+ });
45344
45714
  var AutomationRunTraceSchema = object({
45345
45715
  runId: string().min(1),
45346
45716
  startedAt: number$1(),
@@ -45747,7 +46117,9 @@ var AddonHttpRouteSchema = object({
45747
46117
  ]).optional(),
45748
46118
  description: string().optional(),
45749
46119
  /** The hub limits this route per client address before the handler runs. */
45750
- rateLimit: _enum(["auth"]).optional()
46120
+ rateLimit: _enum(["auth"]).optional(),
46121
+ /** Served once per integration instance; the handler reads `instanceId`. */
46122
+ perInstance: boolean().optional()
45751
46123
  });
45752
46124
  /**
45753
46125
  * Cross-process route invocation envelope. The hub captures the
@@ -45764,6 +46136,8 @@ var InvokeRequestSchema = object({
45764
46136
  query: record(string(), string()),
45765
46137
  body: unknown(),
45766
46138
  headers: record(string(), string()),
46139
+ /** The instance the hub resolved for a `perInstance` route. */
46140
+ instanceId: string().optional(),
45767
46141
  user: object({
45768
46142
  id: string(),
45769
46143
  username: string(),
@@ -56435,53 +56809,6 @@ var enumSensorCapability = {
56435
56809
  * whether persisting is worth a SQLite commit. */
56436
56810
  volatileStateFields: ["lastFetchedAt", "timestamp"]
56437
56811
  };
56438
- /**
56439
- * Generic stateless event emitter. Installed on a `DeviceType.EventEmitter`
56440
- * device. Carries the device's EXACT declared event vocabulary verbatim
56441
- * (NO normalization). Two shapes:
56442
- * - structured source (HA `event.*` entity) → `eventTypes` is the fixed
56443
- * declared vocabulary (e.g. ['press_short','press_long',...]).
56444
- * - generic/legacy source (HA bus events, e.g. zha_event) → `eventTypes`
56445
- * is [] (open) and `lastEvent.data` carries the complex payload.
56446
- * `seq` is monotonic so two identical events still produce distinct slice writes.
56447
- */
56448
- var EventFireSchema = object({
56449
- deviceId: number$1(),
56450
- eventType: string(),
56451
- data: record(string(), unknown()).nullable(),
56452
- timestamp: number$1().meta(readingMeta("none")),
56453
- seq: number$1().meta(readingMeta("count"))
56454
- });
56455
- var EventEmitterStatusSchema = object({
56456
- eventTypes: array(string()),
56457
- lastEvent: EventFireSchema.nullable(),
56458
- eventCountSinceStart: number$1().meta(readingMeta("count"))
56459
- });
56460
- var eventEmitterCapability = {
56461
- name: "event-emitter",
56462
- scope: "device",
56463
- deviceNative: true,
56464
- mode: "singleton",
56465
- deviceTypes: [DeviceType.EventEmitter],
56466
- methods: {},
56467
- events: { onEvent: { data: EventFireSchema } },
56468
- status: {
56469
- schema: EventEmitterStatusSchema,
56470
- kind: "push"
56471
- },
56472
- runtimeState: EventEmitterStatusSchema,
56473
- /**
56474
- * Runtime-state durability: **session** — `eventCountSinceStart` names its own scope.
56475
- *
56476
- * See `RuntimeStateDurability`. Enforced by
56477
- * `scripts/check-runtime-state-durability.ts`.
56478
- */
56479
- durability: "session",
56480
- /**
56481
- * History (D850): none — `eventCountSinceStart` resets with the addon; events live in ledgers.
56482
- */
56483
- history: "none"
56484
- };
56485
56812
  var IdentitySchema = object({
56486
56813
  id: string(),
56487
56814
  name: string(),
@@ -59084,6 +59411,12 @@ var IntegrationLiteSchema = object({
59084
59411
  var AvailableIntegrationTypeSchema = object({
59085
59412
  addonId: string(),
59086
59413
  name: string(),
59414
+ /**
59415
+ * Product name a new integration is prefilled from (`<label> - Home`).
59416
+ * Absent: the client uses `name`. Set when the catalog title is not the
59417
+ * product (Bosch SHC, MQTT).
59418
+ */
59419
+ providerLabel: string().optional(),
59087
59420
  description: string(),
59088
59421
  iconUrl: string().nullable(),
59089
59422
  color: string(),
@@ -71972,7 +72305,18 @@ var OauthIntegrationDescriptorSchema = object({
71972
72305
  * The value is baked into the authorization code at `/authorize` and travels
71973
72306
  * on the tokens, so editing this field changes FUTURE links only.
71974
72307
  */
71975
- refreshTokenTtlSec: union([number$1().int().positive(), literal("never")]).optional()
72308
+ refreshTokenTtlSec: union([number$1().int().positive(), literal("never")]).optional(),
72309
+ /**
72310
+ * The integration instances an account can be linked to (planning#415),
72311
+ * beside the default one. `/api/oauth2/authorize?instance=<id>` is accepted
72312
+ * only for an id listed here; with no `instance=` the link is made to the
72313
+ * default instance, which is never listed and always accepted — it is the
72314
+ * address third parties already hold. Omit for a single-instance integration.
72315
+ */
72316
+ instances: array(object({
72317
+ id: string(),
72318
+ displayName: string()
72319
+ })).optional()
71976
72320
  });
71977
72321
  method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
71978
72322
  /**
@@ -78909,6 +79253,13 @@ var SsoBridgeClaimsSchema = object({
78909
79253
  /** OAuth authorization-code binding — set only on `oauth-code` tokens. */
78910
79254
  redirectUri: string().optional(),
78911
79255
  integrationId: string().optional(),
79256
+ /**
79257
+ * The integration INSTANCE an OAuth link was made for (planning#415). Set on
79258
+ * `oauth-code`, `oauth-access` and `oauth-refresh` tokens of a link made
79259
+ * with `instance=`; absent on a link to the default instance. A cloud relay
79260
+ * reads it off the access token to route; the hub answers from the session.
79261
+ */
79262
+ instanceId: string().optional(),
78912
79263
  /** JWT ID — unique per issued code; consumed-set enforces single-use. */
78913
79264
  jti: string().optional(),
78914
79265
  /** PKCE S256 challenge — set only on `oauth-code` tokens issued to a public
@@ -81287,6 +81638,8 @@ var OauthSessionSummarySchema = object({
81287
81638
  userId: string(),
81288
81639
  username: string(),
81289
81640
  integrationId: string(),
81641
+ /** The instance the link was made for; `null` = the default instance. */
81642
+ instanceId: string().nullable().optional(),
81290
81643
  scopes: array(TokenScopeSchema),
81291
81644
  createdAt: number$1(),
81292
81645
  lastUsedAt: number$1(),
@@ -81386,6 +81739,9 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(_void(), ob
81386
81739
  access: "view"
81387
81740
  }), method(object({
81388
81741
  integrationId: string(),
81742
+ /** The integration instance the link is for. Omit for the default
81743
+ * instance — never pass the addon id to mean it. */
81744
+ instanceId: string().optional(),
81389
81745
  userId: string(),
81390
81746
  username: string(),
81391
81747
  scopes: array(TokenScopeSchema),
@@ -81424,7 +81780,13 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(_void(), ob
81424
81780
  }), method(object({ token: string() }), object({
81425
81781
  userId: string(),
81426
81782
  username: string(),
81427
- scopes: array(TokenScopeSchema)
81783
+ scopes: array(TokenScopeSchema),
81784
+ /** The instance the link was made for, read from the SESSION.
81785
+ * Absent = the default instance. `oauthLinkServesInstance` is the
81786
+ * helper a per-instance route calls to compare it with the instance
81787
+ * of its path; no route declares `perInstance` yet (the Alexa
81788
+ * per-instance route, T3, is the first consumer). */
81789
+ instanceId: string().optional()
81428
81790
  }).nullable(), { access: "view" }), method(object({ userId: string() }), array(ExternalIdentitySchema), { auth: "admin" }), method(ExternalIdentityKeySchema, object({
81429
81791
  userId: string(),
81430
81792
  issuer: string()
@@ -102780,6 +103142,38 @@ function ingestReading(input) {
102780
103142
  value: converted
102781
103143
  };
102782
103144
  }
103145
+ /**
103146
+ * Names chosen when an integration or a Gateway device is created.
103147
+ * A stored name is never rewritten from these helpers.
103148
+ */
103149
+ var HOME_SUFFIX = "Home";
103150
+ function collapse(value) {
103151
+ return value.trim().replace(/\s+/g, " ");
103152
+ }
103153
+ /** "KLF-200" → "KLF200". A hyphen between words ("Home Hub") stays. */
103154
+ function compactModelToken(value) {
103155
+ return value.replace(/([A-Za-z])-(\d)/g, "$1$2");
103156
+ }
103157
+ /** Prefill for a new integration: "<provider> - Home". The operator can edit it. */
103158
+ function defaultIntegrationName(providerLabel) {
103159
+ const label = collapse(providerLabel);
103160
+ if (label.length === 0) return HOME_SUFFIX;
103161
+ return `${label} - ${HOME_SUFFIX}`;
103162
+ }
103163
+ /**
103164
+ * A Gateway device: "<Brand> <Model>". An unknown model is the brand alone
103165
+ * (the caller passes the brand-level fallback it already has, e.g. "Velux KLF-200").
103166
+ */
103167
+ function gatewayDeviceName(brand, model) {
103168
+ const brandPart = compactModelToken(collapse(brand));
103169
+ const raw = collapse(model ?? "");
103170
+ if (raw.length === 0) return brandPart;
103171
+ const modelPart = compactModelToken(raw);
103172
+ const prefix = `${brandPart.toLowerCase()} `;
103173
+ if (modelPart.toLowerCase() === brandPart.toLowerCase()) return brandPart;
103174
+ if (modelPart.toLowerCase().startsWith(prefix)) return modelPart;
103175
+ return `${brandPart} ${modelPart}`;
103176
+ }
102783
103177
  String.raw`(?<=^|["'(\s>,\[{])`;
102784
103178
  var MB = 1024 * 1024;
102785
103179
  1024 * MB, 3072 * MB;
@@ -103008,6 +103402,12 @@ Object.defineProperty(exports, "customAction", {
103008
103402
  return customAction;
103009
103403
  }
103010
103404
  });
103405
+ Object.defineProperty(exports, "defaultIntegrationName", {
103406
+ enumerable: true,
103407
+ get: function() {
103408
+ return defaultIntegrationName;
103409
+ }
103410
+ });
103011
103411
  Object.defineProperty(exports, "defineCustomActions", {
103012
103412
  enumerable: true,
103013
103413
  get: function() {
@@ -103056,6 +103456,12 @@ Object.defineProperty(exports, "eventEmitterCapability", {
103056
103456
  return eventEmitterCapability;
103057
103457
  }
103058
103458
  });
103459
+ Object.defineProperty(exports, "gatewayDeviceName", {
103460
+ enumerable: true,
103461
+ get: function() {
103462
+ return gatewayDeviceName;
103463
+ }
103464
+ });
103059
103465
  Object.defineProperty(exports, "heatPumpControlCapability", {
103060
103466
  enumerable: true,
103061
103467
  get: function() {
@@ -103128,6 +103534,12 @@ Object.defineProperty(exports, "object", {
103128
103534
  return object;
103129
103535
  }
103130
103536
  });
103537
+ Object.defineProperty(exports, "plainEventVocabulary", {
103538
+ enumerable: true,
103539
+ get: function() {
103540
+ return plainEventVocabulary;
103541
+ }
103542
+ });
103131
103543
  Object.defineProperty(exports, "powerMeterCapability", {
103132
103544
  enumerable: true,
103133
103545
  get: function() {