@camstack/addon-export-hap 1.2.86 → 1.2.88

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.
@@ -8515,17 +8515,29 @@ var HHMM = /^([01]\d|2[0-3]):[0-5]\d$/;
8515
8515
  /**
8516
8516
  * DERIVED per-camera storage summary — the single field cheap consumers read
8517
8517
  * (the viewer's status dot, the camera list) instead of walking `bands`:
8518
- * - `off` — no band covers the camera (or it is disabled).
8519
- * - `events` — every band records around triggers only.
8520
- * - `continuous` — at least one band records continuously.
8521
- *
8522
- * NEVER authored: the recorder stamps it from the authoritative `bands` on
8523
- * every save (`activeModeForConfig`). Writing it has no effect.
8518
+ * - `off` — no band covers the camera (or it is disabled).
8519
+ * - `events` — every band records around triggers only.
8520
+ * - `continuous` — at least one band records continuously.
8521
+ * - `on-device-decision`— the DEVICE decides: recording runs for as long as the
8522
+ * camera raises its own `recording-signal` level (a robot that cleans). There
8523
+ * is no schedule to author, because there is no hour to program — see
8524
+ * {@link RecordingConfigSchema}`.deviceDecision`.
8525
+ *
8526
+ * NEVER authored: the recorder stamps it from the authoritative intent
8527
+ * (`bands` + `deviceDecision`) on every save (`activeModeForConfig`). Writing it
8528
+ * has no effect.
8529
+ *
8530
+ * `on-device-decision` is named for WHO decides, not for how the recording is
8531
+ * requested. `on-demand` was rejected: in this repo's vocabulary a "demand" is
8532
+ * something the operator makes (the live gate is the recorder's own "demand
8533
+ * window"), and a knob whose name suggests the operator starts it while the
8534
+ * device actually does is the D62 shape — a control nobody can predict.
8524
8535
  */
8525
8536
  var RecordingStorageModeSchema = _enum([
8526
8537
  "off",
8527
8538
  "events",
8528
- "continuous"
8539
+ "continuous",
8540
+ "on-device-decision"
8529
8541
  ]);
8530
8542
  /**
8531
8543
  * Le macro classi che possono aprire una finestra di registrazione — le stesse
@@ -8575,22 +8587,7 @@ var RecordingTriggersSchema = object({
8575
8587
  * il livello: un contatto trovato già aperto al riavvio del runner non fa
8576
8588
  * registrare.
8577
8589
  */
8578
- sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional(),
8579
- /**
8580
- * La camera registra per tutta la durata del SEGNALE che lei stessa
8581
- * pubblica — la cap `recording-signal` (`active: true` mentre il device è in
8582
- * funzione: un robot che pulisce). È un LIVELLO, non un fronte: la finestra
8583
- * resta aperta finché il segnale è alto e si chiude `postBufferSec` dopo la
8584
- * caduta, così una pulizia di quaranta minuti è UNA clip.
8585
- *
8586
- * Non nomina un device: il segnale è della camera stessa, tenuto fresco dal
8587
- * suo provider (D224); il recorder lo ascolta su `DeviceStateChanged` e lo
8588
- * riconcilia leggendo la slice via RPC, con un tetto oltre il quale un
8589
- * segnale mai abbassato (un evento perso) non può tenere aperta una
8590
- * registrazione (D11). Vedi `recorder/addon/band-decision.ts`
8591
- * (`holdTrigger` / `releaseTrigger`).
8592
- */
8593
- deviceSignal: boolean().optional()
8590
+ sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
8594
8591
  });
8595
8592
  /**
8596
8593
  * Mode of a single recording band — the recorder per-band vocabulary.
@@ -8620,13 +8617,28 @@ var RecordingBandSchema = object({
8620
8617
  end: string().regex(HHMM),
8621
8618
  mode: RecordingBandModeSchema,
8622
8619
  triggers: RecordingBandTriggersSchema.optional(),
8620
+ /**
8621
+ * RETIRED (D381). A band no longer carries a pre-buffer of its own.
8622
+ *
8623
+ * It was the retroactive KEEP bound — which already-written segments survive
8624
+ * a trigger — and it had to be at least as wide as the widest pre-roll the
8625
+ * broker could serve, or the gate would delete the seconds the ring had just
8626
+ * handed the writer. That "at least as wide as" is the tell: it was a second
8627
+ * expression of the broker's retention, in different units, in a different
8628
+ * addon, with an invariant the operator had to maintain by hand. The keep
8629
+ * bound is now derived from the one prebuffer ceiling and there is nothing
8630
+ * left to configure here.
8631
+ *
8632
+ * The key survives in the SHAPE so a config written before that record still
8633
+ * parses and can be migrated deliberately — `RecordingBandSchema` is not
8634
+ * strict, so simply deleting it would strip an operator's value in silence on
8635
+ * the next save (the failure D380 came one commit from shipping). Nothing
8636
+ * reads it: {@link stripRetiredBandPreBufferSec} removes it on load.
8637
+ */
8623
8638
  preBufferSec: number().min(0).optional(),
8624
8639
  postBufferSec: number().min(0).optional()
8625
8640
  });
8626
- ({
8627
- preBufferSec: 15,
8628
- postBufferSec: 30
8629
- }).postBufferSec * 1e3;
8641
+ ({ postBufferSec: 30 }).postBufferSec * 1e3;
8630
8642
  /**
8631
8643
  * Per-device retention overrides. Every field is optional; an unset or `0`
8632
8644
  * value inherits the node-wide recorder default. Only footage-lifetime limits
@@ -8674,8 +8686,29 @@ var RecordingConfigSchema = object({
8674
8686
  * "off" is the absence of a covering band, never a band value.
8675
8687
  */
8676
8688
  bands: array(RecordingBandSchema).default([]),
8689
+ /**
8690
+ * THE device-decided intent: record for as long as the camera itself raises
8691
+ * `recording-signal` (`active: true` while the device is in function — a
8692
+ * robot that cleans). AUTHORED, unlike `mode`, and the only authored
8693
+ * recording intent that is not a band.
8694
+ *
8695
+ * It carries NO schedule on purpose. A band is an HOUR, and this feature has
8696
+ * no hour to program: the device decides. What it costs the operator is one
8697
+ * flag — "this camera can record on its own" — and what it buys is the same
8698
+ * hold/release the recorder already implements (D371, `holdTrigger` /
8699
+ * `releaseTrigger`): the window opens on the rise, stays open for the whole
8700
+ * job however long it is, and closes one pad after the fall.
8701
+ *
8702
+ * EXCLUSIVE with `bands` (below): two authorities deciding when the same
8703
+ * camera records is the D62 failure. `off` remains `enabled: false`, so an
8704
+ * operator switching this camera off is REPORTED off, never as broken.
8705
+ */
8706
+ deviceDecision: boolean().optional(),
8677
8707
  retention: RecordingRetentionSchema.optional()
8678
- }).strict();
8708
+ }).strict().refine((config) => config.deviceDecision !== true || config.bands.length === 0, {
8709
+ message: "deviceDecision is a whole-config mode and carries no schedule: it cannot be combined with bands",
8710
+ path: ["bands"]
8711
+ });
8679
8712
  /**
8680
8713
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
8681
8714
  *
@@ -21458,11 +21491,7 @@ var CameraAudioStatusSchema = object({
21458
21491
  });
21459
21492
  /** Recording block — null when no recording cap is active for this device. */
21460
21493
  var CameraRecordingStatusSchema = object({
21461
- mode: _enum([
21462
- "off",
21463
- "continuous",
21464
- "events"
21465
- ]),
21494
+ mode: RecordingStorageModeSchema,
21466
21495
  active: boolean(),
21467
21496
  storageBytes: number()
21468
21497
  });
@@ -27916,11 +27945,10 @@ DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceI
27916
27945
  var RecordingStatusSchema = object({
27917
27946
  deviceId: number(),
27918
27947
  enabled: boolean(),
27919
- activeMode: _enum([
27920
- "off",
27921
- "continuous",
27922
- "events"
27923
- ]),
27948
+ /** THE derived storage mode, from the one definition
27949
+ * (`deriveRecordingMode`) — never a second enum. A duplicated list is how
27950
+ * `on-device-decision` could have reached the recorder and not the status. */
27951
+ activeMode: RecordingStorageModeSchema,
27924
27952
  nodeId: string(),
27925
27953
  storageBytes: number()
27926
27954
  });
@@ -8503,17 +8503,29 @@ var HHMM = /^([01]\d|2[0-3]):[0-5]\d$/;
8503
8503
  /**
8504
8504
  * DERIVED per-camera storage summary — the single field cheap consumers read
8505
8505
  * (the viewer's status dot, the camera list) instead of walking `bands`:
8506
- * - `off` — no band covers the camera (or it is disabled).
8507
- * - `events` — every band records around triggers only.
8508
- * - `continuous` — at least one band records continuously.
8509
- *
8510
- * NEVER authored: the recorder stamps it from the authoritative `bands` on
8511
- * every save (`activeModeForConfig`). Writing it has no effect.
8506
+ * - `off` — no band covers the camera (or it is disabled).
8507
+ * - `events` — every band records around triggers only.
8508
+ * - `continuous` — at least one band records continuously.
8509
+ * - `on-device-decision`— the DEVICE decides: recording runs for as long as the
8510
+ * camera raises its own `recording-signal` level (a robot that cleans). There
8511
+ * is no schedule to author, because there is no hour to program — see
8512
+ * {@link RecordingConfigSchema}`.deviceDecision`.
8513
+ *
8514
+ * NEVER authored: the recorder stamps it from the authoritative intent
8515
+ * (`bands` + `deviceDecision`) on every save (`activeModeForConfig`). Writing it
8516
+ * has no effect.
8517
+ *
8518
+ * `on-device-decision` is named for WHO decides, not for how the recording is
8519
+ * requested. `on-demand` was rejected: in this repo's vocabulary a "demand" is
8520
+ * something the operator makes (the live gate is the recorder's own "demand
8521
+ * window"), and a knob whose name suggests the operator starts it while the
8522
+ * device actually does is the D62 shape — a control nobody can predict.
8512
8523
  */
8513
8524
  var RecordingStorageModeSchema = _enum([
8514
8525
  "off",
8515
8526
  "events",
8516
- "continuous"
8527
+ "continuous",
8528
+ "on-device-decision"
8517
8529
  ]);
8518
8530
  /**
8519
8531
  * Le macro classi che possono aprire una finestra di registrazione — le stesse
@@ -8563,22 +8575,7 @@ var RecordingTriggersSchema = object({
8563
8575
  * il livello: un contatto trovato già aperto al riavvio del runner non fa
8564
8576
  * registrare.
8565
8577
  */
8566
- sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional(),
8567
- /**
8568
- * La camera registra per tutta la durata del SEGNALE che lei stessa
8569
- * pubblica — la cap `recording-signal` (`active: true` mentre il device è in
8570
- * funzione: un robot che pulisce). È un LIVELLO, non un fronte: la finestra
8571
- * resta aperta finché il segnale è alto e si chiude `postBufferSec` dopo la
8572
- * caduta, così una pulizia di quaranta minuti è UNA clip.
8573
- *
8574
- * Non nomina un device: il segnale è della camera stessa, tenuto fresco dal
8575
- * suo provider (D224); il recorder lo ascolta su `DeviceStateChanged` e lo
8576
- * riconcilia leggendo la slice via RPC, con un tetto oltre il quale un
8577
- * segnale mai abbassato (un evento perso) non può tenere aperta una
8578
- * registrazione (D11). Vedi `recorder/addon/band-decision.ts`
8579
- * (`holdTrigger` / `releaseTrigger`).
8580
- */
8581
- deviceSignal: boolean().optional()
8578
+ sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
8582
8579
  });
8583
8580
  /**
8584
8581
  * Mode of a single recording band — the recorder per-band vocabulary.
@@ -8608,13 +8605,28 @@ var RecordingBandSchema = object({
8608
8605
  end: string().regex(HHMM),
8609
8606
  mode: RecordingBandModeSchema,
8610
8607
  triggers: RecordingBandTriggersSchema.optional(),
8608
+ /**
8609
+ * RETIRED (D381). A band no longer carries a pre-buffer of its own.
8610
+ *
8611
+ * It was the retroactive KEEP bound — which already-written segments survive
8612
+ * a trigger — and it had to be at least as wide as the widest pre-roll the
8613
+ * broker could serve, or the gate would delete the seconds the ring had just
8614
+ * handed the writer. That "at least as wide as" is the tell: it was a second
8615
+ * expression of the broker's retention, in different units, in a different
8616
+ * addon, with an invariant the operator had to maintain by hand. The keep
8617
+ * bound is now derived from the one prebuffer ceiling and there is nothing
8618
+ * left to configure here.
8619
+ *
8620
+ * The key survives in the SHAPE so a config written before that record still
8621
+ * parses and can be migrated deliberately — `RecordingBandSchema` is not
8622
+ * strict, so simply deleting it would strip an operator's value in silence on
8623
+ * the next save (the failure D380 came one commit from shipping). Nothing
8624
+ * reads it: {@link stripRetiredBandPreBufferSec} removes it on load.
8625
+ */
8611
8626
  preBufferSec: number().min(0).optional(),
8612
8627
  postBufferSec: number().min(0).optional()
8613
8628
  });
8614
- ({
8615
- preBufferSec: 15,
8616
- postBufferSec: 30
8617
- }).postBufferSec * 1e3;
8629
+ ({ postBufferSec: 30 }).postBufferSec * 1e3;
8618
8630
  /**
8619
8631
  * Per-device retention overrides. Every field is optional; an unset or `0`
8620
8632
  * value inherits the node-wide recorder default. Only footage-lifetime limits
@@ -8662,8 +8674,29 @@ var RecordingConfigSchema = object({
8662
8674
  * "off" is the absence of a covering band, never a band value.
8663
8675
  */
8664
8676
  bands: array(RecordingBandSchema).default([]),
8677
+ /**
8678
+ * THE device-decided intent: record for as long as the camera itself raises
8679
+ * `recording-signal` (`active: true` while the device is in function — a
8680
+ * robot that cleans). AUTHORED, unlike `mode`, and the only authored
8681
+ * recording intent that is not a band.
8682
+ *
8683
+ * It carries NO schedule on purpose. A band is an HOUR, and this feature has
8684
+ * no hour to program: the device decides. What it costs the operator is one
8685
+ * flag — "this camera can record on its own" — and what it buys is the same
8686
+ * hold/release the recorder already implements (D371, `holdTrigger` /
8687
+ * `releaseTrigger`): the window opens on the rise, stays open for the whole
8688
+ * job however long it is, and closes one pad after the fall.
8689
+ *
8690
+ * EXCLUSIVE with `bands` (below): two authorities deciding when the same
8691
+ * camera records is the D62 failure. `off` remains `enabled: false`, so an
8692
+ * operator switching this camera off is REPORTED off, never as broken.
8693
+ */
8694
+ deviceDecision: boolean().optional(),
8665
8695
  retention: RecordingRetentionSchema.optional()
8666
- }).strict();
8696
+ }).strict().refine((config) => config.deviceDecision !== true || config.bands.length === 0, {
8697
+ message: "deviceDecision is a whole-config mode and carries no schedule: it cannot be combined with bands",
8698
+ path: ["bands"]
8699
+ });
8667
8700
  /**
8668
8701
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
8669
8702
  *
@@ -21446,11 +21479,7 @@ var CameraAudioStatusSchema = object({
21446
21479
  });
21447
21480
  /** Recording block — null when no recording cap is active for this device. */
21448
21481
  var CameraRecordingStatusSchema = object({
21449
- mode: _enum([
21450
- "off",
21451
- "continuous",
21452
- "events"
21453
- ]),
21482
+ mode: RecordingStorageModeSchema,
21454
21483
  active: boolean(),
21455
21484
  storageBytes: number()
21456
21485
  });
@@ -27904,11 +27933,10 @@ DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceI
27904
27933
  var RecordingStatusSchema = object({
27905
27934
  deviceId: number(),
27906
27935
  enabled: boolean(),
27907
- activeMode: _enum([
27908
- "off",
27909
- "continuous",
27910
- "events"
27911
- ]),
27936
+ /** THE derived storage mode, from the one definition
27937
+ * (`deriveRecordingMode`) — never a second enum. A duplicated list is how
27938
+ * `on-device-decision` could have reached the recorder and not the status. */
27939
+ activeMode: RecordingStorageModeSchema,
27912
27940
  nodeId: string(),
27913
27941
  storageBytes: number()
27914
27942
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-export-hap",
3
- "version": "1.2.86",
3
+ "version": "1.2.88",
4
4
  "description": "HomeKit (HAP) exporter for CamStack devices. Publishes each exposed device as its own HomeKit accessory: cameras and doorbells with SRTP streaming, HomeKit Secure Video, motion, two-way audio, PTZ and battery; switches, lights, locks and sensors through a capability→service table.",
5
5
  "keywords": [
6
6
  "camstack",