@camstack/addon-cloudflare 1.2.21 → 1.2.23

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.
@@ -7549,7 +7549,7 @@ var RecordingBandSchema = object({
7549
7549
  postBufferSec: number().min(0).optional()
7550
7550
  });
7551
7551
  ({
7552
- preBufferSec: 10,
7552
+ preBufferSec: 15,
7553
7553
  postBufferSec: 30
7554
7554
  }).postBufferSec * 1e3;
7555
7555
  /**
@@ -13527,128 +13527,103 @@ var COCO_TO_MACRO = {
13527
13527
  var AUDIO_MACRO_LABELS = [
13528
13528
  {
13529
13529
  id: "speech",
13530
- name: "Speech",
13531
- icon: "🗣️"
13530
+ name: "Speech"
13532
13531
  },
13533
13532
  {
13534
13533
  id: "scream",
13535
- name: "Scream / Shout",
13536
- icon: "😱"
13534
+ name: "Scream / Shout"
13537
13535
  },
13538
13536
  {
13539
13537
  id: "crying",
13540
- name: "Crying / Baby",
13541
- icon: "😢"
13538
+ name: "Crying / Baby"
13542
13539
  },
13543
13540
  {
13544
13541
  id: "laughter",
13545
- name: "Laughter",
13546
- icon: "😂"
13542
+ name: "Laughter"
13547
13543
  },
13548
13544
  {
13549
13545
  id: "music",
13550
- name: "Music",
13551
- icon: "🎵"
13546
+ name: "Music"
13552
13547
  },
13553
13548
  {
13554
13549
  id: "dog",
13555
- name: "Dog",
13556
- icon: "🐕"
13550
+ name: "Dog"
13557
13551
  },
13558
13552
  {
13559
13553
  id: "cat",
13560
- name: "Cat",
13561
- icon: "🐈"
13554
+ name: "Cat"
13562
13555
  },
13563
13556
  {
13564
13557
  id: "bird",
13565
- name: "Bird",
13566
- icon: "🐦"
13558
+ name: "Bird"
13567
13559
  },
13568
13560
  {
13569
13561
  id: "animal",
13570
- name: "Animal (other)",
13571
- icon: "🐾"
13562
+ name: "Animal (other)"
13572
13563
  },
13573
13564
  {
13574
13565
  id: "alarm",
13575
- name: "Alarm / Siren",
13576
- icon: "🚨"
13566
+ name: "Alarm / Siren"
13577
13567
  },
13578
13568
  {
13579
13569
  id: "doorbell",
13580
- name: "Doorbell / Knock",
13581
- icon: "🔔"
13570
+ name: "Doorbell / Knock"
13582
13571
  },
13583
13572
  {
13584
13573
  id: "glass_breaking",
13585
- name: "Glass Breaking",
13586
- icon: "💥"
13574
+ name: "Glass Breaking"
13587
13575
  },
13588
13576
  {
13589
13577
  id: "gunshot",
13590
- name: "Gunshot / Explosion",
13591
- icon: "💣"
13578
+ name: "Gunshot / Explosion"
13592
13579
  },
13593
13580
  {
13594
13581
  id: "vehicle",
13595
- name: "Vehicle",
13596
- icon: "🚗"
13582
+ name: "Vehicle"
13597
13583
  },
13598
13584
  {
13599
13585
  id: "siren",
13600
- name: "Emergency Siren",
13601
- icon: "🚑"
13586
+ name: "Emergency Siren"
13602
13587
  },
13603
13588
  {
13604
13589
  id: "fire",
13605
- name: "Fire / Smoke",
13606
- icon: "🔥"
13590
+ name: "Fire / Smoke"
13607
13591
  },
13608
13592
  {
13609
13593
  id: "water",
13610
- name: "Water",
13611
- icon: "💧"
13594
+ name: "Water"
13612
13595
  },
13613
13596
  {
13614
13597
  id: "wind",
13615
- name: "Wind / Weather",
13616
- icon: "🌬️"
13598
+ name: "Wind / Weather"
13617
13599
  },
13618
13600
  {
13619
13601
  id: "door",
13620
- name: "Door",
13621
- icon: "🚪"
13602
+ name: "Door"
13622
13603
  },
13623
13604
  {
13624
13605
  id: "footsteps",
13625
- name: "Footsteps",
13626
- icon: "👣"
13606
+ name: "Footsteps"
13627
13607
  },
13628
13608
  {
13629
13609
  id: "crowd",
13630
- name: "Crowd / Chatter",
13631
- icon: "👥"
13610
+ name: "Crowd / Chatter"
13632
13611
  },
13633
13612
  {
13634
13613
  id: "telephone",
13635
- name: "Telephone",
13636
- icon: "📞"
13614
+ name: "Telephone"
13637
13615
  },
13638
13616
  {
13639
13617
  id: "engine",
13640
- name: "Engine / Motor",
13641
- icon: "⚙️"
13618
+ name: "Engine / Motor"
13642
13619
  },
13643
13620
  {
13644
13621
  id: "tools",
13645
- name: "Tools / Construction",
13646
- icon: "🔨"
13622
+ name: "Tools / Construction"
13647
13623
  },
13648
13624
  {
13649
13625
  id: "silence",
13650
- name: "Silence",
13651
- icon: "🤫"
13626
+ name: "Silence"
13652
13627
  }
13653
13628
  ];
13654
13629
  var YAMNET_TO_MACRO = {
@@ -16112,7 +16087,7 @@ var TrackEnvelopeSchema = object({
16112
16087
  * `snapshots[]` references — megabytes across a page of tracks. `slim`
16113
16088
  * keeps every scalar the list surfaces actually render (ids, class(es),
16114
16089
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16115
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16090
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16116
16091
  * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16117
16092
  * `getTrack`. Mirrors the event-store `projection` convention
16118
16093
  * (`getObjectEvents` et al.).
@@ -16407,6 +16382,35 @@ var TrackSchema = object({
16407
16382
  */
16408
16383
  hasFace: boolean().optional(),
16409
16384
  /**
16385
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding — a
16386
+ * face an operator could ASSIGN to an identity.
16387
+ *
16388
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
16389
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
16390
+ * branch, before every gate, and means no more than "a face detector produced
16391
+ * a face detail". This one is stamped at the single moment the gallery row
16392
+ * LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
16393
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
16394
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
16395
+ * the crop-store drop. Everything between the detector and that insert can
16396
+ * legitimately refuse the face, so a flag written any earlier promises the
16397
+ * operator something to assign and delivers nothing.
16398
+ *
16399
+ * **Independent of recognition.** A face collected but never auto-matched is
16400
+ * still assignable — it is in fact the face an operator most wants to reach —
16401
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
16402
+ * `subLabel`; this says only that the raw material exists.
16403
+ *
16404
+ * **Set once, never cleared.** A track that produced a gallery row produced
16405
+ * one; deleting the row later is the gallery's business, not this flag's.
16406
+ *
16407
+ * **Absent ≠ false**, the same rule as {@link hasFace}: every row written
16408
+ * before the column omits it, and so does every server that predates the
16409
+ * field. A consumer must test `=== true` and render nothing otherwise —
16410
+ * never infer "no assignable face".
16411
+ */
16412
+ hasEmbeddedFace: boolean().optional(),
16413
+ /**
16410
16414
  * This subject CONTAINS a folded rider — a person the rider-pairing step
16411
16415
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
16412
16416
  * so the passage is tracked once and as a VEHICLE.
@@ -17756,6 +17760,32 @@ var DetailResultSchema = object({
17756
17760
  /** FRAME-space bbox (already mapped back from crop space). */
17757
17761
  bbox: NativeCropBboxSchema.optional(),
17758
17762
  embedding: string().optional(),
17763
+ /**
17764
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
17765
+ * so an older runner that does not send it degrades to "unmeasurable", which
17766
+ * the consuming gate treats as accept — never as reject.
17767
+ */
17768
+ embeddingMagnitude: number().optional(),
17769
+ /**
17770
+ * Model that produced `embedding` — the SAME contract `labelModelId` has for
17771
+ * `label`, and for the same reason: the producing node is the only side that
17772
+ * knows which model actually ran, and re-deriving it downstream is exactly
17773
+ * the inference this model exists to forbid.
17774
+ *
17775
+ * Additive and optional, so a runner that predates it degrades to
17776
+ * "unmeasurable" rather than to a wrong answer — the consumer falls back to
17777
+ * its previous assumption instead of refusing.
17778
+ *
17779
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
17780
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
17781
+ * with nothing on the wire it took the id from the GALLERY, so the gate
17782
+ * compared the gallery against itself and could never fire. That turned the
17783
+ * one guard protecting the face feature space into a tautology, and it is
17784
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
17785
+ * gallery as the catalog comment predicts — it would have scored the new
17786
+ * model's vectors against the old model's samples in one cosine space.
17787
+ */
17788
+ embeddingModelId: string().optional(),
17759
17789
  label: string().optional(),
17760
17790
  /**
17761
17791
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -19166,6 +19196,7 @@ DeviceType.Camera, method(object({
19166
19196
  isBattery: boolean(),
19167
19197
  reason: _enum([
19168
19198
  "disabled",
19199
+ "offline",
19169
19200
  "sleeping",
19170
19201
  "unreachable",
19171
19202
  "waking"
@@ -19211,9 +19242,17 @@ targets: array(object({
19211
19242
  sleeping: boolean(),
19212
19243
  /** Current device state rendered over the cached frame. State images
19213
19244
  * remain authoritative even when their photographic background is
19214
- * old; null means the link must carry a current camera frame. */
19245
+ * old; null means the link must carry a current camera frame.
19246
+ *
19247
+ * **This is the ONLY source a surface may derive an inactive tile
19248
+ * from.** A client that reads a device's `online`/`disabled` flags and
19249
+ * draws its own verdict will disagree with the pixels it is painting
19250
+ * — the frame comes from here, and so must the sentence over it
19251
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19252
+ * state. */
19215
19253
  stateReason: _enum([
19216
19254
  "disabled",
19255
+ "offline",
19217
19256
  "sleeping",
19218
19257
  "unreachable",
19219
19258
  "waking"
@@ -24267,9 +24306,21 @@ var RecordingLocationUsageSchema = object({
24267
24306
  * previously rendered as two identical "disks" with a nonsensical used
24268
24307
  * split — hydrate attribution across aliases is arbitrary by nature. */
24269
24308
  locationIds: array(string()).optional(),
24270
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
24309
+ /**
24310
+ * Filesystem root of the physical volume this row accounts — the only
24311
+ * operator-legible identity when a location has no `displayName` yet, and
24312
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
24313
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
24314
+ * it, and this schema must keep validating that older provider's payload.
24315
+ */
24316
+ root: string().optional(),
24317
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
24318
+ * the footage's SHARE of the volume, not how full the volume is — the disk
24319
+ * also holds everything that is not recordings. Volume fill is
24320
+ * `(totalBytes - availableBytes) / totalBytes`. */
24271
24321
  usedBytes: number(),
24272
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
24322
+ /** Free bytes on the location's volume; null when capacity is unknown
24323
+ * (remote/unstattable — the recorder logs the statfs failure with the root). */
24273
24324
  availableBytes: number().nullable(),
24274
24325
  /** Total bytes of the location's volume; null when unknown. */
24275
24326
  totalBytes: number().nullable()
@@ -24281,7 +24332,15 @@ var RecordingStorageUsageSchema = object({
24281
24332
  nodeId: string(),
24282
24333
  totalUsedBytes: number(),
24283
24334
  devices: array(RecordingDeviceUsageSchema),
24284
- locations: array(RecordingLocationUsageSchema)
24335
+ /**
24336
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
24337
+ * of the payload without it: the hub serves this method through a BAKED
24338
+ * router, so a hub whose framework train predates a change to this array
24339
+ * strips it out of an answer a newer recorder happily produced. A UI that
24340
+ * dereferences it unconditionally crashes the whole Storage page over a
24341
+ * missing disk bar.
24342
+ */
24343
+ locations: array(RecordingLocationUsageSchema).optional()
24285
24344
  });
24286
24345
  /**
24287
24346
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -33397,8 +33456,13 @@ Object.freeze({
33397
33456
  "network-access": "ingress",
33398
33457
  "smtp-provider": "email"
33399
33458
  });
33400
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
33459
+ /** Schema defaults an untouched sub-field must author exactly these. */
33460
+ var NC_AUDIO_DEFAULTS = {
33461
+ hitPercent: 60,
33462
+ samplingSeconds: 10
33463
+ };
33401
33464
  new Set(["devices", "classes"]);
33465
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
33402
33466
  /**
33403
33467
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
33404
33468
  *
@@ -33630,6 +33694,39 @@ TimelapseRuleInputSchema.extend({
33630
33694
  createdAt: number(),
33631
33695
  updatedAt: number()
33632
33696
  });
33697
+ Object.freeze(Object.fromEntries([{
33698
+ stepId: "face-embedding",
33699
+ label: "Face recognition model",
33700
+ defaultModelId: "arcface-r100",
33701
+ indexName: "the enrolled face gallery",
33702
+ options: [
33703
+ {
33704
+ id: "arcface-r100",
33705
+ label: "ArcFace (ResNet34)"
33706
+ },
33707
+ {
33708
+ id: "auraface-r100",
33709
+ label: "AuraFace R100"
33710
+ },
33711
+ {
33712
+ id: "inception-resnet-v1",
33713
+ label: "Inception ResNet V1"
33714
+ }
33715
+ ]
33716
+ }, {
33717
+ stepId: "clip-embedding",
33718
+ label: "Semantic search model",
33719
+ defaultModelId: "mobileclip-s1",
33720
+ indexName: "the object semantic-search index",
33721
+ options: [{
33722
+ id: "mobileclip-s1",
33723
+ label: "MobileCLIP S1"
33724
+ }, {
33725
+ id: "mobileclip-s2",
33726
+ label: "MobileCLIP S2"
33727
+ }]
33728
+ }].map((s) => [s.stepId, s.defaultModelId])));
33729
+ string().min(1);
33633
33730
  object({
33634
33731
  /**
33635
33732
  * Fraction of the box's own size added on EACH side before cutting.
@@ -33650,10 +33747,21 @@ object({
33650
33747
  */
33651
33748
  square: boolean()
33652
33749
  });
33653
- ({
33750
+ /**
33751
+ * The convention in force when nobody has configured one — byte-for-byte the
33752
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
33753
+ */
33754
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
33654
33755
  paddingRatio: .15,
33655
33756
  square: false
33656
- }).paddingRatio;
33757
+ };
33758
+ Object.freeze({
33759
+ x: 0,
33760
+ y: 0,
33761
+ w: 1,
33762
+ h: 1
33763
+ });
33764
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
33657
33765
  /**
33658
33766
  * WHICH delivered frames the decode worker retains a native copy of.
33659
33767
  *
@@ -7549,7 +7549,7 @@ var RecordingBandSchema = object({
7549
7549
  postBufferSec: number().min(0).optional()
7550
7550
  });
7551
7551
  ({
7552
- preBufferSec: 10,
7552
+ preBufferSec: 15,
7553
7553
  postBufferSec: 30
7554
7554
  }).postBufferSec * 1e3;
7555
7555
  /**
@@ -13527,128 +13527,103 @@ var COCO_TO_MACRO = {
13527
13527
  var AUDIO_MACRO_LABELS = [
13528
13528
  {
13529
13529
  id: "speech",
13530
- name: "Speech",
13531
- icon: "🗣️"
13530
+ name: "Speech"
13532
13531
  },
13533
13532
  {
13534
13533
  id: "scream",
13535
- name: "Scream / Shout",
13536
- icon: "😱"
13534
+ name: "Scream / Shout"
13537
13535
  },
13538
13536
  {
13539
13537
  id: "crying",
13540
- name: "Crying / Baby",
13541
- icon: "😢"
13538
+ name: "Crying / Baby"
13542
13539
  },
13543
13540
  {
13544
13541
  id: "laughter",
13545
- name: "Laughter",
13546
- icon: "😂"
13542
+ name: "Laughter"
13547
13543
  },
13548
13544
  {
13549
13545
  id: "music",
13550
- name: "Music",
13551
- icon: "🎵"
13546
+ name: "Music"
13552
13547
  },
13553
13548
  {
13554
13549
  id: "dog",
13555
- name: "Dog",
13556
- icon: "🐕"
13550
+ name: "Dog"
13557
13551
  },
13558
13552
  {
13559
13553
  id: "cat",
13560
- name: "Cat",
13561
- icon: "🐈"
13554
+ name: "Cat"
13562
13555
  },
13563
13556
  {
13564
13557
  id: "bird",
13565
- name: "Bird",
13566
- icon: "🐦"
13558
+ name: "Bird"
13567
13559
  },
13568
13560
  {
13569
13561
  id: "animal",
13570
- name: "Animal (other)",
13571
- icon: "🐾"
13562
+ name: "Animal (other)"
13572
13563
  },
13573
13564
  {
13574
13565
  id: "alarm",
13575
- name: "Alarm / Siren",
13576
- icon: "🚨"
13566
+ name: "Alarm / Siren"
13577
13567
  },
13578
13568
  {
13579
13569
  id: "doorbell",
13580
- name: "Doorbell / Knock",
13581
- icon: "🔔"
13570
+ name: "Doorbell / Knock"
13582
13571
  },
13583
13572
  {
13584
13573
  id: "glass_breaking",
13585
- name: "Glass Breaking",
13586
- icon: "💥"
13574
+ name: "Glass Breaking"
13587
13575
  },
13588
13576
  {
13589
13577
  id: "gunshot",
13590
- name: "Gunshot / Explosion",
13591
- icon: "💣"
13578
+ name: "Gunshot / Explosion"
13592
13579
  },
13593
13580
  {
13594
13581
  id: "vehicle",
13595
- name: "Vehicle",
13596
- icon: "🚗"
13582
+ name: "Vehicle"
13597
13583
  },
13598
13584
  {
13599
13585
  id: "siren",
13600
- name: "Emergency Siren",
13601
- icon: "🚑"
13586
+ name: "Emergency Siren"
13602
13587
  },
13603
13588
  {
13604
13589
  id: "fire",
13605
- name: "Fire / Smoke",
13606
- icon: "🔥"
13590
+ name: "Fire / Smoke"
13607
13591
  },
13608
13592
  {
13609
13593
  id: "water",
13610
- name: "Water",
13611
- icon: "💧"
13594
+ name: "Water"
13612
13595
  },
13613
13596
  {
13614
13597
  id: "wind",
13615
- name: "Wind / Weather",
13616
- icon: "🌬️"
13598
+ name: "Wind / Weather"
13617
13599
  },
13618
13600
  {
13619
13601
  id: "door",
13620
- name: "Door",
13621
- icon: "🚪"
13602
+ name: "Door"
13622
13603
  },
13623
13604
  {
13624
13605
  id: "footsteps",
13625
- name: "Footsteps",
13626
- icon: "👣"
13606
+ name: "Footsteps"
13627
13607
  },
13628
13608
  {
13629
13609
  id: "crowd",
13630
- name: "Crowd / Chatter",
13631
- icon: "👥"
13610
+ name: "Crowd / Chatter"
13632
13611
  },
13633
13612
  {
13634
13613
  id: "telephone",
13635
- name: "Telephone",
13636
- icon: "📞"
13614
+ name: "Telephone"
13637
13615
  },
13638
13616
  {
13639
13617
  id: "engine",
13640
- name: "Engine / Motor",
13641
- icon: "⚙️"
13618
+ name: "Engine / Motor"
13642
13619
  },
13643
13620
  {
13644
13621
  id: "tools",
13645
- name: "Tools / Construction",
13646
- icon: "🔨"
13622
+ name: "Tools / Construction"
13647
13623
  },
13648
13624
  {
13649
13625
  id: "silence",
13650
- name: "Silence",
13651
- icon: "🤫"
13626
+ name: "Silence"
13652
13627
  }
13653
13628
  ];
13654
13629
  var YAMNET_TO_MACRO = {
@@ -16112,7 +16087,7 @@ var TrackEnvelopeSchema = object({
16112
16087
  * `snapshots[]` references — megabytes across a page of tracks. `slim`
16113
16088
  * keeps every scalar the list surfaces actually render (ids, class(es),
16114
16089
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16115
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16090
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16116
16091
  * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16117
16092
  * `getTrack`. Mirrors the event-store `projection` convention
16118
16093
  * (`getObjectEvents` et al.).
@@ -16407,6 +16382,35 @@ var TrackSchema = object({
16407
16382
  */
16408
16383
  hasFace: boolean().optional(),
16409
16384
  /**
16385
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding — a
16386
+ * face an operator could ASSIGN to an identity.
16387
+ *
16388
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
16389
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
16390
+ * branch, before every gate, and means no more than "a face detector produced
16391
+ * a face detail". This one is stamped at the single moment the gallery row
16392
+ * LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
16393
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
16394
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
16395
+ * the crop-store drop. Everything between the detector and that insert can
16396
+ * legitimately refuse the face, so a flag written any earlier promises the
16397
+ * operator something to assign and delivers nothing.
16398
+ *
16399
+ * **Independent of recognition.** A face collected but never auto-matched is
16400
+ * still assignable — it is in fact the face an operator most wants to reach —
16401
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
16402
+ * `subLabel`; this says only that the raw material exists.
16403
+ *
16404
+ * **Set once, never cleared.** A track that produced a gallery row produced
16405
+ * one; deleting the row later is the gallery's business, not this flag's.
16406
+ *
16407
+ * **Absent ≠ false**, the same rule as {@link hasFace}: every row written
16408
+ * before the column omits it, and so does every server that predates the
16409
+ * field. A consumer must test `=== true` and render nothing otherwise —
16410
+ * never infer "no assignable face".
16411
+ */
16412
+ hasEmbeddedFace: boolean().optional(),
16413
+ /**
16410
16414
  * This subject CONTAINS a folded rider — a person the rider-pairing step
16411
16415
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
16412
16416
  * so the passage is tracked once and as a VEHICLE.
@@ -17756,6 +17760,32 @@ var DetailResultSchema = object({
17756
17760
  /** FRAME-space bbox (already mapped back from crop space). */
17757
17761
  bbox: NativeCropBboxSchema.optional(),
17758
17762
  embedding: string().optional(),
17763
+ /**
17764
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
17765
+ * so an older runner that does not send it degrades to "unmeasurable", which
17766
+ * the consuming gate treats as accept — never as reject.
17767
+ */
17768
+ embeddingMagnitude: number().optional(),
17769
+ /**
17770
+ * Model that produced `embedding` — the SAME contract `labelModelId` has for
17771
+ * `label`, and for the same reason: the producing node is the only side that
17772
+ * knows which model actually ran, and re-deriving it downstream is exactly
17773
+ * the inference this model exists to forbid.
17774
+ *
17775
+ * Additive and optional, so a runner that predates it degrades to
17776
+ * "unmeasurable" rather than to a wrong answer — the consumer falls back to
17777
+ * its previous assumption instead of refusing.
17778
+ *
17779
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
17780
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
17781
+ * with nothing on the wire it took the id from the GALLERY, so the gate
17782
+ * compared the gallery against itself and could never fire. That turned the
17783
+ * one guard protecting the face feature space into a tautology, and it is
17784
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
17785
+ * gallery as the catalog comment predicts — it would have scored the new
17786
+ * model's vectors against the old model's samples in one cosine space.
17787
+ */
17788
+ embeddingModelId: string().optional(),
17759
17789
  label: string().optional(),
17760
17790
  /**
17761
17791
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -19166,6 +19196,7 @@ DeviceType.Camera, method(object({
19166
19196
  isBattery: boolean(),
19167
19197
  reason: _enum([
19168
19198
  "disabled",
19199
+ "offline",
19169
19200
  "sleeping",
19170
19201
  "unreachable",
19171
19202
  "waking"
@@ -19211,9 +19242,17 @@ targets: array(object({
19211
19242
  sleeping: boolean(),
19212
19243
  /** Current device state rendered over the cached frame. State images
19213
19244
  * remain authoritative even when their photographic background is
19214
- * old; null means the link must carry a current camera frame. */
19245
+ * old; null means the link must carry a current camera frame.
19246
+ *
19247
+ * **This is the ONLY source a surface may derive an inactive tile
19248
+ * from.** A client that reads a device's `online`/`disabled` flags and
19249
+ * draws its own verdict will disagree with the pixels it is painting
19250
+ * — the frame comes from here, and so must the sentence over it
19251
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19252
+ * state. */
19215
19253
  stateReason: _enum([
19216
19254
  "disabled",
19255
+ "offline",
19217
19256
  "sleeping",
19218
19257
  "unreachable",
19219
19258
  "waking"
@@ -24267,9 +24306,21 @@ var RecordingLocationUsageSchema = object({
24267
24306
  * previously rendered as two identical "disks" with a nonsensical used
24268
24307
  * split — hydrate attribution across aliases is arbitrary by nature. */
24269
24308
  locationIds: array(string()).optional(),
24270
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
24309
+ /**
24310
+ * Filesystem root of the physical volume this row accounts — the only
24311
+ * operator-legible identity when a location has no `displayName` yet, and
24312
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
24313
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
24314
+ * it, and this schema must keep validating that older provider's payload.
24315
+ */
24316
+ root: string().optional(),
24317
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
24318
+ * the footage's SHARE of the volume, not how full the volume is — the disk
24319
+ * also holds everything that is not recordings. Volume fill is
24320
+ * `(totalBytes - availableBytes) / totalBytes`. */
24271
24321
  usedBytes: number(),
24272
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
24322
+ /** Free bytes on the location's volume; null when capacity is unknown
24323
+ * (remote/unstattable — the recorder logs the statfs failure with the root). */
24273
24324
  availableBytes: number().nullable(),
24274
24325
  /** Total bytes of the location's volume; null when unknown. */
24275
24326
  totalBytes: number().nullable()
@@ -24281,7 +24332,15 @@ var RecordingStorageUsageSchema = object({
24281
24332
  nodeId: string(),
24282
24333
  totalUsedBytes: number(),
24283
24334
  devices: array(RecordingDeviceUsageSchema),
24284
- locations: array(RecordingLocationUsageSchema)
24335
+ /**
24336
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
24337
+ * of the payload without it: the hub serves this method through a BAKED
24338
+ * router, so a hub whose framework train predates a change to this array
24339
+ * strips it out of an answer a newer recorder happily produced. A UI that
24340
+ * dereferences it unconditionally crashes the whole Storage page over a
24341
+ * missing disk bar.
24342
+ */
24343
+ locations: array(RecordingLocationUsageSchema).optional()
24285
24344
  });
24286
24345
  /**
24287
24346
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -33397,8 +33456,13 @@ Object.freeze({
33397
33456
  "network-access": "ingress",
33398
33457
  "smtp-provider": "email"
33399
33458
  });
33400
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
33459
+ /** Schema defaults an untouched sub-field must author exactly these. */
33460
+ var NC_AUDIO_DEFAULTS = {
33461
+ hitPercent: 60,
33462
+ samplingSeconds: 10
33463
+ };
33401
33464
  new Set(["devices", "classes"]);
33465
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
33402
33466
  /**
33403
33467
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
33404
33468
  *
@@ -33630,6 +33694,39 @@ TimelapseRuleInputSchema.extend({
33630
33694
  createdAt: number(),
33631
33695
  updatedAt: number()
33632
33696
  });
33697
+ Object.freeze(Object.fromEntries([{
33698
+ stepId: "face-embedding",
33699
+ label: "Face recognition model",
33700
+ defaultModelId: "arcface-r100",
33701
+ indexName: "the enrolled face gallery",
33702
+ options: [
33703
+ {
33704
+ id: "arcface-r100",
33705
+ label: "ArcFace (ResNet34)"
33706
+ },
33707
+ {
33708
+ id: "auraface-r100",
33709
+ label: "AuraFace R100"
33710
+ },
33711
+ {
33712
+ id: "inception-resnet-v1",
33713
+ label: "Inception ResNet V1"
33714
+ }
33715
+ ]
33716
+ }, {
33717
+ stepId: "clip-embedding",
33718
+ label: "Semantic search model",
33719
+ defaultModelId: "mobileclip-s1",
33720
+ indexName: "the object semantic-search index",
33721
+ options: [{
33722
+ id: "mobileclip-s1",
33723
+ label: "MobileCLIP S1"
33724
+ }, {
33725
+ id: "mobileclip-s2",
33726
+ label: "MobileCLIP S2"
33727
+ }]
33728
+ }].map((s) => [s.stepId, s.defaultModelId])));
33729
+ string().min(1);
33633
33730
  object({
33634
33731
  /**
33635
33732
  * Fraction of the box's own size added on EACH side before cutting.
@@ -33650,10 +33747,21 @@ object({
33650
33747
  */
33651
33748
  square: boolean()
33652
33749
  });
33653
- ({
33750
+ /**
33751
+ * The convention in force when nobody has configured one — byte-for-byte the
33752
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
33753
+ */
33754
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
33654
33755
  paddingRatio: .15,
33655
33756
  square: false
33656
- }).paddingRatio;
33757
+ };
33758
+ Object.freeze({
33759
+ x: 0,
33760
+ y: 0,
33761
+ w: 1,
33762
+ h: 1
33763
+ });
33764
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
33657
33765
  /**
33658
33766
  * WHICH delivered frames the decode worker retains a native copy of.
33659
33767
  *
@@ -21,7 +21,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  enumerable: true
22
22
  }) : target, mod));
23
23
  //#endregion
24
- const require_dist = require("../dist-CfYr3SWQ.js");
24
+ const require_dist = require("../dist-B3Wo-Mb6.js");
25
25
  let node_crypto = require("node:crypto");
26
26
  let node_path = require("node:path");
27
27
  node_path = __toESM(node_path);
@@ -1,4 +1,4 @@
1
- import { a as BaseAddon, c as boolean, d as number, f as object, m as EventCategory, n as defineCustomActions, o as _enum, p as string, r as networkAccessCapability, s as array, t as customAction, u as literal } from "../dist-DP9CmDJx.mjs";
1
+ import { a as BaseAddon, c as boolean, d as number, f as object, m as EventCategory, n as defineCustomActions, o as _enum, p as string, r as networkAccessCapability, s as array, t as customAction, u as literal } from "../dist-If1V2ljI.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import * as path from "node:path";
4
4
  import { spawn } from "node:child_process";
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("../dist-CfYr3SWQ.js");
2
+ const require_dist = require("../dist-B3Wo-Mb6.js");
3
3
  //#region src/turn/cloudflare-turn.ts
4
4
  /**
5
5
  * Cloudflare returns ICE servers in several flavours depending on which
@@ -1,4 +1,4 @@
1
- import { a as BaseAddon, c as boolean, d as number, f as object, i as turnProviderCapability, l as discriminatedUnion, n as defineCustomActions, p as string, t as customAction, u as literal } from "../dist-DP9CmDJx.mjs";
1
+ import { a as BaseAddon, c as boolean, d as number, f as object, i as turnProviderCapability, l as discriminatedUnion, n as defineCustomActions, p as string, t as customAction, u as literal } from "../dist-If1V2ljI.mjs";
2
2
  //#region src/turn/cloudflare-turn.ts
3
3
  /**
4
4
  * Cloudflare returns ICE servers in several flavours depending on which
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-cloudflare",
3
- "version": "1.2.21",
3
+ "version": "1.2.23",
4
4
  "description": "Cloudflare bundle — Tunnel (network-access) + TURN relay (turn-provider). Multi-entry npm package shipping 2 addons under a single bundle.",
5
5
  "keywords": [
6
6
  "camstack",