@camstack/addon-export-hap 1.2.56 → 1.2.57

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.
@@ -8669,6 +8669,21 @@ var RelocateJobSchema = object({
8669
8669
  bytesMoved: number().int(),
8670
8670
  /** Total files discovered up front; null while (or when) unknown. */
8671
8671
  filesTotal: number().int().nullable(),
8672
+ /**
8673
+ * Rows this run CORRECTED while moving them — a durable mutation the move
8674
+ * made that nobody asked for, so it is reported where the operator reads the
8675
+ * job rather than only in a log line.
8676
+ *
8677
+ * A footage segment records its byte count in its own NAME, and the durable
8678
+ * hour row derives its aggregates from those names. A file that does not
8679
+ * match its name therefore makes the ledger's sums — and with them quota and
8680
+ * pressure eviction — wrong by the difference, and only a rename can fix it.
8681
+ * On 2026-08-30 one such row also stalled a 110 749-file drain permanently.
8682
+ *
8683
+ * Absent on lanes where the question has no meaning: a media blob's size is
8684
+ * in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
8685
+ */
8686
+ rowsReconciled: number().int().nonnegative().optional(),
8672
8687
  startedAt: number(),
8673
8688
  finishedAt: number().nullable(),
8674
8689
  error: string().nullable()
@@ -8737,14 +8752,42 @@ var RelocateMediaInputSchema = object({
8737
8752
  /** Omitted = `move`, the pre-existing behaviour. */
8738
8753
  mode: MediaRelocateModeSchema.optional()
8739
8754
  });
8740
- /** How many rows still carry NO `locationId` — the population a repoint would
8741
- * silently re-aim at a disk that does not hold their bytes. Zero is the only
8742
- * value that permits a non-blocking `eventMedia` cutover. */
8743
- var UnstampedEventMediaCountSchema = object({
8744
- media: number().int().nonnegative(),
8745
- retrainFrames: number().int().nonnegative(),
8746
- total: number().int().nonnegative()
8755
+ /**
8756
+ * The unstamped population of ONE collection split, because the gate and the
8757
+ * operator ask two different questions and only one of them has to be cheap.
8758
+ *
8759
+ * `present` is the GATE: "is there at least one row that would be orphaned by a
8760
+ * repoint". It is a single indexed seek to the first matching row, so it stays
8761
+ * answerable on a saturated disk and answers in O(log n) precisely in the state
8762
+ * that matters — after a seal, when the population is empty.
8763
+ *
8764
+ * `rows` is the NUMBER, for the refusal message and the operator's sense of
8765
+ * scale. It is a second, indexed `COUNT(*)`, and `null` means **not
8766
+ * measurable** — never zero. `{ present: true, rows: null }` is a legitimate
8767
+ * and useful answer: "there are some, and this read could not say how many"
8768
+ * still refuses the cutover, which is the whole job.
8769
+ */
8770
+ var UnstampedRowsSchema = object({
8771
+ present: boolean(),
8772
+ rows: number().int().nonnegative().nullable()
8747
8773
  });
8774
+ /**
8775
+ * How many rows still carry NO `locationId` — the population a repoint would
8776
+ * silently re-aim at a disk that does not hold their bytes.
8777
+ *
8778
+ * **`null` = the count could not be taken**, and it is NOT permission to cut
8779
+ * over. The gate opens on a measured absence and on nothing else; an unread
8780
+ * collection and an empty one are different facts, and this repo has already
8781
+ * paid for conflating them (`RelocateResidueSchema`, D295).
8782
+ */
8783
+ var UnstampedEventMediaCountSchema = object({
8784
+ media: UnstampedRowsSchema,
8785
+ retrainFrames: UnstampedRowsSchema,
8786
+ /** True when EITHER collection holds one. The refusal reads this. */
8787
+ anyPresent: boolean(),
8788
+ /** Sum across both, or `null` when either lane could not be counted. */
8789
+ total: number().int().nonnegative().nullable()
8790
+ }).nullable();
8748
8791
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
8749
8792
  /** The independently selectable logical storage classes — every class
8750
8793
  * `storage.listLocationDeclarations` reports, so an operator never meets a
@@ -8855,6 +8898,10 @@ var StorageMigrationMoveProgressSchema = object({
8855
8898
  /** The archive census — the **M** of "N of M" (D295). `null` = unknowable. */
8856
8899
  filesTotal: number().int().nonnegative().nullable(),
8857
8900
  bytesMoved: number().int().nonnegative(),
8901
+ /** Rows the mover corrected while moving them — see `RelocateJob`. Absent on
8902
+ * a lane that cannot reconcile. A migration that silently rewrote durable
8903
+ * rows would be the same failure as one that silently skipped them. */
8904
+ rowsReconciled: number().int().nonnegative().optional(),
8858
8905
  /** The MOVER's start, not the migration's: a drain restarted after an addon
8859
8906
  * crash gets a new mover, and a rate computed from the migration's start
8860
8907
  * would silently average in the time nothing was running. */
@@ -8657,6 +8657,21 @@ var RelocateJobSchema = object({
8657
8657
  bytesMoved: number().int(),
8658
8658
  /** Total files discovered up front; null while (or when) unknown. */
8659
8659
  filesTotal: number().int().nullable(),
8660
+ /**
8661
+ * Rows this run CORRECTED while moving them — a durable mutation the move
8662
+ * made that nobody asked for, so it is reported where the operator reads the
8663
+ * job rather than only in a log line.
8664
+ *
8665
+ * A footage segment records its byte count in its own NAME, and the durable
8666
+ * hour row derives its aggregates from those names. A file that does not
8667
+ * match its name therefore makes the ledger's sums — and with them quota and
8668
+ * pressure eviction — wrong by the difference, and only a rename can fix it.
8669
+ * On 2026-08-30 one such row also stalled a 110 749-file drain permanently.
8670
+ *
8671
+ * Absent on lanes where the question has no meaning: a media blob's size is
8672
+ * in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
8673
+ */
8674
+ rowsReconciled: number().int().nonnegative().optional(),
8660
8675
  startedAt: number(),
8661
8676
  finishedAt: number().nullable(),
8662
8677
  error: string().nullable()
@@ -8725,14 +8740,42 @@ var RelocateMediaInputSchema = object({
8725
8740
  /** Omitted = `move`, the pre-existing behaviour. */
8726
8741
  mode: MediaRelocateModeSchema.optional()
8727
8742
  });
8728
- /** How many rows still carry NO `locationId` — the population a repoint would
8729
- * silently re-aim at a disk that does not hold their bytes. Zero is the only
8730
- * value that permits a non-blocking `eventMedia` cutover. */
8731
- var UnstampedEventMediaCountSchema = object({
8732
- media: number().int().nonnegative(),
8733
- retrainFrames: number().int().nonnegative(),
8734
- total: number().int().nonnegative()
8743
+ /**
8744
+ * The unstamped population of ONE collection split, because the gate and the
8745
+ * operator ask two different questions and only one of them has to be cheap.
8746
+ *
8747
+ * `present` is the GATE: "is there at least one row that would be orphaned by a
8748
+ * repoint". It is a single indexed seek to the first matching row, so it stays
8749
+ * answerable on a saturated disk and answers in O(log n) precisely in the state
8750
+ * that matters — after a seal, when the population is empty.
8751
+ *
8752
+ * `rows` is the NUMBER, for the refusal message and the operator's sense of
8753
+ * scale. It is a second, indexed `COUNT(*)`, and `null` means **not
8754
+ * measurable** — never zero. `{ present: true, rows: null }` is a legitimate
8755
+ * and useful answer: "there are some, and this read could not say how many"
8756
+ * still refuses the cutover, which is the whole job.
8757
+ */
8758
+ var UnstampedRowsSchema = object({
8759
+ present: boolean(),
8760
+ rows: number().int().nonnegative().nullable()
8735
8761
  });
8762
+ /**
8763
+ * How many rows still carry NO `locationId` — the population a repoint would
8764
+ * silently re-aim at a disk that does not hold their bytes.
8765
+ *
8766
+ * **`null` = the count could not be taken**, and it is NOT permission to cut
8767
+ * over. The gate opens on a measured absence and on nothing else; an unread
8768
+ * collection and an empty one are different facts, and this repo has already
8769
+ * paid for conflating them (`RelocateResidueSchema`, D295).
8770
+ */
8771
+ var UnstampedEventMediaCountSchema = object({
8772
+ media: UnstampedRowsSchema,
8773
+ retrainFrames: UnstampedRowsSchema,
8774
+ /** True when EITHER collection holds one. The refusal reads this. */
8775
+ anyPresent: boolean(),
8776
+ /** Sum across both, or `null` when either lane could not be counted. */
8777
+ total: number().int().nonnegative().nullable()
8778
+ }).nullable();
8736
8779
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
8737
8780
  /** The independently selectable logical storage classes — every class
8738
8781
  * `storage.listLocationDeclarations` reports, so an operator never meets a
@@ -8843,6 +8886,10 @@ var StorageMigrationMoveProgressSchema = object({
8843
8886
  /** The archive census — the **M** of "N of M" (D295). `null` = unknowable. */
8844
8887
  filesTotal: number().int().nonnegative().nullable(),
8845
8888
  bytesMoved: number().int().nonnegative(),
8889
+ /** Rows the mover corrected while moving them — see `RelocateJob`. Absent on
8890
+ * a lane that cannot reconcile. A migration that silently rewrote durable
8891
+ * rows would be the same failure as one that silently skipped them. */
8892
+ rowsReconciled: number().int().nonnegative().optional(),
8846
8893
  /** The MOVER's start, not the migration's: a drain restarted after an addon
8847
8894
  * crash gets a new mover, and a rate computed from the migration's start
8848
8895
  * would silently average in the time nothing was running. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-export-hap",
3
- "version": "1.2.56",
3
+ "version": "1.2.57",
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",