@camstack/addon-export-hap 1.2.33 β†’ 1.2.35

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.
@@ -8232,7 +8232,7 @@ var RecordingBandSchema = object({
8232
8232
  postBufferSec: number().min(0).optional()
8233
8233
  });
8234
8234
  ({
8235
- preBufferSec: 10,
8235
+ preBufferSec: 15,
8236
8236
  postBufferSec: 30
8237
8237
  }).postBufferSec * 1e3;
8238
8238
  /**
@@ -14306,128 +14306,103 @@ var COCO_TO_MACRO = {
14306
14306
  var AUDIO_MACRO_LABELS = [
14307
14307
  {
14308
14308
  id: "speech",
14309
- name: "Speech",
14310
- icon: "πŸ—£οΈ"
14309
+ name: "Speech"
14311
14310
  },
14312
14311
  {
14313
14312
  id: "scream",
14314
- name: "Scream / Shout",
14315
- icon: "😱"
14313
+ name: "Scream / Shout"
14316
14314
  },
14317
14315
  {
14318
14316
  id: "crying",
14319
- name: "Crying / Baby",
14320
- icon: "😒"
14317
+ name: "Crying / Baby"
14321
14318
  },
14322
14319
  {
14323
14320
  id: "laughter",
14324
- name: "Laughter",
14325
- icon: "πŸ˜‚"
14321
+ name: "Laughter"
14326
14322
  },
14327
14323
  {
14328
14324
  id: "music",
14329
- name: "Music",
14330
- icon: "🎡"
14325
+ name: "Music"
14331
14326
  },
14332
14327
  {
14333
14328
  id: "dog",
14334
- name: "Dog",
14335
- icon: "πŸ•"
14329
+ name: "Dog"
14336
14330
  },
14337
14331
  {
14338
14332
  id: "cat",
14339
- name: "Cat",
14340
- icon: "🐈"
14333
+ name: "Cat"
14341
14334
  },
14342
14335
  {
14343
14336
  id: "bird",
14344
- name: "Bird",
14345
- icon: "🐦"
14337
+ name: "Bird"
14346
14338
  },
14347
14339
  {
14348
14340
  id: "animal",
14349
- name: "Animal (other)",
14350
- icon: "🐾"
14341
+ name: "Animal (other)"
14351
14342
  },
14352
14343
  {
14353
14344
  id: "alarm",
14354
- name: "Alarm / Siren",
14355
- icon: "🚨"
14345
+ name: "Alarm / Siren"
14356
14346
  },
14357
14347
  {
14358
14348
  id: "doorbell",
14359
- name: "Doorbell / Knock",
14360
- icon: "πŸ””"
14349
+ name: "Doorbell / Knock"
14361
14350
  },
14362
14351
  {
14363
14352
  id: "glass_breaking",
14364
- name: "Glass Breaking",
14365
- icon: "πŸ’₯"
14353
+ name: "Glass Breaking"
14366
14354
  },
14367
14355
  {
14368
14356
  id: "gunshot",
14369
- name: "Gunshot / Explosion",
14370
- icon: "πŸ’£"
14357
+ name: "Gunshot / Explosion"
14371
14358
  },
14372
14359
  {
14373
14360
  id: "vehicle",
14374
- name: "Vehicle",
14375
- icon: "πŸš—"
14361
+ name: "Vehicle"
14376
14362
  },
14377
14363
  {
14378
14364
  id: "siren",
14379
- name: "Emergency Siren",
14380
- icon: "πŸš‘"
14365
+ name: "Emergency Siren"
14381
14366
  },
14382
14367
  {
14383
14368
  id: "fire",
14384
- name: "Fire / Smoke",
14385
- icon: "πŸ”₯"
14369
+ name: "Fire / Smoke"
14386
14370
  },
14387
14371
  {
14388
14372
  id: "water",
14389
- name: "Water",
14390
- icon: "πŸ’§"
14373
+ name: "Water"
14391
14374
  },
14392
14375
  {
14393
14376
  id: "wind",
14394
- name: "Wind / Weather",
14395
- icon: "🌬️"
14377
+ name: "Wind / Weather"
14396
14378
  },
14397
14379
  {
14398
14380
  id: "door",
14399
- name: "Door",
14400
- icon: "πŸšͺ"
14381
+ name: "Door"
14401
14382
  },
14402
14383
  {
14403
14384
  id: "footsteps",
14404
- name: "Footsteps",
14405
- icon: "πŸ‘£"
14385
+ name: "Footsteps"
14406
14386
  },
14407
14387
  {
14408
14388
  id: "crowd",
14409
- name: "Crowd / Chatter",
14410
- icon: "πŸ‘₯"
14389
+ name: "Crowd / Chatter"
14411
14390
  },
14412
14391
  {
14413
14392
  id: "telephone",
14414
- name: "Telephone",
14415
- icon: "πŸ“ž"
14393
+ name: "Telephone"
14416
14394
  },
14417
14395
  {
14418
14396
  id: "engine",
14419
- name: "Engine / Motor",
14420
- icon: "βš™οΈ"
14397
+ name: "Engine / Motor"
14421
14398
  },
14422
14399
  {
14423
14400
  id: "tools",
14424
- name: "Tools / Construction",
14425
- icon: "πŸ”¨"
14401
+ name: "Tools / Construction"
14426
14402
  },
14427
14403
  {
14428
14404
  id: "silence",
14429
- name: "Silence",
14430
- icon: "🀫"
14405
+ name: "Silence"
14431
14406
  }
14432
14407
  ];
14433
14408
  var YAMNET_TO_MACRO = {
@@ -16891,7 +16866,7 @@ var TrackEnvelopeSchema = object({
16891
16866
  * `snapshots[]` references β€” megabytes across a page of tracks. `slim`
16892
16867
  * keeps every scalar the list surfaces actually render (ids, class(es),
16893
16868
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16894
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16869
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16895
16870
  * `snapshots` as EMPTY arrays β€” detail views re-fetch the full row via
16896
16871
  * `getTrack`. Mirrors the event-store `projection` convention
16897
16872
  * (`getObjectEvents` et al.).
@@ -17186,6 +17161,35 @@ var TrackSchema = object({
17186
17161
  */
17187
17162
  hasFace: boolean().optional(),
17188
17163
  /**
17164
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding β€” a
17165
+ * face an operator could ASSIGN to an identity.
17166
+ *
17167
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
17168
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
17169
+ * branch, before every gate, and means no more than "a face detector produced
17170
+ * a face detail". This one is stamped at the single moment the gallery row
17171
+ * LANDS β€” after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
17172
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
17173
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
17174
+ * the crop-store drop. Everything between the detector and that insert can
17175
+ * legitimately refuse the face, so a flag written any earlier promises the
17176
+ * operator something to assign and delivers nothing.
17177
+ *
17178
+ * **Independent of recognition.** A face collected but never auto-matched is
17179
+ * still assignable β€” it is in fact the face an operator most wants to reach β€”
17180
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
17181
+ * `subLabel`; this says only that the raw material exists.
17182
+ *
17183
+ * **Set once, never cleared.** A track that produced a gallery row produced
17184
+ * one; deleting the row later is the gallery's business, not this flag's.
17185
+ *
17186
+ * **Absent β‰  false**, the same rule as {@link hasFace}: every row written
17187
+ * before the column omits it, and so does every server that predates the
17188
+ * field. A consumer must test `=== true` and render nothing otherwise β€”
17189
+ * never infer "no assignable face".
17190
+ */
17191
+ hasEmbeddedFace: boolean().optional(),
17192
+ /**
17189
17193
  * This subject CONTAINS a folded rider β€” a person the rider-pairing step
17190
17194
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
17191
17195
  * so the passage is tracked once and as a VEHICLE.
@@ -18535,6 +18539,32 @@ var DetailResultSchema = object({
18535
18539
  /** FRAME-space bbox (already mapped back from crop space). */
18536
18540
  bbox: NativeCropBboxSchema.optional(),
18537
18541
  embedding: string().optional(),
18542
+ /**
18543
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
18544
+ * so an older runner that does not send it degrades to "unmeasurable", which
18545
+ * the consuming gate treats as accept β€” never as reject.
18546
+ */
18547
+ embeddingMagnitude: number().optional(),
18548
+ /**
18549
+ * Model that produced `embedding` β€” the SAME contract `labelModelId` has for
18550
+ * `label`, and for the same reason: the producing node is the only side that
18551
+ * knows which model actually ran, and re-deriving it downstream is exactly
18552
+ * the inference this model exists to forbid.
18553
+ *
18554
+ * Additive and optional, so a runner that predates it degrades to
18555
+ * "unmeasurable" rather than to a wrong answer β€” the consumer falls back to
18556
+ * its previous assumption instead of refusing.
18557
+ *
18558
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
18559
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
18560
+ * with nothing on the wire it took the id from the GALLERY, so the gate
18561
+ * compared the gallery against itself and could never fire. That turned the
18562
+ * one guard protecting the face feature space into a tautology, and it is
18563
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
18564
+ * gallery as the catalog comment predicts β€” it would have scored the new
18565
+ * model's vectors against the old model's samples in one cosine space.
18566
+ */
18567
+ embeddingModelId: string().optional(),
18538
18568
  label: string().optional(),
18539
18569
  /**
18540
18570
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -19945,6 +19975,7 @@ DeviceType.Camera, method(object({
19945
19975
  isBattery: boolean(),
19946
19976
  reason: _enum([
19947
19977
  "disabled",
19978
+ "offline",
19948
19979
  "sleeping",
19949
19980
  "unreachable",
19950
19981
  "waking"
@@ -19990,9 +20021,17 @@ targets: array(object({
19990
20021
  sleeping: boolean(),
19991
20022
  /** Current device state rendered over the cached frame. State images
19992
20023
  * remain authoritative even when their photographic background is
19993
- * old; null means the link must carry a current camera frame. */
20024
+ * old; null means the link must carry a current camera frame.
20025
+ *
20026
+ * **This is the ONLY source a surface may derive an inactive tile
20027
+ * from.** A client that reads a device's `online`/`disabled` flags and
20028
+ * draws its own verdict will disagree with the pixels it is painting
20029
+ * β€” the frame comes from here, and so must the sentence over it
20030
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
20031
+ * state. */
19994
20032
  stateReason: _enum([
19995
20033
  "disabled",
20034
+ "offline",
19996
20035
  "sleeping",
19997
20036
  "unreachable",
19998
20037
  "waking"
@@ -25071,9 +25110,21 @@ var RecordingLocationUsageSchema = object({
25071
25110
  * previously rendered as two identical "disks" with a nonsensical used
25072
25111
  * split β€” hydrate attribution across aliases is arbitrary by nature. */
25073
25112
  locationIds: array(string()).optional(),
25074
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
25113
+ /**
25114
+ * Filesystem root of the physical volume this row accounts β€” the only
25115
+ * operator-legible identity when a location has no `displayName` yet, and
25116
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
25117
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
25118
+ * it, and this schema must keep validating that older provider's payload.
25119
+ */
25120
+ root: string().optional(),
25121
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
25122
+ * the footage's SHARE of the volume, not how full the volume is β€” the disk
25123
+ * also holds everything that is not recordings. Volume fill is
25124
+ * `(totalBytes - availableBytes) / totalBytes`. */
25075
25125
  usedBytes: number(),
25076
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
25126
+ /** Free bytes on the location's volume; null when capacity is unknown
25127
+ * (remote/unstattable β€” the recorder logs the statfs failure with the root). */
25077
25128
  availableBytes: number().nullable(),
25078
25129
  /** Total bytes of the location's volume; null when unknown. */
25079
25130
  totalBytes: number().nullable()
@@ -25085,7 +25136,15 @@ var RecordingStorageUsageSchema = object({
25085
25136
  nodeId: string(),
25086
25137
  totalUsedBytes: number(),
25087
25138
  devices: array(RecordingDeviceUsageSchema),
25088
- locations: array(RecordingLocationUsageSchema)
25139
+ /**
25140
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
25141
+ * of the payload without it: the hub serves this method through a BAKED
25142
+ * router, so a hub whose framework train predates a change to this array
25143
+ * strips it out of an answer a newer recorder happily produced. A UI that
25144
+ * dereferences it unconditionally crashes the whole Storage page over a
25145
+ * missing disk bar.
25146
+ */
25147
+ locations: array(RecordingLocationUsageSchema).optional()
25089
25148
  });
25090
25149
  /**
25091
25150
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -34226,8 +34285,13 @@ Object.freeze({
34226
34285
  "network-access": "ingress",
34227
34286
  "smtp-provider": "email"
34228
34287
  });
34229
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
34288
+ /** Schema defaults β€” an untouched sub-field must author exactly these. */
34289
+ var NC_AUDIO_DEFAULTS = {
34290
+ hitPercent: 60,
34291
+ samplingSeconds: 10
34292
+ };
34230
34293
  new Set(["devices", "classes"]);
34294
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
34231
34295
  /**
34232
34296
  * TimelapseRule β€” the STANDALONE scheduled timelapse producer's rule model.
34233
34297
  *
@@ -34459,6 +34523,39 @@ TimelapseRuleInputSchema.extend({
34459
34523
  createdAt: number(),
34460
34524
  updatedAt: number()
34461
34525
  });
34526
+ Object.freeze(Object.fromEntries([{
34527
+ stepId: "face-embedding",
34528
+ label: "Face recognition model",
34529
+ defaultModelId: "arcface-r100",
34530
+ indexName: "the enrolled face gallery",
34531
+ options: [
34532
+ {
34533
+ id: "arcface-r100",
34534
+ label: "ArcFace (ResNet34)"
34535
+ },
34536
+ {
34537
+ id: "auraface-r100",
34538
+ label: "AuraFace R100"
34539
+ },
34540
+ {
34541
+ id: "inception-resnet-v1",
34542
+ label: "Inception ResNet V1"
34543
+ }
34544
+ ]
34545
+ }, {
34546
+ stepId: "clip-embedding",
34547
+ label: "Semantic search model",
34548
+ defaultModelId: "mobileclip-s1",
34549
+ indexName: "the object semantic-search index",
34550
+ options: [{
34551
+ id: "mobileclip-s1",
34552
+ label: "MobileCLIP S1"
34553
+ }, {
34554
+ id: "mobileclip-s2",
34555
+ label: "MobileCLIP S2"
34556
+ }]
34557
+ }].map((s) => [s.stepId, s.defaultModelId])));
34558
+ string().min(1);
34462
34559
  object({
34463
34560
  /**
34464
34561
  * Fraction of the box's own size added on EACH side before cutting.
@@ -34479,10 +34576,21 @@ object({
34479
34576
  */
34480
34577
  square: boolean()
34481
34578
  });
34482
- ({
34579
+ /**
34580
+ * The convention in force when nobody has configured one β€” byte-for-byte the
34581
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
34582
+ */
34583
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
34483
34584
  paddingRatio: .15,
34484
34585
  square: false
34485
- }).paddingRatio;
34586
+ };
34587
+ Object.freeze({
34588
+ x: 0,
34589
+ y: 0,
34590
+ w: 1,
34591
+ h: 1
34592
+ });
34593
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
34486
34594
  /**
34487
34595
  * WHICH delivered frames the decode worker retains a native copy of.
34488
34596
  *
@@ -94247,7 +94355,7 @@ function isConnectionLike(value) {
94247
94355
  return isRecord$1(value) && typeof value["hasEventNotifications"] === "function";
94248
94356
  }
94249
94357
  function isIterable$1(value) {
94250
- return isRecord$1(value) && typeof value[Symbol.iterator] === "function";
94358
+ return isRecord$1(value) && typeof Reflect.get(value, Symbol.iterator) === "function";
94251
94359
  }
94252
94360
  /** `accessory._server.httpServer.connections`, or null at any missing hop. */
94253
94361
  function readConnections$1(accessory) {
@@ -94709,7 +94817,7 @@ function isRecord(value) {
94709
94817
  return typeof value === "object" && value !== null;
94710
94818
  }
94711
94819
  function isIterable(value) {
94712
- return isRecord(value) && typeof value[Symbol.iterator] === "function";
94820
+ return isRecord(value) && typeof Reflect.get(value, Symbol.iterator) === "function";
94713
94821
  }
94714
94822
  function isAccessoryInfoLike(value) {
94715
94823
  return isRecord(value) && isRecord(value["pairedClients"]) && typeof value["hasAdminPermissions"] === "function";
@@ -8220,7 +8220,7 @@ var RecordingBandSchema = object({
8220
8220
  postBufferSec: number().min(0).optional()
8221
8221
  });
8222
8222
  ({
8223
- preBufferSec: 10,
8223
+ preBufferSec: 15,
8224
8224
  postBufferSec: 30
8225
8225
  }).postBufferSec * 1e3;
8226
8226
  /**
@@ -14294,128 +14294,103 @@ var COCO_TO_MACRO = {
14294
14294
  var AUDIO_MACRO_LABELS = [
14295
14295
  {
14296
14296
  id: "speech",
14297
- name: "Speech",
14298
- icon: "πŸ—£οΈ"
14297
+ name: "Speech"
14299
14298
  },
14300
14299
  {
14301
14300
  id: "scream",
14302
- name: "Scream / Shout",
14303
- icon: "😱"
14301
+ name: "Scream / Shout"
14304
14302
  },
14305
14303
  {
14306
14304
  id: "crying",
14307
- name: "Crying / Baby",
14308
- icon: "😒"
14305
+ name: "Crying / Baby"
14309
14306
  },
14310
14307
  {
14311
14308
  id: "laughter",
14312
- name: "Laughter",
14313
- icon: "πŸ˜‚"
14309
+ name: "Laughter"
14314
14310
  },
14315
14311
  {
14316
14312
  id: "music",
14317
- name: "Music",
14318
- icon: "🎡"
14313
+ name: "Music"
14319
14314
  },
14320
14315
  {
14321
14316
  id: "dog",
14322
- name: "Dog",
14323
- icon: "πŸ•"
14317
+ name: "Dog"
14324
14318
  },
14325
14319
  {
14326
14320
  id: "cat",
14327
- name: "Cat",
14328
- icon: "🐈"
14321
+ name: "Cat"
14329
14322
  },
14330
14323
  {
14331
14324
  id: "bird",
14332
- name: "Bird",
14333
- icon: "🐦"
14325
+ name: "Bird"
14334
14326
  },
14335
14327
  {
14336
14328
  id: "animal",
14337
- name: "Animal (other)",
14338
- icon: "🐾"
14329
+ name: "Animal (other)"
14339
14330
  },
14340
14331
  {
14341
14332
  id: "alarm",
14342
- name: "Alarm / Siren",
14343
- icon: "🚨"
14333
+ name: "Alarm / Siren"
14344
14334
  },
14345
14335
  {
14346
14336
  id: "doorbell",
14347
- name: "Doorbell / Knock",
14348
- icon: "πŸ””"
14337
+ name: "Doorbell / Knock"
14349
14338
  },
14350
14339
  {
14351
14340
  id: "glass_breaking",
14352
- name: "Glass Breaking",
14353
- icon: "πŸ’₯"
14341
+ name: "Glass Breaking"
14354
14342
  },
14355
14343
  {
14356
14344
  id: "gunshot",
14357
- name: "Gunshot / Explosion",
14358
- icon: "πŸ’£"
14345
+ name: "Gunshot / Explosion"
14359
14346
  },
14360
14347
  {
14361
14348
  id: "vehicle",
14362
- name: "Vehicle",
14363
- icon: "πŸš—"
14349
+ name: "Vehicle"
14364
14350
  },
14365
14351
  {
14366
14352
  id: "siren",
14367
- name: "Emergency Siren",
14368
- icon: "πŸš‘"
14353
+ name: "Emergency Siren"
14369
14354
  },
14370
14355
  {
14371
14356
  id: "fire",
14372
- name: "Fire / Smoke",
14373
- icon: "πŸ”₯"
14357
+ name: "Fire / Smoke"
14374
14358
  },
14375
14359
  {
14376
14360
  id: "water",
14377
- name: "Water",
14378
- icon: "πŸ’§"
14361
+ name: "Water"
14379
14362
  },
14380
14363
  {
14381
14364
  id: "wind",
14382
- name: "Wind / Weather",
14383
- icon: "🌬️"
14365
+ name: "Wind / Weather"
14384
14366
  },
14385
14367
  {
14386
14368
  id: "door",
14387
- name: "Door",
14388
- icon: "πŸšͺ"
14369
+ name: "Door"
14389
14370
  },
14390
14371
  {
14391
14372
  id: "footsteps",
14392
- name: "Footsteps",
14393
- icon: "πŸ‘£"
14373
+ name: "Footsteps"
14394
14374
  },
14395
14375
  {
14396
14376
  id: "crowd",
14397
- name: "Crowd / Chatter",
14398
- icon: "πŸ‘₯"
14377
+ name: "Crowd / Chatter"
14399
14378
  },
14400
14379
  {
14401
14380
  id: "telephone",
14402
- name: "Telephone",
14403
- icon: "πŸ“ž"
14381
+ name: "Telephone"
14404
14382
  },
14405
14383
  {
14406
14384
  id: "engine",
14407
- name: "Engine / Motor",
14408
- icon: "βš™οΈ"
14385
+ name: "Engine / Motor"
14409
14386
  },
14410
14387
  {
14411
14388
  id: "tools",
14412
- name: "Tools / Construction",
14413
- icon: "πŸ”¨"
14389
+ name: "Tools / Construction"
14414
14390
  },
14415
14391
  {
14416
14392
  id: "silence",
14417
- name: "Silence",
14418
- icon: "🀫"
14393
+ name: "Silence"
14419
14394
  }
14420
14395
  ];
14421
14396
  var YAMNET_TO_MACRO = {
@@ -16879,7 +16854,7 @@ var TrackEnvelopeSchema = object({
16879
16854
  * `snapshots[]` references β€” megabytes across a page of tracks. `slim`
16880
16855
  * keeps every scalar the list surfaces actually render (ids, class(es),
16881
16856
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16882
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16857
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16883
16858
  * `snapshots` as EMPTY arrays β€” detail views re-fetch the full row via
16884
16859
  * `getTrack`. Mirrors the event-store `projection` convention
16885
16860
  * (`getObjectEvents` et al.).
@@ -17174,6 +17149,35 @@ var TrackSchema = object({
17174
17149
  */
17175
17150
  hasFace: boolean().optional(),
17176
17151
  /**
17152
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding β€” a
17153
+ * face an operator could ASSIGN to an identity.
17154
+ *
17155
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
17156
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
17157
+ * branch, before every gate, and means no more than "a face detector produced
17158
+ * a face detail". This one is stamped at the single moment the gallery row
17159
+ * LANDS β€” after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
17160
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
17161
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
17162
+ * the crop-store drop. Everything between the detector and that insert can
17163
+ * legitimately refuse the face, so a flag written any earlier promises the
17164
+ * operator something to assign and delivers nothing.
17165
+ *
17166
+ * **Independent of recognition.** A face collected but never auto-matched is
17167
+ * still assignable β€” it is in fact the face an operator most wants to reach β€”
17168
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
17169
+ * `subLabel`; this says only that the raw material exists.
17170
+ *
17171
+ * **Set once, never cleared.** A track that produced a gallery row produced
17172
+ * one; deleting the row later is the gallery's business, not this flag's.
17173
+ *
17174
+ * **Absent β‰  false**, the same rule as {@link hasFace}: every row written
17175
+ * before the column omits it, and so does every server that predates the
17176
+ * field. A consumer must test `=== true` and render nothing otherwise β€”
17177
+ * never infer "no assignable face".
17178
+ */
17179
+ hasEmbeddedFace: boolean().optional(),
17180
+ /**
17177
17181
  * This subject CONTAINS a folded rider β€” a person the rider-pairing step
17178
17182
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
17179
17183
  * so the passage is tracked once and as a VEHICLE.
@@ -18523,6 +18527,32 @@ var DetailResultSchema = object({
18523
18527
  /** FRAME-space bbox (already mapped back from crop space). */
18524
18528
  bbox: NativeCropBboxSchema.optional(),
18525
18529
  embedding: string().optional(),
18530
+ /**
18531
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
18532
+ * so an older runner that does not send it degrades to "unmeasurable", which
18533
+ * the consuming gate treats as accept β€” never as reject.
18534
+ */
18535
+ embeddingMagnitude: number().optional(),
18536
+ /**
18537
+ * Model that produced `embedding` β€” the SAME contract `labelModelId` has for
18538
+ * `label`, and for the same reason: the producing node is the only side that
18539
+ * knows which model actually ran, and re-deriving it downstream is exactly
18540
+ * the inference this model exists to forbid.
18541
+ *
18542
+ * Additive and optional, so a runner that predates it degrades to
18543
+ * "unmeasurable" rather than to a wrong answer β€” the consumer falls back to
18544
+ * its previous assumption instead of refusing.
18545
+ *
18546
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
18547
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
18548
+ * with nothing on the wire it took the id from the GALLERY, so the gate
18549
+ * compared the gallery against itself and could never fire. That turned the
18550
+ * one guard protecting the face feature space into a tautology, and it is
18551
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
18552
+ * gallery as the catalog comment predicts β€” it would have scored the new
18553
+ * model's vectors against the old model's samples in one cosine space.
18554
+ */
18555
+ embeddingModelId: string().optional(),
18526
18556
  label: string().optional(),
18527
18557
  /**
18528
18558
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -19933,6 +19963,7 @@ DeviceType.Camera, method(object({
19933
19963
  isBattery: boolean(),
19934
19964
  reason: _enum([
19935
19965
  "disabled",
19966
+ "offline",
19936
19967
  "sleeping",
19937
19968
  "unreachable",
19938
19969
  "waking"
@@ -19978,9 +20009,17 @@ targets: array(object({
19978
20009
  sleeping: boolean(),
19979
20010
  /** Current device state rendered over the cached frame. State images
19980
20011
  * remain authoritative even when their photographic background is
19981
- * old; null means the link must carry a current camera frame. */
20012
+ * old; null means the link must carry a current camera frame.
20013
+ *
20014
+ * **This is the ONLY source a surface may derive an inactive tile
20015
+ * from.** A client that reads a device's `online`/`disabled` flags and
20016
+ * draws its own verdict will disagree with the pixels it is painting
20017
+ * β€” the frame comes from here, and so must the sentence over it
20018
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
20019
+ * state. */
19982
20020
  stateReason: _enum([
19983
20021
  "disabled",
20022
+ "offline",
19984
20023
  "sleeping",
19985
20024
  "unreachable",
19986
20025
  "waking"
@@ -25059,9 +25098,21 @@ var RecordingLocationUsageSchema = object({
25059
25098
  * previously rendered as two identical "disks" with a nonsensical used
25060
25099
  * split β€” hydrate attribution across aliases is arbitrary by nature. */
25061
25100
  locationIds: array(string()).optional(),
25062
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
25101
+ /**
25102
+ * Filesystem root of the physical volume this row accounts β€” the only
25103
+ * operator-legible identity when a location has no `displayName` yet, and
25104
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
25105
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
25106
+ * it, and this schema must keep validating that older provider's payload.
25107
+ */
25108
+ root: string().optional(),
25109
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
25110
+ * the footage's SHARE of the volume, not how full the volume is β€” the disk
25111
+ * also holds everything that is not recordings. Volume fill is
25112
+ * `(totalBytes - availableBytes) / totalBytes`. */
25063
25113
  usedBytes: number(),
25064
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
25114
+ /** Free bytes on the location's volume; null when capacity is unknown
25115
+ * (remote/unstattable β€” the recorder logs the statfs failure with the root). */
25065
25116
  availableBytes: number().nullable(),
25066
25117
  /** Total bytes of the location's volume; null when unknown. */
25067
25118
  totalBytes: number().nullable()
@@ -25073,7 +25124,15 @@ var RecordingStorageUsageSchema = object({
25073
25124
  nodeId: string(),
25074
25125
  totalUsedBytes: number(),
25075
25126
  devices: array(RecordingDeviceUsageSchema),
25076
- locations: array(RecordingLocationUsageSchema)
25127
+ /**
25128
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
25129
+ * of the payload without it: the hub serves this method through a BAKED
25130
+ * router, so a hub whose framework train predates a change to this array
25131
+ * strips it out of an answer a newer recorder happily produced. A UI that
25132
+ * dereferences it unconditionally crashes the whole Storage page over a
25133
+ * missing disk bar.
25134
+ */
25135
+ locations: array(RecordingLocationUsageSchema).optional()
25077
25136
  });
25078
25137
  /**
25079
25138
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -34214,8 +34273,13 @@ Object.freeze({
34214
34273
  "network-access": "ingress",
34215
34274
  "smtp-provider": "email"
34216
34275
  });
34217
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
34276
+ /** Schema defaults β€” an untouched sub-field must author exactly these. */
34277
+ var NC_AUDIO_DEFAULTS = {
34278
+ hitPercent: 60,
34279
+ samplingSeconds: 10
34280
+ };
34218
34281
  new Set(["devices", "classes"]);
34282
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
34219
34283
  /**
34220
34284
  * TimelapseRule β€” the STANDALONE scheduled timelapse producer's rule model.
34221
34285
  *
@@ -34447,6 +34511,39 @@ TimelapseRuleInputSchema.extend({
34447
34511
  createdAt: number(),
34448
34512
  updatedAt: number()
34449
34513
  });
34514
+ Object.freeze(Object.fromEntries([{
34515
+ stepId: "face-embedding",
34516
+ label: "Face recognition model",
34517
+ defaultModelId: "arcface-r100",
34518
+ indexName: "the enrolled face gallery",
34519
+ options: [
34520
+ {
34521
+ id: "arcface-r100",
34522
+ label: "ArcFace (ResNet34)"
34523
+ },
34524
+ {
34525
+ id: "auraface-r100",
34526
+ label: "AuraFace R100"
34527
+ },
34528
+ {
34529
+ id: "inception-resnet-v1",
34530
+ label: "Inception ResNet V1"
34531
+ }
34532
+ ]
34533
+ }, {
34534
+ stepId: "clip-embedding",
34535
+ label: "Semantic search model",
34536
+ defaultModelId: "mobileclip-s1",
34537
+ indexName: "the object semantic-search index",
34538
+ options: [{
34539
+ id: "mobileclip-s1",
34540
+ label: "MobileCLIP S1"
34541
+ }, {
34542
+ id: "mobileclip-s2",
34543
+ label: "MobileCLIP S2"
34544
+ }]
34545
+ }].map((s) => [s.stepId, s.defaultModelId])));
34546
+ string().min(1);
34450
34547
  object({
34451
34548
  /**
34452
34549
  * Fraction of the box's own size added on EACH side before cutting.
@@ -34467,10 +34564,21 @@ object({
34467
34564
  */
34468
34565
  square: boolean()
34469
34566
  });
34470
- ({
34567
+ /**
34568
+ * The convention in force when nobody has configured one β€” byte-for-byte the
34569
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
34570
+ */
34571
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
34471
34572
  paddingRatio: .15,
34472
34573
  square: false
34473
- }).paddingRatio;
34574
+ };
34575
+ Object.freeze({
34576
+ x: 0,
34577
+ y: 0,
34578
+ w: 1,
34579
+ h: 1
34580
+ });
34581
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
34474
34582
  /**
34475
34583
  * WHICH delivered frames the decode worker retains a native copy of.
34476
34584
  *
@@ -94235,7 +94343,7 @@ function isConnectionLike(value) {
94235
94343
  return isRecord$1(value) && typeof value["hasEventNotifications"] === "function";
94236
94344
  }
94237
94345
  function isIterable$1(value) {
94238
- return isRecord$1(value) && typeof value[Symbol.iterator] === "function";
94346
+ return isRecord$1(value) && typeof Reflect.get(value, Symbol.iterator) === "function";
94239
94347
  }
94240
94348
  /** `accessory._server.httpServer.connections`, or null at any missing hop. */
94241
94349
  function readConnections$1(accessory) {
@@ -94697,7 +94805,7 @@ function isRecord(value) {
94697
94805
  return typeof value === "object" && value !== null;
94698
94806
  }
94699
94807
  function isIterable(value) {
94700
- return isRecord(value) && typeof value[Symbol.iterator] === "function";
94808
+ return isRecord(value) && typeof Reflect.get(value, Symbol.iterator) === "function";
94701
94809
  }
94702
94810
  function isAccessoryInfoLike(value) {
94703
94811
  return isRecord(value) && isRecord(value["pairedClients"]) && typeof value["hasAdminPermissions"] === "function";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-export-hap",
3
- "version": "1.2.33",
3
+ "version": "1.2.35",
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",