@camstack/addon-provider-reolink 1.2.44 → 1.2.46

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.
Files changed (3) hide show
  1. package/dist/addon.js +167 -59
  2. package/dist/addon.mjs +167 -59
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -7605,7 +7605,7 @@ var RecordingBandSchema = object({
7605
7605
  postBufferSec: number().min(0).optional()
7606
7606
  });
7607
7607
  ({
7608
- preBufferSec: 10,
7608
+ preBufferSec: 15,
7609
7609
  postBufferSec: 30
7610
7610
  }).postBufferSec * 1e3;
7611
7611
  /**
@@ -13995,128 +13995,103 @@ var COCO_TO_MACRO = {
13995
13995
  var AUDIO_MACRO_LABELS = [
13996
13996
  {
13997
13997
  id: "speech",
13998
- name: "Speech",
13999
- icon: "🗣️"
13998
+ name: "Speech"
14000
13999
  },
14001
14000
  {
14002
14001
  id: "scream",
14003
- name: "Scream / Shout",
14004
- icon: "😱"
14002
+ name: "Scream / Shout"
14005
14003
  },
14006
14004
  {
14007
14005
  id: "crying",
14008
- name: "Crying / Baby",
14009
- icon: "😢"
14006
+ name: "Crying / Baby"
14010
14007
  },
14011
14008
  {
14012
14009
  id: "laughter",
14013
- name: "Laughter",
14014
- icon: "😂"
14010
+ name: "Laughter"
14015
14011
  },
14016
14012
  {
14017
14013
  id: "music",
14018
- name: "Music",
14019
- icon: "🎵"
14014
+ name: "Music"
14020
14015
  },
14021
14016
  {
14022
14017
  id: "dog",
14023
- name: "Dog",
14024
- icon: "🐕"
14018
+ name: "Dog"
14025
14019
  },
14026
14020
  {
14027
14021
  id: "cat",
14028
- name: "Cat",
14029
- icon: "🐈"
14022
+ name: "Cat"
14030
14023
  },
14031
14024
  {
14032
14025
  id: "bird",
14033
- name: "Bird",
14034
- icon: "🐦"
14026
+ name: "Bird"
14035
14027
  },
14036
14028
  {
14037
14029
  id: "animal",
14038
- name: "Animal (other)",
14039
- icon: "🐾"
14030
+ name: "Animal (other)"
14040
14031
  },
14041
14032
  {
14042
14033
  id: "alarm",
14043
- name: "Alarm / Siren",
14044
- icon: "🚨"
14034
+ name: "Alarm / Siren"
14045
14035
  },
14046
14036
  {
14047
14037
  id: "doorbell",
14048
- name: "Doorbell / Knock",
14049
- icon: "🔔"
14038
+ name: "Doorbell / Knock"
14050
14039
  },
14051
14040
  {
14052
14041
  id: "glass_breaking",
14053
- name: "Glass Breaking",
14054
- icon: "💥"
14042
+ name: "Glass Breaking"
14055
14043
  },
14056
14044
  {
14057
14045
  id: "gunshot",
14058
- name: "Gunshot / Explosion",
14059
- icon: "💣"
14046
+ name: "Gunshot / Explosion"
14060
14047
  },
14061
14048
  {
14062
14049
  id: "vehicle",
14063
- name: "Vehicle",
14064
- icon: "🚗"
14050
+ name: "Vehicle"
14065
14051
  },
14066
14052
  {
14067
14053
  id: "siren",
14068
- name: "Emergency Siren",
14069
- icon: "🚑"
14054
+ name: "Emergency Siren"
14070
14055
  },
14071
14056
  {
14072
14057
  id: "fire",
14073
- name: "Fire / Smoke",
14074
- icon: "🔥"
14058
+ name: "Fire / Smoke"
14075
14059
  },
14076
14060
  {
14077
14061
  id: "water",
14078
- name: "Water",
14079
- icon: "💧"
14062
+ name: "Water"
14080
14063
  },
14081
14064
  {
14082
14065
  id: "wind",
14083
- name: "Wind / Weather",
14084
- icon: "🌬️"
14066
+ name: "Wind / Weather"
14085
14067
  },
14086
14068
  {
14087
14069
  id: "door",
14088
- name: "Door",
14089
- icon: "🚪"
14070
+ name: "Door"
14090
14071
  },
14091
14072
  {
14092
14073
  id: "footsteps",
14093
- name: "Footsteps",
14094
- icon: "👣"
14074
+ name: "Footsteps"
14095
14075
  },
14096
14076
  {
14097
14077
  id: "crowd",
14098
- name: "Crowd / Chatter",
14099
- icon: "👥"
14078
+ name: "Crowd / Chatter"
14100
14079
  },
14101
14080
  {
14102
14081
  id: "telephone",
14103
- name: "Telephone",
14104
- icon: "📞"
14082
+ name: "Telephone"
14105
14083
  },
14106
14084
  {
14107
14085
  id: "engine",
14108
- name: "Engine / Motor",
14109
- icon: "⚙️"
14086
+ name: "Engine / Motor"
14110
14087
  },
14111
14088
  {
14112
14089
  id: "tools",
14113
- name: "Tools / Construction",
14114
- icon: "🔨"
14090
+ name: "Tools / Construction"
14115
14091
  },
14116
14092
  {
14117
14093
  id: "silence",
14118
- name: "Silence",
14119
- icon: "🤫"
14094
+ name: "Silence"
14120
14095
  }
14121
14096
  ];
14122
14097
  var YAMNET_TO_MACRO = {
@@ -16618,7 +16593,7 @@ var TrackEnvelopeSchema = object({
16618
16593
  * `snapshots[]` references — megabytes across a page of tracks. `slim`
16619
16594
  * keeps every scalar the list surfaces actually render (ids, class(es),
16620
16595
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16621
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16596
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16622
16597
  * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16623
16598
  * `getTrack`. Mirrors the event-store `projection` convention
16624
16599
  * (`getObjectEvents` et al.).
@@ -16913,6 +16888,35 @@ var TrackSchema = object({
16913
16888
  */
16914
16889
  hasFace: boolean().optional(),
16915
16890
  /**
16891
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding — a
16892
+ * face an operator could ASSIGN to an identity.
16893
+ *
16894
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
16895
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
16896
+ * branch, before every gate, and means no more than "a face detector produced
16897
+ * a face detail". This one is stamped at the single moment the gallery row
16898
+ * LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
16899
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
16900
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
16901
+ * the crop-store drop. Everything between the detector and that insert can
16902
+ * legitimately refuse the face, so a flag written any earlier promises the
16903
+ * operator something to assign and delivers nothing.
16904
+ *
16905
+ * **Independent of recognition.** A face collected but never auto-matched is
16906
+ * still assignable — it is in fact the face an operator most wants to reach —
16907
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
16908
+ * `subLabel`; this says only that the raw material exists.
16909
+ *
16910
+ * **Set once, never cleared.** A track that produced a gallery row produced
16911
+ * one; deleting the row later is the gallery's business, not this flag's.
16912
+ *
16913
+ * **Absent ≠ false**, the same rule as {@link hasFace}: every row written
16914
+ * before the column omits it, and so does every server that predates the
16915
+ * field. A consumer must test `=== true` and render nothing otherwise —
16916
+ * never infer "no assignable face".
16917
+ */
16918
+ hasEmbeddedFace: boolean().optional(),
16919
+ /**
16916
16920
  * This subject CONTAINS a folded rider — a person the rider-pairing step
16917
16921
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
16918
16922
  * so the passage is tracked once and as a VEHICLE.
@@ -18302,6 +18306,32 @@ var DetailResultSchema = object({
18302
18306
  /** FRAME-space bbox (already mapped back from crop space). */
18303
18307
  bbox: NativeCropBboxSchema.optional(),
18304
18308
  embedding: string().optional(),
18309
+ /**
18310
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
18311
+ * so an older runner that does not send it degrades to "unmeasurable", which
18312
+ * the consuming gate treats as accept — never as reject.
18313
+ */
18314
+ embeddingMagnitude: number().optional(),
18315
+ /**
18316
+ * Model that produced `embedding` — the SAME contract `labelModelId` has for
18317
+ * `label`, and for the same reason: the producing node is the only side that
18318
+ * knows which model actually ran, and re-deriving it downstream is exactly
18319
+ * the inference this model exists to forbid.
18320
+ *
18321
+ * Additive and optional, so a runner that predates it degrades to
18322
+ * "unmeasurable" rather than to a wrong answer — the consumer falls back to
18323
+ * its previous assumption instead of refusing.
18324
+ *
18325
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
18326
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
18327
+ * with nothing on the wire it took the id from the GALLERY, so the gate
18328
+ * compared the gallery against itself and could never fire. That turned the
18329
+ * one guard protecting the face feature space into a tautology, and it is
18330
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
18331
+ * gallery as the catalog comment predicts — it would have scored the new
18332
+ * model's vectors against the old model's samples in one cosine space.
18333
+ */
18334
+ embeddingModelId: string().optional(),
18305
18335
  label: string().optional(),
18306
18336
  /**
18307
18337
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -19766,6 +19796,7 @@ var snapshotCapability = {
19766
19796
  isBattery: boolean(),
19767
19797
  reason: _enum([
19768
19798
  "disabled",
19799
+ "offline",
19769
19800
  "sleeping",
19770
19801
  "unreachable",
19771
19802
  "waking"
@@ -19855,9 +19886,17 @@ targets: array(object({
19855
19886
  sleeping: boolean(),
19856
19887
  /** Current device state rendered over the cached frame. State images
19857
19888
  * remain authoritative even when their photographic background is
19858
- * old; null means the link must carry a current camera frame. */
19889
+ * old; null means the link must carry a current camera frame.
19890
+ *
19891
+ * **This is the ONLY source a surface may derive an inactive tile
19892
+ * from.** A client that reads a device's `online`/`disabled` flags and
19893
+ * draws its own verdict will disagree with the pixels it is painting
19894
+ * — the frame comes from here, and so must the sentence over it
19895
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19896
+ * state. */
19859
19897
  stateReason: _enum([
19860
19898
  "disabled",
19899
+ "offline",
19861
19900
  "sleeping",
19862
19901
  "unreachable",
19863
19902
  "waking"
@@ -26669,9 +26708,21 @@ var RecordingLocationUsageSchema = object({
26669
26708
  * previously rendered as two identical "disks" with a nonsensical used
26670
26709
  * split — hydrate attribution across aliases is arbitrary by nature. */
26671
26710
  locationIds: array(string()).optional(),
26672
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
26711
+ /**
26712
+ * Filesystem root of the physical volume this row accounts — the only
26713
+ * operator-legible identity when a location has no `displayName` yet, and
26714
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
26715
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
26716
+ * it, and this schema must keep validating that older provider's payload.
26717
+ */
26718
+ root: string().optional(),
26719
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
26720
+ * the footage's SHARE of the volume, not how full the volume is — the disk
26721
+ * also holds everything that is not recordings. Volume fill is
26722
+ * `(totalBytes - availableBytes) / totalBytes`. */
26673
26723
  usedBytes: number(),
26674
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
26724
+ /** Free bytes on the location's volume; null when capacity is unknown
26725
+ * (remote/unstattable — the recorder logs the statfs failure with the root). */
26675
26726
  availableBytes: number().nullable(),
26676
26727
  /** Total bytes of the location's volume; null when unknown. */
26677
26728
  totalBytes: number().nullable()
@@ -26683,7 +26734,15 @@ var RecordingStorageUsageSchema = object({
26683
26734
  nodeId: string(),
26684
26735
  totalUsedBytes: number(),
26685
26736
  devices: array(RecordingDeviceUsageSchema),
26686
- locations: array(RecordingLocationUsageSchema)
26737
+ /**
26738
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
26739
+ * of the payload without it: the hub serves this method through a BAKED
26740
+ * router, so a hub whose framework train predates a change to this array
26741
+ * strips it out of an answer a newer recorder happily produced. A UI that
26742
+ * dereferences it unconditionally crashes the whole Storage page over a
26743
+ * missing disk bar.
26744
+ */
26745
+ locations: array(RecordingLocationUsageSchema).optional()
26687
26746
  });
26688
26747
  /**
26689
26748
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -37746,8 +37805,13 @@ Object.freeze({
37746
37805
  "network-access": "ingress",
37747
37806
  "smtp-provider": "email"
37748
37807
  });
37749
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
37808
+ /** Schema defaults an untouched sub-field must author exactly these. */
37809
+ var NC_AUDIO_DEFAULTS = {
37810
+ hitPercent: 60,
37811
+ samplingSeconds: 10
37812
+ };
37750
37813
  new Set(["devices", "classes"]);
37814
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
37751
37815
  /**
37752
37816
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
37753
37817
  *
@@ -37979,6 +38043,39 @@ TimelapseRuleInputSchema.extend({
37979
38043
  createdAt: number(),
37980
38044
  updatedAt: number()
37981
38045
  });
38046
+ Object.freeze(Object.fromEntries([{
38047
+ stepId: "face-embedding",
38048
+ label: "Face recognition model",
38049
+ defaultModelId: "arcface-r100",
38050
+ indexName: "the enrolled face gallery",
38051
+ options: [
38052
+ {
38053
+ id: "arcface-r100",
38054
+ label: "ArcFace (ResNet34)"
38055
+ },
38056
+ {
38057
+ id: "auraface-r100",
38058
+ label: "AuraFace R100"
38059
+ },
38060
+ {
38061
+ id: "inception-resnet-v1",
38062
+ label: "Inception ResNet V1"
38063
+ }
38064
+ ]
38065
+ }, {
38066
+ stepId: "clip-embedding",
38067
+ label: "Semantic search model",
38068
+ defaultModelId: "mobileclip-s1",
38069
+ indexName: "the object semantic-search index",
38070
+ options: [{
38071
+ id: "mobileclip-s1",
38072
+ label: "MobileCLIP S1"
38073
+ }, {
38074
+ id: "mobileclip-s2",
38075
+ label: "MobileCLIP S2"
38076
+ }]
38077
+ }].map((s) => [s.stepId, s.defaultModelId])));
38078
+ string().min(1);
37982
38079
  object({
37983
38080
  /**
37984
38081
  * Fraction of the box's own size added on EACH side before cutting.
@@ -37999,10 +38096,21 @@ object({
37999
38096
  */
38000
38097
  square: boolean()
38001
38098
  });
38002
- ({
38099
+ /**
38100
+ * The convention in force when nobody has configured one — byte-for-byte the
38101
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
38102
+ */
38103
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
38003
38104
  paddingRatio: .15,
38004
38105
  square: false
38005
- }).paddingRatio;
38106
+ };
38107
+ Object.freeze({
38108
+ x: 0,
38109
+ y: 0,
38110
+ w: 1,
38111
+ h: 1
38112
+ });
38113
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
38006
38114
  /**
38007
38115
  * WHICH delivered frames the decode worker retains a native copy of.
38008
38116
  *
package/dist/addon.mjs CHANGED
@@ -7600,7 +7600,7 @@ var RecordingBandSchema = object({
7600
7600
  postBufferSec: number().min(0).optional()
7601
7601
  });
7602
7602
  ({
7603
- preBufferSec: 10,
7603
+ preBufferSec: 15,
7604
7604
  postBufferSec: 30
7605
7605
  }).postBufferSec * 1e3;
7606
7606
  /**
@@ -13990,128 +13990,103 @@ var COCO_TO_MACRO = {
13990
13990
  var AUDIO_MACRO_LABELS = [
13991
13991
  {
13992
13992
  id: "speech",
13993
- name: "Speech",
13994
- icon: "🗣️"
13993
+ name: "Speech"
13995
13994
  },
13996
13995
  {
13997
13996
  id: "scream",
13998
- name: "Scream / Shout",
13999
- icon: "😱"
13997
+ name: "Scream / Shout"
14000
13998
  },
14001
13999
  {
14002
14000
  id: "crying",
14003
- name: "Crying / Baby",
14004
- icon: "😢"
14001
+ name: "Crying / Baby"
14005
14002
  },
14006
14003
  {
14007
14004
  id: "laughter",
14008
- name: "Laughter",
14009
- icon: "😂"
14005
+ name: "Laughter"
14010
14006
  },
14011
14007
  {
14012
14008
  id: "music",
14013
- name: "Music",
14014
- icon: "🎵"
14009
+ name: "Music"
14015
14010
  },
14016
14011
  {
14017
14012
  id: "dog",
14018
- name: "Dog",
14019
- icon: "🐕"
14013
+ name: "Dog"
14020
14014
  },
14021
14015
  {
14022
14016
  id: "cat",
14023
- name: "Cat",
14024
- icon: "🐈"
14017
+ name: "Cat"
14025
14018
  },
14026
14019
  {
14027
14020
  id: "bird",
14028
- name: "Bird",
14029
- icon: "🐦"
14021
+ name: "Bird"
14030
14022
  },
14031
14023
  {
14032
14024
  id: "animal",
14033
- name: "Animal (other)",
14034
- icon: "🐾"
14025
+ name: "Animal (other)"
14035
14026
  },
14036
14027
  {
14037
14028
  id: "alarm",
14038
- name: "Alarm / Siren",
14039
- icon: "🚨"
14029
+ name: "Alarm / Siren"
14040
14030
  },
14041
14031
  {
14042
14032
  id: "doorbell",
14043
- name: "Doorbell / Knock",
14044
- icon: "🔔"
14033
+ name: "Doorbell / Knock"
14045
14034
  },
14046
14035
  {
14047
14036
  id: "glass_breaking",
14048
- name: "Glass Breaking",
14049
- icon: "💥"
14037
+ name: "Glass Breaking"
14050
14038
  },
14051
14039
  {
14052
14040
  id: "gunshot",
14053
- name: "Gunshot / Explosion",
14054
- icon: "💣"
14041
+ name: "Gunshot / Explosion"
14055
14042
  },
14056
14043
  {
14057
14044
  id: "vehicle",
14058
- name: "Vehicle",
14059
- icon: "🚗"
14045
+ name: "Vehicle"
14060
14046
  },
14061
14047
  {
14062
14048
  id: "siren",
14063
- name: "Emergency Siren",
14064
- icon: "🚑"
14049
+ name: "Emergency Siren"
14065
14050
  },
14066
14051
  {
14067
14052
  id: "fire",
14068
- name: "Fire / Smoke",
14069
- icon: "🔥"
14053
+ name: "Fire / Smoke"
14070
14054
  },
14071
14055
  {
14072
14056
  id: "water",
14073
- name: "Water",
14074
- icon: "💧"
14057
+ name: "Water"
14075
14058
  },
14076
14059
  {
14077
14060
  id: "wind",
14078
- name: "Wind / Weather",
14079
- icon: "🌬️"
14061
+ name: "Wind / Weather"
14080
14062
  },
14081
14063
  {
14082
14064
  id: "door",
14083
- name: "Door",
14084
- icon: "🚪"
14065
+ name: "Door"
14085
14066
  },
14086
14067
  {
14087
14068
  id: "footsteps",
14088
- name: "Footsteps",
14089
- icon: "👣"
14069
+ name: "Footsteps"
14090
14070
  },
14091
14071
  {
14092
14072
  id: "crowd",
14093
- name: "Crowd / Chatter",
14094
- icon: "👥"
14073
+ name: "Crowd / Chatter"
14095
14074
  },
14096
14075
  {
14097
14076
  id: "telephone",
14098
- name: "Telephone",
14099
- icon: "📞"
14077
+ name: "Telephone"
14100
14078
  },
14101
14079
  {
14102
14080
  id: "engine",
14103
- name: "Engine / Motor",
14104
- icon: "⚙️"
14081
+ name: "Engine / Motor"
14105
14082
  },
14106
14083
  {
14107
14084
  id: "tools",
14108
- name: "Tools / Construction",
14109
- icon: "🔨"
14085
+ name: "Tools / Construction"
14110
14086
  },
14111
14087
  {
14112
14088
  id: "silence",
14113
- name: "Silence",
14114
- icon: "🤫"
14089
+ name: "Silence"
14115
14090
  }
14116
14091
  ];
14117
14092
  var YAMNET_TO_MACRO = {
@@ -16613,7 +16588,7 @@ var TrackEnvelopeSchema = object({
16613
16588
  * `snapshots[]` references — megabytes across a page of tracks. `slim`
16614
16589
  * keeps every scalar the list surfaces actually render (ids, class(es),
16615
16590
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16616
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16591
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16617
16592
  * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16618
16593
  * `getTrack`. Mirrors the event-store `projection` convention
16619
16594
  * (`getObjectEvents` et al.).
@@ -16908,6 +16883,35 @@ var TrackSchema = object({
16908
16883
  */
16909
16884
  hasFace: boolean().optional(),
16910
16885
  /**
16886
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding — a
16887
+ * face an operator could ASSIGN to an identity.
16888
+ *
16889
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
16890
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
16891
+ * branch, before every gate, and means no more than "a face detector produced
16892
+ * a face detail". This one is stamped at the single moment the gallery row
16893
+ * LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
16894
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
16895
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
16896
+ * the crop-store drop. Everything between the detector and that insert can
16897
+ * legitimately refuse the face, so a flag written any earlier promises the
16898
+ * operator something to assign and delivers nothing.
16899
+ *
16900
+ * **Independent of recognition.** A face collected but never auto-matched is
16901
+ * still assignable — it is in fact the face an operator most wants to reach —
16902
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
16903
+ * `subLabel`; this says only that the raw material exists.
16904
+ *
16905
+ * **Set once, never cleared.** A track that produced a gallery row produced
16906
+ * one; deleting the row later is the gallery's business, not this flag's.
16907
+ *
16908
+ * **Absent ≠ false**, the same rule as {@link hasFace}: every row written
16909
+ * before the column omits it, and so does every server that predates the
16910
+ * field. A consumer must test `=== true` and render nothing otherwise —
16911
+ * never infer "no assignable face".
16912
+ */
16913
+ hasEmbeddedFace: boolean().optional(),
16914
+ /**
16911
16915
  * This subject CONTAINS a folded rider — a person the rider-pairing step
16912
16916
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
16913
16917
  * so the passage is tracked once and as a VEHICLE.
@@ -18297,6 +18301,32 @@ var DetailResultSchema = object({
18297
18301
  /** FRAME-space bbox (already mapped back from crop space). */
18298
18302
  bbox: NativeCropBboxSchema.optional(),
18299
18303
  embedding: string().optional(),
18304
+ /**
18305
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
18306
+ * so an older runner that does not send it degrades to "unmeasurable", which
18307
+ * the consuming gate treats as accept — never as reject.
18308
+ */
18309
+ embeddingMagnitude: number().optional(),
18310
+ /**
18311
+ * Model that produced `embedding` — the SAME contract `labelModelId` has for
18312
+ * `label`, and for the same reason: the producing node is the only side that
18313
+ * knows which model actually ran, and re-deriving it downstream is exactly
18314
+ * the inference this model exists to forbid.
18315
+ *
18316
+ * Additive and optional, so a runner that predates it degrades to
18317
+ * "unmeasurable" rather than to a wrong answer — the consumer falls back to
18318
+ * its previous assumption instead of refusing.
18319
+ *
18320
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
18321
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
18322
+ * with nothing on the wire it took the id from the GALLERY, so the gate
18323
+ * compared the gallery against itself and could never fire. That turned the
18324
+ * one guard protecting the face feature space into a tautology, and it is
18325
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
18326
+ * gallery as the catalog comment predicts — it would have scored the new
18327
+ * model's vectors against the old model's samples in one cosine space.
18328
+ */
18329
+ embeddingModelId: string().optional(),
18300
18330
  label: string().optional(),
18301
18331
  /**
18302
18332
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -19761,6 +19791,7 @@ var snapshotCapability = {
19761
19791
  isBattery: boolean(),
19762
19792
  reason: _enum([
19763
19793
  "disabled",
19794
+ "offline",
19764
19795
  "sleeping",
19765
19796
  "unreachable",
19766
19797
  "waking"
@@ -19850,9 +19881,17 @@ targets: array(object({
19850
19881
  sleeping: boolean(),
19851
19882
  /** Current device state rendered over the cached frame. State images
19852
19883
  * remain authoritative even when their photographic background is
19853
- * old; null means the link must carry a current camera frame. */
19884
+ * old; null means the link must carry a current camera frame.
19885
+ *
19886
+ * **This is the ONLY source a surface may derive an inactive tile
19887
+ * from.** A client that reads a device's `online`/`disabled` flags and
19888
+ * draws its own verdict will disagree with the pixels it is painting
19889
+ * — the frame comes from here, and so must the sentence over it
19890
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19891
+ * state. */
19854
19892
  stateReason: _enum([
19855
19893
  "disabled",
19894
+ "offline",
19856
19895
  "sleeping",
19857
19896
  "unreachable",
19858
19897
  "waking"
@@ -26664,9 +26703,21 @@ var RecordingLocationUsageSchema = object({
26664
26703
  * previously rendered as two identical "disks" with a nonsensical used
26665
26704
  * split — hydrate attribution across aliases is arbitrary by nature. */
26666
26705
  locationIds: array(string()).optional(),
26667
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
26706
+ /**
26707
+ * Filesystem root of the physical volume this row accounts — the only
26708
+ * operator-legible identity when a location has no `displayName` yet, and
26709
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
26710
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
26711
+ * it, and this schema must keep validating that older provider's payload.
26712
+ */
26713
+ root: string().optional(),
26714
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
26715
+ * the footage's SHARE of the volume, not how full the volume is — the disk
26716
+ * also holds everything that is not recordings. Volume fill is
26717
+ * `(totalBytes - availableBytes) / totalBytes`. */
26668
26718
  usedBytes: number(),
26669
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
26719
+ /** Free bytes on the location's volume; null when capacity is unknown
26720
+ * (remote/unstattable — the recorder logs the statfs failure with the root). */
26670
26721
  availableBytes: number().nullable(),
26671
26722
  /** Total bytes of the location's volume; null when unknown. */
26672
26723
  totalBytes: number().nullable()
@@ -26678,7 +26729,15 @@ var RecordingStorageUsageSchema = object({
26678
26729
  nodeId: string(),
26679
26730
  totalUsedBytes: number(),
26680
26731
  devices: array(RecordingDeviceUsageSchema),
26681
- locations: array(RecordingLocationUsageSchema)
26732
+ /**
26733
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
26734
+ * of the payload without it: the hub serves this method through a BAKED
26735
+ * router, so a hub whose framework train predates a change to this array
26736
+ * strips it out of an answer a newer recorder happily produced. A UI that
26737
+ * dereferences it unconditionally crashes the whole Storage page over a
26738
+ * missing disk bar.
26739
+ */
26740
+ locations: array(RecordingLocationUsageSchema).optional()
26682
26741
  });
26683
26742
  /**
26684
26743
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -37741,8 +37800,13 @@ Object.freeze({
37741
37800
  "network-access": "ingress",
37742
37801
  "smtp-provider": "email"
37743
37802
  });
37744
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
37803
+ /** Schema defaults an untouched sub-field must author exactly these. */
37804
+ var NC_AUDIO_DEFAULTS = {
37805
+ hitPercent: 60,
37806
+ samplingSeconds: 10
37807
+ };
37745
37808
  new Set(["devices", "classes"]);
37809
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
37746
37810
  /**
37747
37811
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
37748
37812
  *
@@ -37974,6 +38038,39 @@ TimelapseRuleInputSchema.extend({
37974
38038
  createdAt: number(),
37975
38039
  updatedAt: number()
37976
38040
  });
38041
+ Object.freeze(Object.fromEntries([{
38042
+ stepId: "face-embedding",
38043
+ label: "Face recognition model",
38044
+ defaultModelId: "arcface-r100",
38045
+ indexName: "the enrolled face gallery",
38046
+ options: [
38047
+ {
38048
+ id: "arcface-r100",
38049
+ label: "ArcFace (ResNet34)"
38050
+ },
38051
+ {
38052
+ id: "auraface-r100",
38053
+ label: "AuraFace R100"
38054
+ },
38055
+ {
38056
+ id: "inception-resnet-v1",
38057
+ label: "Inception ResNet V1"
38058
+ }
38059
+ ]
38060
+ }, {
38061
+ stepId: "clip-embedding",
38062
+ label: "Semantic search model",
38063
+ defaultModelId: "mobileclip-s1",
38064
+ indexName: "the object semantic-search index",
38065
+ options: [{
38066
+ id: "mobileclip-s1",
38067
+ label: "MobileCLIP S1"
38068
+ }, {
38069
+ id: "mobileclip-s2",
38070
+ label: "MobileCLIP S2"
38071
+ }]
38072
+ }].map((s) => [s.stepId, s.defaultModelId])));
38073
+ string().min(1);
37977
38074
  object({
37978
38075
  /**
37979
38076
  * Fraction of the box's own size added on EACH side before cutting.
@@ -37994,10 +38091,21 @@ object({
37994
38091
  */
37995
38092
  square: boolean()
37996
38093
  });
37997
- ({
38094
+ /**
38095
+ * The convention in force when nobody has configured one — byte-for-byte the
38096
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
38097
+ */
38098
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
37998
38099
  paddingRatio: .15,
37999
38100
  square: false
38000
- }).paddingRatio;
38101
+ };
38102
+ Object.freeze({
38103
+ x: 0,
38104
+ y: 0,
38105
+ w: 1,
38106
+ h: 1
38107
+ });
38108
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
38001
38109
  /**
38002
38110
  * WHICH delivered frames the decode worker retains a native copy of.
38003
38111
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-reolink",
3
- "version": "1.2.44",
3
+ "version": "1.2.46",
4
4
  "description": "Reolink camera device provider addon for CamStack — native Baichuan protocol",
5
5
  "keywords": [
6
6
  "camstack",