@camstack/addon-auth 1.2.26 → 1.2.28

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.
@@ -7680,7 +7680,7 @@ var RecordingBandSchema = object({
7680
7680
  postBufferSec: number().min(0).optional()
7681
7681
  });
7682
7682
  ({
7683
- preBufferSec: 10,
7683
+ preBufferSec: 15,
7684
7684
  postBufferSec: 30
7685
7685
  }).postBufferSec * 1e3;
7686
7686
  /**
@@ -13665,128 +13665,103 @@ var COCO_TO_MACRO = {
13665
13665
  var AUDIO_MACRO_LABELS = [
13666
13666
  {
13667
13667
  id: "speech",
13668
- name: "Speech",
13669
- icon: "🗣️"
13668
+ name: "Speech"
13670
13669
  },
13671
13670
  {
13672
13671
  id: "scream",
13673
- name: "Scream / Shout",
13674
- icon: "😱"
13672
+ name: "Scream / Shout"
13675
13673
  },
13676
13674
  {
13677
13675
  id: "crying",
13678
- name: "Crying / Baby",
13679
- icon: "😢"
13676
+ name: "Crying / Baby"
13680
13677
  },
13681
13678
  {
13682
13679
  id: "laughter",
13683
- name: "Laughter",
13684
- icon: "😂"
13680
+ name: "Laughter"
13685
13681
  },
13686
13682
  {
13687
13683
  id: "music",
13688
- name: "Music",
13689
- icon: "🎵"
13684
+ name: "Music"
13690
13685
  },
13691
13686
  {
13692
13687
  id: "dog",
13693
- name: "Dog",
13694
- icon: "🐕"
13688
+ name: "Dog"
13695
13689
  },
13696
13690
  {
13697
13691
  id: "cat",
13698
- name: "Cat",
13699
- icon: "🐈"
13692
+ name: "Cat"
13700
13693
  },
13701
13694
  {
13702
13695
  id: "bird",
13703
- name: "Bird",
13704
- icon: "🐦"
13696
+ name: "Bird"
13705
13697
  },
13706
13698
  {
13707
13699
  id: "animal",
13708
- name: "Animal (other)",
13709
- icon: "🐾"
13700
+ name: "Animal (other)"
13710
13701
  },
13711
13702
  {
13712
13703
  id: "alarm",
13713
- name: "Alarm / Siren",
13714
- icon: "🚨"
13704
+ name: "Alarm / Siren"
13715
13705
  },
13716
13706
  {
13717
13707
  id: "doorbell",
13718
- name: "Doorbell / Knock",
13719
- icon: "🔔"
13708
+ name: "Doorbell / Knock"
13720
13709
  },
13721
13710
  {
13722
13711
  id: "glass_breaking",
13723
- name: "Glass Breaking",
13724
- icon: "💥"
13712
+ name: "Glass Breaking"
13725
13713
  },
13726
13714
  {
13727
13715
  id: "gunshot",
13728
- name: "Gunshot / Explosion",
13729
- icon: "💣"
13716
+ name: "Gunshot / Explosion"
13730
13717
  },
13731
13718
  {
13732
13719
  id: "vehicle",
13733
- name: "Vehicle",
13734
- icon: "🚗"
13720
+ name: "Vehicle"
13735
13721
  },
13736
13722
  {
13737
13723
  id: "siren",
13738
- name: "Emergency Siren",
13739
- icon: "🚑"
13724
+ name: "Emergency Siren"
13740
13725
  },
13741
13726
  {
13742
13727
  id: "fire",
13743
- name: "Fire / Smoke",
13744
- icon: "🔥"
13728
+ name: "Fire / Smoke"
13745
13729
  },
13746
13730
  {
13747
13731
  id: "water",
13748
- name: "Water",
13749
- icon: "💧"
13732
+ name: "Water"
13750
13733
  },
13751
13734
  {
13752
13735
  id: "wind",
13753
- name: "Wind / Weather",
13754
- icon: "🌬️"
13736
+ name: "Wind / Weather"
13755
13737
  },
13756
13738
  {
13757
13739
  id: "door",
13758
- name: "Door",
13759
- icon: "🚪"
13740
+ name: "Door"
13760
13741
  },
13761
13742
  {
13762
13743
  id: "footsteps",
13763
- name: "Footsteps",
13764
- icon: "👣"
13744
+ name: "Footsteps"
13765
13745
  },
13766
13746
  {
13767
13747
  id: "crowd",
13768
- name: "Crowd / Chatter",
13769
- icon: "👥"
13748
+ name: "Crowd / Chatter"
13770
13749
  },
13771
13750
  {
13772
13751
  id: "telephone",
13773
- name: "Telephone",
13774
- icon: "📞"
13752
+ name: "Telephone"
13775
13753
  },
13776
13754
  {
13777
13755
  id: "engine",
13778
- name: "Engine / Motor",
13779
- icon: "⚙️"
13756
+ name: "Engine / Motor"
13780
13757
  },
13781
13758
  {
13782
13759
  id: "tools",
13783
- name: "Tools / Construction",
13784
- icon: "🔨"
13760
+ name: "Tools / Construction"
13785
13761
  },
13786
13762
  {
13787
13763
  id: "silence",
13788
- name: "Silence",
13789
- icon: "🤫"
13764
+ name: "Silence"
13790
13765
  }
13791
13766
  ];
13792
13767
  var YAMNET_TO_MACRO = {
@@ -16250,7 +16225,7 @@ var TrackEnvelopeSchema = object({
16250
16225
  * `snapshots[]` references — megabytes across a page of tracks. `slim`
16251
16226
  * keeps every scalar the list surfaces actually render (ids, class(es),
16252
16227
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16253
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16228
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16254
16229
  * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16255
16230
  * `getTrack`. Mirrors the event-store `projection` convention
16256
16231
  * (`getObjectEvents` et al.).
@@ -16545,6 +16520,35 @@ var TrackSchema = object({
16545
16520
  */
16546
16521
  hasFace: boolean().optional(),
16547
16522
  /**
16523
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding — a
16524
+ * face an operator could ASSIGN to an identity.
16525
+ *
16526
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
16527
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
16528
+ * branch, before every gate, and means no more than "a face detector produced
16529
+ * a face detail". This one is stamped at the single moment the gallery row
16530
+ * LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
16531
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
16532
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
16533
+ * the crop-store drop. Everything between the detector and that insert can
16534
+ * legitimately refuse the face, so a flag written any earlier promises the
16535
+ * operator something to assign and delivers nothing.
16536
+ *
16537
+ * **Independent of recognition.** A face collected but never auto-matched is
16538
+ * still assignable — it is in fact the face an operator most wants to reach —
16539
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
16540
+ * `subLabel`; this says only that the raw material exists.
16541
+ *
16542
+ * **Set once, never cleared.** A track that produced a gallery row produced
16543
+ * one; deleting the row later is the gallery's business, not this flag's.
16544
+ *
16545
+ * **Absent ≠ false**, the same rule as {@link hasFace}: every row written
16546
+ * before the column omits it, and so does every server that predates the
16547
+ * field. A consumer must test `=== true` and render nothing otherwise —
16548
+ * never infer "no assignable face".
16549
+ */
16550
+ hasEmbeddedFace: boolean().optional(),
16551
+ /**
16548
16552
  * This subject CONTAINS a folded rider — a person the rider-pairing step
16549
16553
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
16550
16554
  * so the passage is tracked once and as a VEHICLE.
@@ -17894,6 +17898,32 @@ var DetailResultSchema = object({
17894
17898
  /** FRAME-space bbox (already mapped back from crop space). */
17895
17899
  bbox: NativeCropBboxSchema.optional(),
17896
17900
  embedding: string().optional(),
17901
+ /**
17902
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
17903
+ * so an older runner that does not send it degrades to "unmeasurable", which
17904
+ * the consuming gate treats as accept — never as reject.
17905
+ */
17906
+ embeddingMagnitude: number().optional(),
17907
+ /**
17908
+ * Model that produced `embedding` — the SAME contract `labelModelId` has for
17909
+ * `label`, and for the same reason: the producing node is the only side that
17910
+ * knows which model actually ran, and re-deriving it downstream is exactly
17911
+ * the inference this model exists to forbid.
17912
+ *
17913
+ * Additive and optional, so a runner that predates it degrades to
17914
+ * "unmeasurable" rather than to a wrong answer — the consumer falls back to
17915
+ * its previous assumption instead of refusing.
17916
+ *
17917
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
17918
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
17919
+ * with nothing on the wire it took the id from the GALLERY, so the gate
17920
+ * compared the gallery against itself and could never fire. That turned the
17921
+ * one guard protecting the face feature space into a tautology, and it is
17922
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
17923
+ * gallery as the catalog comment predicts — it would have scored the new
17924
+ * model's vectors against the old model's samples in one cosine space.
17925
+ */
17926
+ embeddingModelId: string().optional(),
17897
17927
  label: string().optional(),
17898
17928
  /**
17899
17929
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -18769,6 +18799,12 @@ var CameraStatusSchema = object({
18769
18799
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
18770
18800
  fetchedAt: number()
18771
18801
  });
18802
+ var InferenceDeviceExclusionReasonSchema = _enum([
18803
+ "disabled",
18804
+ "unavailable",
18805
+ "cannot-host-camera-root",
18806
+ "accelerator-preferred"
18807
+ ]);
18772
18808
  var NodeInferenceDeviceSchema = object({
18773
18809
  /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
18774
18810
  key: string(),
@@ -18799,7 +18835,17 @@ var NodeInferenceDeviceSchema = object({
18799
18835
  * available per format; this is the stored selection that becomes the
18800
18836
  * default for EVERY camera landing on this accelerator.
18801
18837
  */
18802
- steps: record(string(), DeviceStepConfigSchema).optional()
18838
+ steps: record(string(), DeviceStepConfigSchema).optional(),
18839
+ /**
18840
+ * `null` when the device IS a camera-root candidate on this node; otherwise
18841
+ * the reason the dispatcher drops it. Computed by the SAME
18842
+ * `resolveInferenceDeviceEligibility` the dispatcher runs, so this view can
18843
+ * never disagree with the election — deriving it in the UI from
18844
+ * `enabled`/`available` would silently miss `cannot-host-camera-root` (needs
18845
+ * the node's model catalog) and `accelerator-preferred` (needs the node-wide
18846
+ * "an accelerator is serving" predicate).
18847
+ */
18848
+ exclusion: InferenceDeviceExclusionReasonSchema.nullable()
18803
18849
  });
18804
18850
  var NodeInferenceDevicesSchema = object({
18805
18851
  nodeId: string(),
@@ -19304,6 +19350,7 @@ DeviceType.Camera, method(object({
19304
19350
  isBattery: boolean(),
19305
19351
  reason: _enum([
19306
19352
  "disabled",
19353
+ "offline",
19307
19354
  "sleeping",
19308
19355
  "unreachable",
19309
19356
  "waking"
@@ -19349,9 +19396,17 @@ targets: array(object({
19349
19396
  sleeping: boolean(),
19350
19397
  /** Current device state rendered over the cached frame. State images
19351
19398
  * remain authoritative even when their photographic background is
19352
- * old; null means the link must carry a current camera frame. */
19399
+ * old; null means the link must carry a current camera frame.
19400
+ *
19401
+ * **This is the ONLY source a surface may derive an inactive tile
19402
+ * from.** A client that reads a device's `online`/`disabled` flags and
19403
+ * draws its own verdict will disagree with the pixels it is painting
19404
+ * — the frame comes from here, and so must the sentence over it
19405
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19406
+ * state. */
19353
19407
  stateReason: _enum([
19354
19408
  "disabled",
19409
+ "offline",
19355
19410
  "sleeping",
19356
19411
  "unreachable",
19357
19412
  "waking"
@@ -22565,7 +22620,12 @@ var ListResultSchema = object({
22565
22620
  probedAt: number()
22566
22621
  });
22567
22622
  var PreferredSchema = LocalInterfaceSchema.nullable();
22568
- var GetConnectionEndpointsResultSchema = object({ endpoints: array(object({
22623
+ /**
22624
+ * Candidate base URL for the SDK to race on connect. Order matters —
22625
+ * the SDK should attempt these top-to-bottom with a short per-candidate
22626
+ * timeout (e.g. 1500ms) and cache the winner for the session.
22627
+ */
22628
+ var ConnectionEndpointSchema = object({
22569
22629
  /** Operator-facing label (e.g. "LAN — en0", "Public tunnel"). */
22570
22630
  label: string(),
22571
22631
  /** Fully-formed base URL with scheme + host + port. */
@@ -22608,7 +22668,42 @@ var GetConnectionEndpointsResultSchema = object({ endpoints: array(object({
22608
22668
  * ordering between polls.
22609
22669
  */
22610
22670
  priority: number()
22611
- })).readonly() });
22671
+ });
22672
+ /**
22673
+ * Where the advertised local port came from. Ordered most → least
22674
+ * authoritative, and the whole point of returning it: a client must be able to
22675
+ * tell a FACT about the hub's socket from an echo of its own guess.
22676
+ */
22677
+ var LocalPortSourceEnum = _enum([
22678
+ "server-config",
22679
+ "server-env",
22680
+ "caller-hint",
22681
+ "default"
22682
+ ]);
22683
+ /** The port every LAN/loopback `baseUrl` in the same result was built with. */
22684
+ var AdvertisedLocalPortSchema = object({
22685
+ port: number().int().min(1).max(65535),
22686
+ source: LocalPortSourceEnum
22687
+ });
22688
+ var GetConnectionEndpointsResultSchema = object({
22689
+ endpoints: array(ConnectionEndpointSchema).readonly(),
22690
+ /**
22691
+ * The port the hub built the LAN/loopback URLs with, and where that number
22692
+ * came from.
22693
+ *
22694
+ * Returned rather than merely applied, because "the URL is right" and "the
22695
+ * client can KNOW the URL is right" are different properties. A client that
22696
+ * only sees a corrected URL cannot distinguish a hub that fixed the port from
22697
+ * a hub that echoed the port the client sent, so it cannot decide whether to
22698
+ * race the candidate or discard it. With `source` it can: anything but
22699
+ * `caller-hint` is the hub's own socket.
22700
+ *
22701
+ * Absent on hubs predating this field — a client that finds it missing is
22702
+ * talking to an echoing hub and must degrade exactly as it does for
22703
+ * `caller-hint`.
22704
+ */
22705
+ localPort: AdvertisedLocalPortSchema
22706
+ });
22612
22707
  /**
22613
22708
  * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
22614
22709
  * AUTO (resolved from the candidate ranking at send time); `resolved` reports
@@ -22629,8 +22724,13 @@ var AllowedAddressesSchema = object({
22629
22724
  */
22630
22725
  addresses: array(string()).readonly() });
22631
22726
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
22632
- /** Local hub HTTP port to use in base URLs. */
22633
- port: number().int().min(1).max(65535),
22727
+ /**
22728
+ * LEGACY HINT — do not send from new code. Kept optional so clients
22729
+ * written against the echoing contract keep working; the hub uses it
22730
+ * only when it cannot read its own port, and says so via
22731
+ * `localPort.source === 'caller-hint'`.
22732
+ */
22733
+ port: number().int().min(1).max(65535).optional(),
22634
22734
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
22635
22735
  * candidate. Default `true`. */
22636
22736
  includeLoopback: boolean().optional(),
@@ -33554,7 +33654,6 @@ var NC_AUDIO_DEFAULTS = {
33554
33654
  hitPercent: 60,
33555
33655
  samplingSeconds: 10
33556
33656
  };
33557
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
33558
33657
  new Set(["devices", "classes"]);
33559
33658
  NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
33560
33659
  /**
@@ -33788,6 +33887,39 @@ TimelapseRuleInputSchema.extend({
33788
33887
  createdAt: number(),
33789
33888
  updatedAt: number()
33790
33889
  });
33890
+ Object.freeze(Object.fromEntries([{
33891
+ stepId: "face-embedding",
33892
+ label: "Face recognition model",
33893
+ defaultModelId: "arcface-r100",
33894
+ indexName: "the enrolled face gallery",
33895
+ options: [
33896
+ {
33897
+ id: "arcface-r100",
33898
+ label: "ArcFace (ResNet34)"
33899
+ },
33900
+ {
33901
+ id: "auraface-r100",
33902
+ label: "AuraFace R100"
33903
+ },
33904
+ {
33905
+ id: "inception-resnet-v1",
33906
+ label: "Inception ResNet V1"
33907
+ }
33908
+ ]
33909
+ }, {
33910
+ stepId: "clip-embedding",
33911
+ label: "Semantic search model",
33912
+ defaultModelId: "mobileclip-s1",
33913
+ indexName: "the object semantic-search index",
33914
+ options: [{
33915
+ id: "mobileclip-s1",
33916
+ label: "MobileCLIP S1"
33917
+ }, {
33918
+ id: "mobileclip-s2",
33919
+ label: "MobileCLIP S2"
33920
+ }]
33921
+ }].map((s) => [s.stepId, s.defaultModelId])));
33922
+ string().min(1);
33791
33923
  object({
33792
33924
  /**
33793
33925
  * Fraction of the box's own size added on EACH side before cutting.
@@ -33808,10 +33940,21 @@ object({
33808
33940
  */
33809
33941
  square: boolean()
33810
33942
  });
33811
- ({
33943
+ /**
33944
+ * The convention in force when nobody has configured one — byte-for-byte the
33945
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
33946
+ */
33947
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
33812
33948
  paddingRatio: .15,
33813
33949
  square: false
33814
- }).paddingRatio;
33950
+ };
33951
+ Object.freeze({
33952
+ x: 0,
33953
+ y: 0,
33954
+ w: 1,
33955
+ h: 1
33956
+ });
33957
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
33815
33958
  /**
33816
33959
  * WHICH delivered frames the decode worker retains a native copy of.
33817
33960
  *
@@ -7680,7 +7680,7 @@ var RecordingBandSchema = object({
7680
7680
  postBufferSec: number().min(0).optional()
7681
7681
  });
7682
7682
  ({
7683
- preBufferSec: 10,
7683
+ preBufferSec: 15,
7684
7684
  postBufferSec: 30
7685
7685
  }).postBufferSec * 1e3;
7686
7686
  /**
@@ -13665,128 +13665,103 @@ var COCO_TO_MACRO = {
13665
13665
  var AUDIO_MACRO_LABELS = [
13666
13666
  {
13667
13667
  id: "speech",
13668
- name: "Speech",
13669
- icon: "🗣️"
13668
+ name: "Speech"
13670
13669
  },
13671
13670
  {
13672
13671
  id: "scream",
13673
- name: "Scream / Shout",
13674
- icon: "😱"
13672
+ name: "Scream / Shout"
13675
13673
  },
13676
13674
  {
13677
13675
  id: "crying",
13678
- name: "Crying / Baby",
13679
- icon: "😢"
13676
+ name: "Crying / Baby"
13680
13677
  },
13681
13678
  {
13682
13679
  id: "laughter",
13683
- name: "Laughter",
13684
- icon: "😂"
13680
+ name: "Laughter"
13685
13681
  },
13686
13682
  {
13687
13683
  id: "music",
13688
- name: "Music",
13689
- icon: "🎵"
13684
+ name: "Music"
13690
13685
  },
13691
13686
  {
13692
13687
  id: "dog",
13693
- name: "Dog",
13694
- icon: "🐕"
13688
+ name: "Dog"
13695
13689
  },
13696
13690
  {
13697
13691
  id: "cat",
13698
- name: "Cat",
13699
- icon: "🐈"
13692
+ name: "Cat"
13700
13693
  },
13701
13694
  {
13702
13695
  id: "bird",
13703
- name: "Bird",
13704
- icon: "🐦"
13696
+ name: "Bird"
13705
13697
  },
13706
13698
  {
13707
13699
  id: "animal",
13708
- name: "Animal (other)",
13709
- icon: "🐾"
13700
+ name: "Animal (other)"
13710
13701
  },
13711
13702
  {
13712
13703
  id: "alarm",
13713
- name: "Alarm / Siren",
13714
- icon: "🚨"
13704
+ name: "Alarm / Siren"
13715
13705
  },
13716
13706
  {
13717
13707
  id: "doorbell",
13718
- name: "Doorbell / Knock",
13719
- icon: "🔔"
13708
+ name: "Doorbell / Knock"
13720
13709
  },
13721
13710
  {
13722
13711
  id: "glass_breaking",
13723
- name: "Glass Breaking",
13724
- icon: "💥"
13712
+ name: "Glass Breaking"
13725
13713
  },
13726
13714
  {
13727
13715
  id: "gunshot",
13728
- name: "Gunshot / Explosion",
13729
- icon: "💣"
13716
+ name: "Gunshot / Explosion"
13730
13717
  },
13731
13718
  {
13732
13719
  id: "vehicle",
13733
- name: "Vehicle",
13734
- icon: "🚗"
13720
+ name: "Vehicle"
13735
13721
  },
13736
13722
  {
13737
13723
  id: "siren",
13738
- name: "Emergency Siren",
13739
- icon: "🚑"
13724
+ name: "Emergency Siren"
13740
13725
  },
13741
13726
  {
13742
13727
  id: "fire",
13743
- name: "Fire / Smoke",
13744
- icon: "🔥"
13728
+ name: "Fire / Smoke"
13745
13729
  },
13746
13730
  {
13747
13731
  id: "water",
13748
- name: "Water",
13749
- icon: "💧"
13732
+ name: "Water"
13750
13733
  },
13751
13734
  {
13752
13735
  id: "wind",
13753
- name: "Wind / Weather",
13754
- icon: "🌬️"
13736
+ name: "Wind / Weather"
13755
13737
  },
13756
13738
  {
13757
13739
  id: "door",
13758
- name: "Door",
13759
- icon: "🚪"
13740
+ name: "Door"
13760
13741
  },
13761
13742
  {
13762
13743
  id: "footsteps",
13763
- name: "Footsteps",
13764
- icon: "👣"
13744
+ name: "Footsteps"
13765
13745
  },
13766
13746
  {
13767
13747
  id: "crowd",
13768
- name: "Crowd / Chatter",
13769
- icon: "👥"
13748
+ name: "Crowd / Chatter"
13770
13749
  },
13771
13750
  {
13772
13751
  id: "telephone",
13773
- name: "Telephone",
13774
- icon: "📞"
13752
+ name: "Telephone"
13775
13753
  },
13776
13754
  {
13777
13755
  id: "engine",
13778
- name: "Engine / Motor",
13779
- icon: "⚙️"
13756
+ name: "Engine / Motor"
13780
13757
  },
13781
13758
  {
13782
13759
  id: "tools",
13783
- name: "Tools / Construction",
13784
- icon: "🔨"
13760
+ name: "Tools / Construction"
13785
13761
  },
13786
13762
  {
13787
13763
  id: "silence",
13788
- name: "Silence",
13789
- icon: "🤫"
13764
+ name: "Silence"
13790
13765
  }
13791
13766
  ];
13792
13767
  var YAMNET_TO_MACRO = {
@@ -16250,7 +16225,7 @@ var TrackEnvelopeSchema = object({
16250
16225
  * `snapshots[]` references — megabytes across a page of tracks. `slim`
16251
16226
  * keeps every scalar the list surfaces actually render (ids, class(es),
16252
16227
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16253
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16228
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16254
16229
  * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16255
16230
  * `getTrack`. Mirrors the event-store `projection` convention
16256
16231
  * (`getObjectEvents` et al.).
@@ -16545,6 +16520,35 @@ var TrackSchema = object({
16545
16520
  */
16546
16521
  hasFace: boolean().optional(),
16547
16522
  /**
16523
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding — a
16524
+ * face an operator could ASSIGN to an identity.
16525
+ *
16526
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
16527
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
16528
+ * branch, before every gate, and means no more than "a face detector produced
16529
+ * a face detail". This one is stamped at the single moment the gallery row
16530
+ * LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
16531
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
16532
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
16533
+ * the crop-store drop. Everything between the detector and that insert can
16534
+ * legitimately refuse the face, so a flag written any earlier promises the
16535
+ * operator something to assign and delivers nothing.
16536
+ *
16537
+ * **Independent of recognition.** A face collected but never auto-matched is
16538
+ * still assignable — it is in fact the face an operator most wants to reach —
16539
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
16540
+ * `subLabel`; this says only that the raw material exists.
16541
+ *
16542
+ * **Set once, never cleared.** A track that produced a gallery row produced
16543
+ * one; deleting the row later is the gallery's business, not this flag's.
16544
+ *
16545
+ * **Absent ≠ false**, the same rule as {@link hasFace}: every row written
16546
+ * before the column omits it, and so does every server that predates the
16547
+ * field. A consumer must test `=== true` and render nothing otherwise —
16548
+ * never infer "no assignable face".
16549
+ */
16550
+ hasEmbeddedFace: boolean().optional(),
16551
+ /**
16548
16552
  * This subject CONTAINS a folded rider — a person the rider-pairing step
16549
16553
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
16550
16554
  * so the passage is tracked once and as a VEHICLE.
@@ -17894,6 +17898,32 @@ var DetailResultSchema = object({
17894
17898
  /** FRAME-space bbox (already mapped back from crop space). */
17895
17899
  bbox: NativeCropBboxSchema.optional(),
17896
17900
  embedding: string().optional(),
17901
+ /**
17902
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
17903
+ * so an older runner that does not send it degrades to "unmeasurable", which
17904
+ * the consuming gate treats as accept — never as reject.
17905
+ */
17906
+ embeddingMagnitude: number().optional(),
17907
+ /**
17908
+ * Model that produced `embedding` — the SAME contract `labelModelId` has for
17909
+ * `label`, and for the same reason: the producing node is the only side that
17910
+ * knows which model actually ran, and re-deriving it downstream is exactly
17911
+ * the inference this model exists to forbid.
17912
+ *
17913
+ * Additive and optional, so a runner that predates it degrades to
17914
+ * "unmeasurable" rather than to a wrong answer — the consumer falls back to
17915
+ * its previous assumption instead of refusing.
17916
+ *
17917
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
17918
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
17919
+ * with nothing on the wire it took the id from the GALLERY, so the gate
17920
+ * compared the gallery against itself and could never fire. That turned the
17921
+ * one guard protecting the face feature space into a tautology, and it is
17922
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
17923
+ * gallery as the catalog comment predicts — it would have scored the new
17924
+ * model's vectors against the old model's samples in one cosine space.
17925
+ */
17926
+ embeddingModelId: string().optional(),
17897
17927
  label: string().optional(),
17898
17928
  /**
17899
17929
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -18769,6 +18799,12 @@ var CameraStatusSchema = object({
18769
18799
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
18770
18800
  fetchedAt: number()
18771
18801
  });
18802
+ var InferenceDeviceExclusionReasonSchema = _enum([
18803
+ "disabled",
18804
+ "unavailable",
18805
+ "cannot-host-camera-root",
18806
+ "accelerator-preferred"
18807
+ ]);
18772
18808
  var NodeInferenceDeviceSchema = object({
18773
18809
  /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
18774
18810
  key: string(),
@@ -18799,7 +18835,17 @@ var NodeInferenceDeviceSchema = object({
18799
18835
  * available per format; this is the stored selection that becomes the
18800
18836
  * default for EVERY camera landing on this accelerator.
18801
18837
  */
18802
- steps: record(string(), DeviceStepConfigSchema).optional()
18838
+ steps: record(string(), DeviceStepConfigSchema).optional(),
18839
+ /**
18840
+ * `null` when the device IS a camera-root candidate on this node; otherwise
18841
+ * the reason the dispatcher drops it. Computed by the SAME
18842
+ * `resolveInferenceDeviceEligibility` the dispatcher runs, so this view can
18843
+ * never disagree with the election — deriving it in the UI from
18844
+ * `enabled`/`available` would silently miss `cannot-host-camera-root` (needs
18845
+ * the node's model catalog) and `accelerator-preferred` (needs the node-wide
18846
+ * "an accelerator is serving" predicate).
18847
+ */
18848
+ exclusion: InferenceDeviceExclusionReasonSchema.nullable()
18803
18849
  });
18804
18850
  var NodeInferenceDevicesSchema = object({
18805
18851
  nodeId: string(),
@@ -19304,6 +19350,7 @@ DeviceType.Camera, method(object({
19304
19350
  isBattery: boolean(),
19305
19351
  reason: _enum([
19306
19352
  "disabled",
19353
+ "offline",
19307
19354
  "sleeping",
19308
19355
  "unreachable",
19309
19356
  "waking"
@@ -19349,9 +19396,17 @@ targets: array(object({
19349
19396
  sleeping: boolean(),
19350
19397
  /** Current device state rendered over the cached frame. State images
19351
19398
  * remain authoritative even when their photographic background is
19352
- * old; null means the link must carry a current camera frame. */
19399
+ * old; null means the link must carry a current camera frame.
19400
+ *
19401
+ * **This is the ONLY source a surface may derive an inactive tile
19402
+ * from.** A client that reads a device's `online`/`disabled` flags and
19403
+ * draws its own verdict will disagree with the pixels it is painting
19404
+ * — the frame comes from here, and so must the sentence over it
19405
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19406
+ * state. */
19353
19407
  stateReason: _enum([
19354
19408
  "disabled",
19409
+ "offline",
19355
19410
  "sleeping",
19356
19411
  "unreachable",
19357
19412
  "waking"
@@ -22565,7 +22620,12 @@ var ListResultSchema = object({
22565
22620
  probedAt: number()
22566
22621
  });
22567
22622
  var PreferredSchema = LocalInterfaceSchema.nullable();
22568
- var GetConnectionEndpointsResultSchema = object({ endpoints: array(object({
22623
+ /**
22624
+ * Candidate base URL for the SDK to race on connect. Order matters —
22625
+ * the SDK should attempt these top-to-bottom with a short per-candidate
22626
+ * timeout (e.g. 1500ms) and cache the winner for the session.
22627
+ */
22628
+ var ConnectionEndpointSchema = object({
22569
22629
  /** Operator-facing label (e.g. "LAN — en0", "Public tunnel"). */
22570
22630
  label: string(),
22571
22631
  /** Fully-formed base URL with scheme + host + port. */
@@ -22608,7 +22668,42 @@ var GetConnectionEndpointsResultSchema = object({ endpoints: array(object({
22608
22668
  * ordering between polls.
22609
22669
  */
22610
22670
  priority: number()
22611
- })).readonly() });
22671
+ });
22672
+ /**
22673
+ * Where the advertised local port came from. Ordered most → least
22674
+ * authoritative, and the whole point of returning it: a client must be able to
22675
+ * tell a FACT about the hub's socket from an echo of its own guess.
22676
+ */
22677
+ var LocalPortSourceEnum = _enum([
22678
+ "server-config",
22679
+ "server-env",
22680
+ "caller-hint",
22681
+ "default"
22682
+ ]);
22683
+ /** The port every LAN/loopback `baseUrl` in the same result was built with. */
22684
+ var AdvertisedLocalPortSchema = object({
22685
+ port: number().int().min(1).max(65535),
22686
+ source: LocalPortSourceEnum
22687
+ });
22688
+ var GetConnectionEndpointsResultSchema = object({
22689
+ endpoints: array(ConnectionEndpointSchema).readonly(),
22690
+ /**
22691
+ * The port the hub built the LAN/loopback URLs with, and where that number
22692
+ * came from.
22693
+ *
22694
+ * Returned rather than merely applied, because "the URL is right" and "the
22695
+ * client can KNOW the URL is right" are different properties. A client that
22696
+ * only sees a corrected URL cannot distinguish a hub that fixed the port from
22697
+ * a hub that echoed the port the client sent, so it cannot decide whether to
22698
+ * race the candidate or discard it. With `source` it can: anything but
22699
+ * `caller-hint` is the hub's own socket.
22700
+ *
22701
+ * Absent on hubs predating this field — a client that finds it missing is
22702
+ * talking to an echoing hub and must degrade exactly as it does for
22703
+ * `caller-hint`.
22704
+ */
22705
+ localPort: AdvertisedLocalPortSchema
22706
+ });
22612
22707
  /**
22613
22708
  * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
22614
22709
  * AUTO (resolved from the candidate ranking at send time); `resolved` reports
@@ -22629,8 +22724,13 @@ var AllowedAddressesSchema = object({
22629
22724
  */
22630
22725
  addresses: array(string()).readonly() });
22631
22726
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
22632
- /** Local hub HTTP port to use in base URLs. */
22633
- port: number().int().min(1).max(65535),
22727
+ /**
22728
+ * LEGACY HINT — do not send from new code. Kept optional so clients
22729
+ * written against the echoing contract keep working; the hub uses it
22730
+ * only when it cannot read its own port, and says so via
22731
+ * `localPort.source === 'caller-hint'`.
22732
+ */
22733
+ port: number().int().min(1).max(65535).optional(),
22634
22734
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
22635
22735
  * candidate. Default `true`. */
22636
22736
  includeLoopback: boolean().optional(),
@@ -33554,7 +33654,6 @@ var NC_AUDIO_DEFAULTS = {
33554
33654
  hitPercent: 60,
33555
33655
  samplingSeconds: 10
33556
33656
  };
33557
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
33558
33657
  new Set(["devices", "classes"]);
33559
33658
  NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
33560
33659
  /**
@@ -33788,6 +33887,39 @@ TimelapseRuleInputSchema.extend({
33788
33887
  createdAt: number(),
33789
33888
  updatedAt: number()
33790
33889
  });
33890
+ Object.freeze(Object.fromEntries([{
33891
+ stepId: "face-embedding",
33892
+ label: "Face recognition model",
33893
+ defaultModelId: "arcface-r100",
33894
+ indexName: "the enrolled face gallery",
33895
+ options: [
33896
+ {
33897
+ id: "arcface-r100",
33898
+ label: "ArcFace (ResNet34)"
33899
+ },
33900
+ {
33901
+ id: "auraface-r100",
33902
+ label: "AuraFace R100"
33903
+ },
33904
+ {
33905
+ id: "inception-resnet-v1",
33906
+ label: "Inception ResNet V1"
33907
+ }
33908
+ ]
33909
+ }, {
33910
+ stepId: "clip-embedding",
33911
+ label: "Semantic search model",
33912
+ defaultModelId: "mobileclip-s1",
33913
+ indexName: "the object semantic-search index",
33914
+ options: [{
33915
+ id: "mobileclip-s1",
33916
+ label: "MobileCLIP S1"
33917
+ }, {
33918
+ id: "mobileclip-s2",
33919
+ label: "MobileCLIP S2"
33920
+ }]
33921
+ }].map((s) => [s.stepId, s.defaultModelId])));
33922
+ string().min(1);
33791
33923
  object({
33792
33924
  /**
33793
33925
  * Fraction of the box's own size added on EACH side before cutting.
@@ -33808,10 +33940,21 @@ object({
33808
33940
  */
33809
33941
  square: boolean()
33810
33942
  });
33811
- ({
33943
+ /**
33944
+ * The convention in force when nobody has configured one — byte-for-byte the
33945
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
33946
+ */
33947
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
33812
33948
  paddingRatio: .15,
33813
33949
  square: false
33814
- }).paddingRatio;
33950
+ };
33951
+ Object.freeze({
33952
+ x: 0,
33953
+ y: 0,
33954
+ w: 1,
33955
+ h: 1
33956
+ });
33957
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
33815
33958
  /**
33816
33959
  * WHICH delivered frames the decode worker retains a native copy of.
33817
33960
  *
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../chunk-Cek0wNdY.js");
6
- const require_dist = require("../dist-DwFrw_t5.js");
6
+ const require_dist = require("../dist-Bs-LegcV.js");
7
7
  //#region src/magic-link/auth-magic-link.addon.ts
8
8
  /**
9
9
  * Magic-link authentication addon.
@@ -1,4 +1,4 @@
1
- import { a as loginMethodCapability, c as BaseAddon, i as buildAddonRouteProvider, r as authProviderCapability, s as errMsg, t as addonRoutesCapability } from "../dist-WXZYDzKC.mjs";
1
+ import { a as loginMethodCapability, c as BaseAddon, i as buildAddonRouteProvider, r as authProviderCapability, s as errMsg, t as addonRoutesCapability } from "../dist-Bx_rSXbP.mjs";
2
2
  //#region src/magic-link/auth-magic-link.addon.ts
3
3
  /**
4
4
  * Magic-link authentication addon.
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-Cek0wNdY.js");
6
- const require_dist = require("../dist-DwFrw_t5.js");
6
+ const require_dist = require("../dist-Bs-LegcV.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  node_crypto = require_chunk.__toESM(node_crypto);
9
9
  //#region node_modules/jose/dist/webapi/lib/buffer_utils.js
@@ -1,4 +1,4 @@
1
- import { a as loginMethodCapability, c as BaseAddon, i as buildAddonRouteProvider, r as authProviderCapability, s as errMsg, t as addonRoutesCapability } from "../dist-WXZYDzKC.mjs";
1
+ import { a as loginMethodCapability, c as BaseAddon, i as buildAddonRouteProvider, r as authProviderCapability, s as errMsg, t as addonRoutesCapability } from "../dist-Bx_rSXbP.mjs";
2
2
  import * as crypto$1 from "node:crypto";
3
3
  //#region node_modules/jose/dist/webapi/lib/buffer_utils.js
4
4
  var encoder = new TextEncoder();
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
3
3
  var e = {
4
4
  "@camstack/sdk": {
5
5
  name: "@camstack/sdk",
6
- version: "1.2.25",
6
+ version: "1.2.27",
7
7
  scope: ["default"],
8
8
  loaded: !1,
9
9
  from: "addon_auth_webauthn_widgets",
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.90",
21
+ version: "1.2.95",
22
22
  scope: ["default"],
23
23
  loaded: !1,
24
24
  from: "addon_auth_webauthn_widgets",
@@ -33,7 +33,7 @@ var e = {
33
33
  },
34
34
  "@camstack/ui-library": {
35
35
  name: "@camstack/ui-library",
36
- version: "1.2.62",
36
+ version: "1.2.65",
37
37
  scope: ["default"],
38
38
  loaded: !1,
39
39
  from: "addon_auth_webauthn_widgets",
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-Cek0wNdY.js");
6
- const require_dist = require("../dist-DwFrw_t5.js");
6
+ const require_dist = require("../dist-Bs-LegcV.js");
7
7
  let stream = require("stream");
8
8
  stream = require_chunk.__toESM(stream, 1);
9
9
  let http = require("http");
@@ -1,4 +1,4 @@
1
- import { a as loginMethodCapability, c as BaseAddon, d as number, f as object, l as array, n as addonWidgetsSourceCapability, o as userPasskeysCapability, p as string, u as boolean } from "../dist-WXZYDzKC.mjs";
1
+ import { a as loginMethodCapability, c as BaseAddon, d as number, f as object, l as array, n as addonWidgetsSourceCapability, o as userPasskeysCapability, p as string, u as boolean } from "../dist-Bx_rSXbP.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import Stream from "stream";
4
4
  import http from "http";
@@ -36,7 +36,7 @@ async function r() {
36
36
  }
37
37
  },
38
38
  "@camstack/types": {
39
- version: "1.2.90",
39
+ version: "1.2.95",
40
40
  scope: "default",
41
41
  shareConfig: {
42
42
  singleton: !0,
@@ -45,7 +45,7 @@ async function r() {
45
45
  }
46
46
  },
47
47
  "@camstack/sdk": {
48
- version: "1.2.25",
48
+ version: "1.2.27",
49
49
  scope: "default",
50
50
  shareConfig: {
51
51
  singleton: !0,
@@ -81,7 +81,7 @@ async function r() {
81
81
  }
82
82
  },
83
83
  "@camstack/ui-library": {
84
- version: "1.2.62",
84
+ version: "1.2.65",
85
85
  scope: "default",
86
86
  shareConfig: {
87
87
  singleton: !0,
@@ -30,7 +30,7 @@ async function d(e) {
30
30
  }
31
31
  }
32
32
  async function f() {
33
- return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_auth_webauthn_widgets-CntHiwqk.mjs")).catch((e) => {
33
+ return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_auth_webauthn_widgets-CL_2iH1o.mjs")).catch((e) => {
34
34
  throw l = void 0, e;
35
35
  }), l;
36
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-auth",
3
- "version": "1.2.26",
3
+ "version": "1.2.28",
4
4
  "description": "Authentication bundle — magic-link, OIDC, and WebAuthn/passkey. Multi-entry npm package shipping 3 addons under a single bundle; each addon keeps its own id, capabilities, and runner.",
5
5
  "keywords": [
6
6
  "camstack",