@camstack/types 1.2.295 → 1.2.296

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/index.js CHANGED
@@ -21312,19 +21312,52 @@ var NcAlarmNonBlockingEditSchema = zod.z.object({
21312
21312
  nonBlocking: zod.z.boolean()
21313
21313
  });
21314
21314
  /**
21315
- * One arm mode's non-blocking list: devices that may be open when that mode
21316
- * arms, without the arm being refused.
21315
+ * Controllable openings: opt IN to blocking (default is do not block). Contacts
21316
+ * keep using {@link NcAlarmNonBlockingEditSchema}.
21317
+ */
21318
+ var NcAlarmBlockingEditSchema = zod.z.object({
21319
+ mode: AlarmArmModeSchema,
21320
+ deviceId: zod.z.number().int().positive(),
21321
+ /** true = on the list (blocks when open); false = off the list (default). */
21322
+ blocking: zod.z.boolean()
21323
+ });
21324
+ /**
21325
+ * Controllable openings: opt OUT of secure-on-arm (default is secure ON —
21326
+ * close / lock / turn off when this mode arms).
21317
21327
  */
21318
- var NcAlarmNonBlockingSchema = zod.z.object({
21328
+ var NcAlarmSecureOnArmEditSchema = zod.z.object({
21329
+ mode: AlarmArmModeSchema,
21330
+ deviceId: zod.z.number().int().positive(),
21331
+ /** true = secure on arm (default); false = do not actuate on arm. */
21332
+ secureOnArm: zod.z.boolean()
21333
+ });
21334
+ /**
21335
+ * One arm mode's device-id list (non-blocking, blocking, or secure-on-arm-off).
21336
+ */
21337
+ var NcAlarmModeDeviceListSchema = zod.z.object({
21319
21338
  mode: AlarmArmModeSchema,
21320
21339
  deviceIds: zod.z.array(zod.z.number().int()).max(200)
21321
21340
  });
21322
21341
  /**
21342
+ * One arm mode's non-blocking list: devices that may be open when that mode
21343
+ * arms, without the arm being refused.
21344
+ */
21345
+ var NcAlarmNonBlockingSchema = NcAlarmModeDeviceListSchema;
21346
+ /** Controllable devices that DO block when open (opt-in; default empty). */
21347
+ var NcAlarmBlockingSchema = NcAlarmModeDeviceListSchema;
21348
+ /**
21349
+ * Controllable devices that do NOT secure on arm (opt-out; default empty =
21350
+ * every controllable secures).
21351
+ */
21352
+ var NcAlarmSecureOnArmOffSchema = NcAlarmModeDeviceListSchema;
21353
+ /**
21323
21354
  * The per-mode lists, at most one per mode. Two lists for one mode have no
21324
21355
  * meaning a reader could agree on (union? the last one?), so they are refused
21325
21356
  * at the boundary rather than interpreted.
21326
21357
  */
21327
21358
  var NcAlarmNonBlockingListSchema = zod.z.array(NcAlarmNonBlockingSchema).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
21359
+ var NcAlarmBlockingListSchema = zod.z.array(NcAlarmBlockingSchema).max(8).refine(uniqueModes, { message: "blocking: at most one list per arm mode" });
21360
+ var NcAlarmSecureOnArmOffListSchema = zod.z.array(NcAlarmSecureOnArmOffSchema).max(8).refine(uniqueModes, { message: "secureOnArmOff: at most one list per arm mode" });
21328
21361
  /**
21329
21362
  * The three durations — global, and per mode since D697 — the panel's state
21330
21363
  * machine runs on, who hears about its transitions, and which openings each mode tolerates.
@@ -21367,9 +21400,23 @@ var NcAlarmSettingsSchema = zod.z.object({
21367
21400
  * arm (a window left ajar for the cat under `home`, say). At most one entry
21368
21401
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
21369
21402
  * parses as "every opening blocks" — the behaviour it was written under.
21403
+ * Contacts use this list; controllable openings use {@link blocking} instead
21404
+ * (default: do not block).
21370
21405
  */
21371
21406
  nonBlocking: NcAlarmNonBlockingListSchema.default([]),
21372
21407
  /**
21408
+ * Per arm mode, controllable openings that DO refuse the arm when open.
21409
+ * Default `[]` = none block (secure-on-arm closes them instead). Absent on a
21410
+ * blob older than this field — read as empty.
21411
+ */
21412
+ blocking: NcAlarmBlockingListSchema.default([]),
21413
+ /**
21414
+ * Per arm mode, controllable openings that must NOT be actuated on arm.
21415
+ * Default `[]` = every controllable secures (close / lock / off). Absent on
21416
+ * an older blob — read as empty (secure ON).
21417
+ */
21418
+ secureOnArmOff: NcAlarmSecureOnArmOffListSchema.default([]),
21419
+ /**
21373
21420
  * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
21374
21421
  * without a field, uses the global value above — so `[]`, the default, is exactly the
21375
21422
  * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
@@ -21379,7 +21426,7 @@ var NcAlarmSettingsSchema = zod.z.object({
21379
21426
  /**
21380
21427
  * Every field optional — a tab edits one control at a time.
21381
21428
  *
21382
- * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
21429
+ * List fields and `modeDelays` are re-declared WITHOUT their defaults:
21383
21430
  * `.partial()` does not remove an inner `.default()`, so a patch that never
21384
21431
  * named the field would parse to `[]` and wipe every mode's list on an
21385
21432
  * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
@@ -21387,11 +21434,15 @@ var NcAlarmSettingsSchema = zod.z.object({
21387
21434
  */
21388
21435
  var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
21389
21436
  nonBlocking: NcAlarmNonBlockingListSchema,
21437
+ blocking: NcAlarmBlockingListSchema,
21438
+ secureOnArmOff: NcAlarmSecureOnArmOffListSchema,
21390
21439
  /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
21391
21440
  modeDelays: NcAlarmModeDelaysEditListSchema,
21392
21441
  /** ONE membership change; the panel applies it to the list it holds at its turn. */
21393
- nonBlockingEdit: NcAlarmNonBlockingEditSchema
21394
- }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
21442
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema,
21443
+ blockingEdit: NcAlarmBlockingEditSchema,
21444
+ secureOnArmEdit: NcAlarmSecureOnArmEditSchema
21445
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" }).refine((p) => p.blocking === void 0 || p.blockingEdit === void 0, { message: "blocking and blockingEdit are exclusive — send the whole lists or one edit" }).refine((p) => p.secureOnArmOff === void 0 || p.secureOnArmEdit === void 0, { message: "secureOnArmOff and secureOnArmEdit are exclusive — send the whole lists or one edit" });
21395
21446
  /**
21396
21447
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
21397
21448
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -21508,7 +21559,13 @@ var NcAlarmSensorStateSchema = zod.z.object({
21508
21559
  /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
21509
21560
  unknownWhy: zod.z.enum(["read-failed", "unknown-word"]).nullable(),
21510
21561
  /** The device manager's liveness as the centre mirrors it; null = not known. */
21511
- online: zod.z.boolean().nullable()
21562
+ online: zod.z.boolean().nullable(),
21563
+ /**
21564
+ * True when the opening is a cover / lock / switch — the table shows the
21565
+ * Secure-on-arm switch and uses the controllable defaults. False for contacts
21566
+ * and for non-openings. Defaulted so an older hub answer still parses.
21567
+ */
21568
+ controllable: zod.z.boolean().default(false)
21512
21569
  });
21513
21570
  var NcAlarmSensorsInputSchema = zod.z.object({ deviceIds: zod.z.array(zod.z.number().int().positive()).max(500) });
21514
21571
  var NcAlarmSensorsSchema = zod.z.object({
@@ -66174,9 +66231,22 @@ var ALARM_PANEL_TRIGGER_METHOD = "trigger";
66174
66231
  var NC_ALARM_OPENING_EVENT_KINDS = [
66175
66232
  "contact",
66176
66233
  "cover",
66177
- "lock"
66234
+ "lock",
66235
+ "switch"
66178
66236
  ];
66179
66237
  /**
66238
+ * Opening caps that can be ACTUATED to a secure state on arm (close / lock /
66239
+ * off). Contacts are openings but not controllable — they only block.
66240
+ */
66241
+ var NC_ALARM_CONTROLLABLE_CAPS = [
66242
+ "cover",
66243
+ "lock-control",
66244
+ "switch"
66245
+ ];
66246
+ function isAlarmControllableCap(cap) {
66247
+ return NC_ALARM_CONTROLLABLE_CAPS.includes(cap);
66248
+ }
66249
+ /**
66180
66250
  * A rule belongs to the alarm when its `deviceState` gate names ANY device's
66181
66251
  * `armed_*` word, or an ENABLED `onTrigger` sequence pulls the alarm panel's
66182
66252
  * trigger (D630).
@@ -66204,6 +66274,46 @@ function sensorTransitionNeverFires(rule) {
66204
66274
  /** The warning an editor shows for {@link sensorTransitionNeverFires}. */
66205
66275
  var NC_SENSOR_TRANSITION_NEVER_FIRES_WARNING = "This rule belongs to the alarm, and an alarm rule fires only when an opening OPENS. Set to “only when it clears”, it can never fire.";
66206
66276
  //#endregion
66277
+ //#region src/notification/alarm-controllable.ts
66278
+ /**
66279
+ * Controllable openings on the alarm: defaults for the two switches, and the
66280
+ * actuation each cap gets when "secure on arm" fires.
66281
+ *
66282
+ * Controllable = cover / lock-control / switch. Contacts stay passive: they
66283
+ * block by default and have no secure switch.
66284
+ */
66285
+ /** Whether this device refuses the arm when open. */
66286
+ function alarmDeviceBlocksArming(input) {
66287
+ if (input.controllable) return input.blocking.includes(input.deviceId);
66288
+ return !input.nonBlocking.includes(input.deviceId);
66289
+ }
66290
+ /** Whether this controllable should be closed/locked/turned off on arm. */
66291
+ function alarmDeviceSecureOnArm(input) {
66292
+ if (!input.controllable) return false;
66293
+ return !input.secureOnArmOff.includes(input.deviceId);
66294
+ }
66295
+ /** The one secure command for a controllable opening cap, or null for contacts. */
66296
+ function secureActuationFor(cap) {
66297
+ if (!isAlarmControllableCap(cap)) return null;
66298
+ switch (cap) {
66299
+ case "cover": return {
66300
+ cap,
66301
+ method: "close",
66302
+ args: {}
66303
+ };
66304
+ case "lock-control": return {
66305
+ cap,
66306
+ method: "lock",
66307
+ args: {}
66308
+ };
66309
+ case "switch": return {
66310
+ cap,
66311
+ method: "setState",
66312
+ args: { on: false }
66313
+ };
66314
+ }
66315
+ }
66316
+ //#endregion
66207
66317
  //#region src/notification/alarm-settings.ts
66208
66318
  var NC_ALARM_DELAY_FIELDS = [
66209
66319
  "exitDelaySec",
@@ -66264,10 +66374,11 @@ function applyModeDelaysEdits(current, edits) {
66264
66374
  return out.filter((e) => e.exitDelaySec !== void 0 || e.entryDelaySec !== void 0 || e.triggeredDurationSec !== void 0);
66265
66375
  }
66266
66376
  /**
66267
- * Put ONE device on, or take it off, ONE mode's list. A no-op answers `changed: false`; an add
66268
- * to a full list is REFUSED by reason (never silently dropped); an emptied list drops its entry.
66377
+ * Put ONE device on, or take it off, ONE mode's device-id list. A no-op answers
66378
+ * `changed: false`; an add to a full list is REFUSED by reason (never silently
66379
+ * dropped); an emptied list drops its entry.
66269
66380
  */
66270
- function applyNonBlockingEdit(lists, edit) {
66381
+ function applyModeDeviceListEdit(lists, edit) {
66271
66382
  const copy = lists.map((l) => ({
66272
66383
  mode: l.mode,
66273
66384
  deviceIds: [...l.deviceIds]
@@ -66275,12 +66386,12 @@ function applyNonBlockingEdit(lists, edit) {
66275
66386
  const at = copy.findIndex((l) => l.mode === edit.mode);
66276
66387
  const held = at >= 0 ? copy[at]?.deviceIds ?? [] : [];
66277
66388
  const present = held.includes(edit.deviceId);
66278
- if (edit.nonBlocking === present) return {
66389
+ if (edit.present === present) return {
66279
66390
  kind: "applied",
66280
66391
  lists: copy,
66281
66392
  changed: false
66282
66393
  };
66283
- if (edit.nonBlocking) {
66394
+ if (edit.present) {
66284
66395
  if (held.length >= 200) return {
66285
66396
  kind: "refused",
66286
66397
  reason: "list-full",
@@ -66306,6 +66417,35 @@ function applyNonBlockingEdit(lists, edit) {
66306
66417
  changed: true
66307
66418
  };
66308
66419
  }
66420
+ /**
66421
+ * Put ONE device on, or take it off, ONE mode's non-blocking list.
66422
+ */
66423
+ function applyNonBlockingEdit(lists, edit) {
66424
+ return applyModeDeviceListEdit(lists, {
66425
+ mode: edit.mode,
66426
+ deviceId: edit.deviceId,
66427
+ present: edit.nonBlocking
66428
+ });
66429
+ }
66430
+ /** Controllable opt-in to blocking. */
66431
+ function applyBlockingEdit(lists, edit) {
66432
+ return applyModeDeviceListEdit(lists, {
66433
+ mode: edit.mode,
66434
+ deviceId: edit.deviceId,
66435
+ present: edit.blocking
66436
+ });
66437
+ }
66438
+ /**
66439
+ * Controllable secure-on-arm: `secureOnArm: true` removes from the opt-out list;
66440
+ * `false` adds to it.
66441
+ */
66442
+ function applySecureOnArmEdit(lists, edit) {
66443
+ return applyModeDeviceListEdit(lists, {
66444
+ mode: edit.mode,
66445
+ deviceId: edit.deviceId,
66446
+ present: !edit.secureOnArm
66447
+ });
66448
+ }
66309
66449
  function sameSet(a, b) {
66310
66450
  const sa = new Set(a);
66311
66451
  const sb = new Set(b);
@@ -66344,6 +66484,9 @@ function editFieldOf(edit, field) {
66344
66484
  case "triggeredDurationSec": return edit.triggeredDurationSec;
66345
66485
  }
66346
66486
  }
66487
+ function listHolds(lists, mode, deviceId) {
66488
+ return lists?.find((l) => l.mode === mode)?.deviceIds.includes(deviceId) ?? false;
66489
+ }
66347
66490
  /**
66348
66491
  * True iff every key the patch sent is reflected in what the host returned. A host older than
66349
66492
  * this build strips the keys it does not know; this is how a client tells "saved" from "parsed
@@ -66358,6 +66501,8 @@ function alarmPatchLanded(patch, returned) {
66358
66501
  if (patch.triggeredDurationSec !== void 0 && patch.triggeredDurationSec !== returned.triggeredDurationSec) return false;
66359
66502
  if (patch.announceTargets !== void 0 && !sameSet(patch.announceTargets, returned.announceTargets)) return false;
66360
66503
  if (patch.nonBlocking !== void 0 && !sameLists(patch.nonBlocking, returned.nonBlocking ?? [])) return false;
66504
+ if (patch.blocking !== void 0 && !sameLists(patch.blocking, returned.blocking ?? [])) return false;
66505
+ if (patch.secureOnArmOff !== void 0 && !sameLists(patch.secureOnArmOff, returned.secureOnArmOff ?? [])) return false;
66361
66506
  for (const edit of patch.modeDelays ?? []) {
66362
66507
  const entry = (returned.modeDelays ?? []).find((e) => e.mode === edit.mode);
66363
66508
  for (const field of NC_ALARM_DELAY_FIELDS) {
@@ -66369,7 +66514,15 @@ function alarmPatchLanded(patch, returned) {
66369
66514
  }
66370
66515
  if (patch.nonBlockingEdit !== void 0) {
66371
66516
  const e = patch.nonBlockingEdit;
66372
- if (((returned.nonBlocking ?? []).find((l) => l.mode === e.mode)?.deviceIds.includes(e.deviceId) ?? false) !== e.nonBlocking) return false;
66517
+ if (listHolds(returned.nonBlocking, e.mode, e.deviceId) !== e.nonBlocking) return false;
66518
+ }
66519
+ if (patch.blockingEdit !== void 0) {
66520
+ const e = patch.blockingEdit;
66521
+ if (listHolds(returned.blocking, e.mode, e.deviceId) !== e.blocking) return false;
66522
+ }
66523
+ if (patch.secureOnArmEdit !== void 0) {
66524
+ const e = patch.secureOnArmEdit;
66525
+ if (listHolds(returned.secureOnArmOff, e.mode, e.deviceId) === e.secureOnArm) return false;
66373
66526
  }
66374
66527
  return true;
66375
66528
  }
@@ -71003,6 +71156,7 @@ exports.NATIVE_LEASE_TILE_BUDGET_KEY = NATIVE_LEASE_TILE_BUDGET_KEY;
71003
71156
  exports.NAVIGATION_ACTION_CATALOG = NAVIGATION_ACTION_CATALOG;
71004
71157
  exports.NAVIGATION_LIGHT_LEVEL_MAX = NAVIGATION_LIGHT_LEVEL_MAX;
71005
71158
  exports.NAVIGATION_LIGHT_LEVEL_MIN = NAVIGATION_LIGHT_LEVEL_MIN;
71159
+ exports.NC_ALARM_CONTROLLABLE_CAPS = NC_ALARM_CONTROLLABLE_CAPS;
71006
71160
  exports.NC_ALARM_DELAY_FIELDS = NC_ALARM_DELAY_FIELDS;
71007
71161
  exports.NC_ALARM_DELAY_MAX_SEC = NC_ALARM_DELAY_MAX_SEC;
71008
71162
  exports.NC_ALARM_NONBLOCKING_MAX = NC_ALARM_NONBLOCKING_MAX;
@@ -71099,11 +71253,17 @@ exports.NavigationMoveCommandSchema = NavigationMoveCommandSchema;
71099
71253
  exports.NavigationPointSchema = NavigationPointSchema;
71100
71254
  exports.NavigationRuntimeStateSchema = NavigationRuntimeStateSchema;
71101
71255
  exports.NavigationStatusSchema = NavigationStatusSchema;
71256
+ exports.NcAlarmBlockingEditSchema = NcAlarmBlockingEditSchema;
71257
+ exports.NcAlarmBlockingSchema = NcAlarmBlockingSchema;
71102
71258
  exports.NcAlarmConfigSchema = NcAlarmConfigSchema;
71103
71259
  exports.NcAlarmModeCoverageSchema = NcAlarmModeCoverageSchema;
71104
71260
  exports.NcAlarmModeDelaysEditSchema = NcAlarmModeDelaysEditSchema;
71105
71261
  exports.NcAlarmModeDelaysSchema = NcAlarmModeDelaysSchema;
71262
+ exports.NcAlarmModeDeviceListSchema = NcAlarmModeDeviceListSchema;
71106
71263
  exports.NcAlarmNonBlockingEditSchema = NcAlarmNonBlockingEditSchema;
71264
+ exports.NcAlarmNonBlockingSchema = NcAlarmNonBlockingSchema;
71265
+ exports.NcAlarmSecureOnArmEditSchema = NcAlarmSecureOnArmEditSchema;
71266
+ exports.NcAlarmSecureOnArmOffSchema = NcAlarmSecureOnArmOffSchema;
71107
71267
  exports.NcAlarmSensorReadingSchema = NcAlarmSensorReadingSchema;
71108
71268
  exports.NcAlarmSensorStateSchema = NcAlarmSensorStateSchema;
71109
71269
  exports.NcAlarmSensorsInputSchema = NcAlarmSensorsInputSchema;
@@ -71685,12 +71845,17 @@ exports.addonWidgetsSourceCapability = addonWidgetsSourceCapability;
71685
71845
  exports.addonsCapability = addonsCapability;
71686
71846
  exports.adminUiCapability = require_sleep.adminUiCapability;
71687
71847
  exports.airQualitySensorCapability = airQualitySensorCapability;
71848
+ exports.alarmDeviceBlocksArming = alarmDeviceBlocksArming;
71849
+ exports.alarmDeviceSecureOnArm = alarmDeviceSecureOnArm;
71688
71850
  exports.alarmPanelCapability = alarmPanelCapability;
71689
71851
  exports.alarmPatchLanded = alarmPatchLanded;
71690
71852
  exports.alertsCapability = alertsCapability;
71691
71853
  exports.ambientLightSensorCapability = ambientLightSensorCapability;
71854
+ exports.applyBlockingEdit = applyBlockingEdit;
71692
71855
  exports.applyModeDelaysEdits = applyModeDelaysEdits;
71856
+ exports.applyModeDeviceListEdit = applyModeDeviceListEdit;
71693
71857
  exports.applyNonBlockingEdit = applyNonBlockingEdit;
71858
+ exports.applySecureOnArmEdit = applySecureOnArmEdit;
71694
71859
  exports.asBoolean = require_sleep.asBoolean;
71695
71860
  exports.asJsonArray = require_sleep.asJsonArray;
71696
71861
  exports.asJsonObject = require_sleep.asJsonObject;
@@ -71950,6 +72115,7 @@ exports.invalidClusterStepModelEntries = invalidClusterStepModelEntries;
71950
72115
  exports.invertPresetFeature = invertPresetFeature;
71951
72116
  exports.invocationFromEncodeProfile = require_composition.invocationFromEncodeProfile;
71952
72117
  exports.isAgentOnlyPlacement = isAgentOnlyPlacement;
72118
+ exports.isAlarmControllableCap = isAlarmControllableCap;
71953
72119
  exports.isArrayOutputSchema = isArrayOutputSchema;
71954
72120
  exports.isAudioChunkFormat = require_sleep.isAudioChunkFormat;
71955
72121
  exports.isAudioClassName = isAudioClassName;
@@ -72197,6 +72363,7 @@ exports.scopesAllowDeviceCap = scopesAllowDeviceCap;
72197
72363
  exports.scoreRuntimes = scoreRuntimes;
72198
72364
  exports.scriptRunnerCapability = scriptRunnerCapability;
72199
72365
  exports.searchDisplayIcons = searchDisplayIcons;
72366
+ exports.secureActuationFor = secureActuationFor;
72200
72367
  exports.selectAssignedProfileSlots = require_sleep.selectAssignedProfileSlots;
72201
72368
  exports.sendTimesOfSchedule = sendTimesOfSchedule;
72202
72369
  exports.sensorRaisedOf = sensorRaisedOf;