@camstack/addon-remote-storage 1.2.22 → 1.2.24

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.
package/dist/s3.addon.js CHANGED
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_shared = require("./shared-BJAy3oN8.js");
5
+ const require_shared = require("./shared-CAxkUIT8.js");
6
6
  let node_stream = require("node:stream");
7
7
  let _aws_sdk_client_s3 = require("@aws-sdk/client-s3");
8
8
  let _aws_sdk_lib_storage = require("@aws-sdk/lib-storage");
package/dist/s3.addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { c as BaseAddon, i as rearmIdleAbort, n as getOptionalBasePath, o as scheduleIdleAbort, s as storageProviderCapability, t as createSessionId } from "./shared-BRLPgCy4.mjs";
1
+ import { c as BaseAddon, i as rearmIdleAbort, n as getOptionalBasePath, o as scheduleIdleAbort, s as storageProviderCapability, t as createSessionId } from "./shared-CMeaUSWI.mjs";
2
2
  import { PassThrough } from "node:stream";
3
3
  import { DeleteObjectCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectsV2Command, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
4
4
  import { Upload } from "@aws-sdk/lib-storage";
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_shared = require("./shared-BJAy3oN8.js");
5
+ const require_shared = require("./shared-CAxkUIT8.js");
6
6
  let ssh2 = require("ssh2");
7
7
  let node_path = require("node:path");
8
8
  node_path = require_shared.__toESM(node_path);
@@ -1,4 +1,4 @@
1
- import { a as safeJoinRemotePath, c as BaseAddon, i as rearmIdleAbort, o as scheduleIdleAbort, r as getRequiredBasePath, s as storageProviderCapability, t as createSessionId } from "./shared-BRLPgCy4.mjs";
1
+ import { a as safeJoinRemotePath, c as BaseAddon, i as rearmIdleAbort, o as scheduleIdleAbort, r as getRequiredBasePath, s as storageProviderCapability, t as createSessionId } from "./shared-CMeaUSWI.mjs";
2
2
  import { Client } from "ssh2";
3
3
  import * as path from "node:path";
4
4
  //#region src/providers/sftp/sftp-config-schema.ts
@@ -7574,7 +7574,7 @@ var RecordingBandSchema = object({
7574
7574
  postBufferSec: number().min(0).optional()
7575
7575
  });
7576
7576
  ({
7577
- preBufferSec: 10,
7577
+ preBufferSec: 15,
7578
7578
  postBufferSec: 30
7579
7579
  }).postBufferSec * 1e3;
7580
7580
  /**
@@ -13513,128 +13513,103 @@ var COCO_TO_MACRO = {
13513
13513
  var AUDIO_MACRO_LABELS = [
13514
13514
  {
13515
13515
  id: "speech",
13516
- name: "Speech",
13517
- icon: "🗣️"
13516
+ name: "Speech"
13518
13517
  },
13519
13518
  {
13520
13519
  id: "scream",
13521
- name: "Scream / Shout",
13522
- icon: "😱"
13520
+ name: "Scream / Shout"
13523
13521
  },
13524
13522
  {
13525
13523
  id: "crying",
13526
- name: "Crying / Baby",
13527
- icon: "😢"
13524
+ name: "Crying / Baby"
13528
13525
  },
13529
13526
  {
13530
13527
  id: "laughter",
13531
- name: "Laughter",
13532
- icon: "😂"
13528
+ name: "Laughter"
13533
13529
  },
13534
13530
  {
13535
13531
  id: "music",
13536
- name: "Music",
13537
- icon: "🎵"
13532
+ name: "Music"
13538
13533
  },
13539
13534
  {
13540
13535
  id: "dog",
13541
- name: "Dog",
13542
- icon: "🐕"
13536
+ name: "Dog"
13543
13537
  },
13544
13538
  {
13545
13539
  id: "cat",
13546
- name: "Cat",
13547
- icon: "🐈"
13540
+ name: "Cat"
13548
13541
  },
13549
13542
  {
13550
13543
  id: "bird",
13551
- name: "Bird",
13552
- icon: "🐦"
13544
+ name: "Bird"
13553
13545
  },
13554
13546
  {
13555
13547
  id: "animal",
13556
- name: "Animal (other)",
13557
- icon: "🐾"
13548
+ name: "Animal (other)"
13558
13549
  },
13559
13550
  {
13560
13551
  id: "alarm",
13561
- name: "Alarm / Siren",
13562
- icon: "🚨"
13552
+ name: "Alarm / Siren"
13563
13553
  },
13564
13554
  {
13565
13555
  id: "doorbell",
13566
- name: "Doorbell / Knock",
13567
- icon: "🔔"
13556
+ name: "Doorbell / Knock"
13568
13557
  },
13569
13558
  {
13570
13559
  id: "glass_breaking",
13571
- name: "Glass Breaking",
13572
- icon: "💥"
13560
+ name: "Glass Breaking"
13573
13561
  },
13574
13562
  {
13575
13563
  id: "gunshot",
13576
- name: "Gunshot / Explosion",
13577
- icon: "💣"
13564
+ name: "Gunshot / Explosion"
13578
13565
  },
13579
13566
  {
13580
13567
  id: "vehicle",
13581
- name: "Vehicle",
13582
- icon: "🚗"
13568
+ name: "Vehicle"
13583
13569
  },
13584
13570
  {
13585
13571
  id: "siren",
13586
- name: "Emergency Siren",
13587
- icon: "🚑"
13572
+ name: "Emergency Siren"
13588
13573
  },
13589
13574
  {
13590
13575
  id: "fire",
13591
- name: "Fire / Smoke",
13592
- icon: "🔥"
13576
+ name: "Fire / Smoke"
13593
13577
  },
13594
13578
  {
13595
13579
  id: "water",
13596
- name: "Water",
13597
- icon: "💧"
13580
+ name: "Water"
13598
13581
  },
13599
13582
  {
13600
13583
  id: "wind",
13601
- name: "Wind / Weather",
13602
- icon: "🌬️"
13584
+ name: "Wind / Weather"
13603
13585
  },
13604
13586
  {
13605
13587
  id: "door",
13606
- name: "Door",
13607
- icon: "🚪"
13588
+ name: "Door"
13608
13589
  },
13609
13590
  {
13610
13591
  id: "footsteps",
13611
- name: "Footsteps",
13612
- icon: "👣"
13592
+ name: "Footsteps"
13613
13593
  },
13614
13594
  {
13615
13595
  id: "crowd",
13616
- name: "Crowd / Chatter",
13617
- icon: "👥"
13596
+ name: "Crowd / Chatter"
13618
13597
  },
13619
13598
  {
13620
13599
  id: "telephone",
13621
- name: "Telephone",
13622
- icon: "📞"
13600
+ name: "Telephone"
13623
13601
  },
13624
13602
  {
13625
13603
  id: "engine",
13626
- name: "Engine / Motor",
13627
- icon: "⚙️"
13604
+ name: "Engine / Motor"
13628
13605
  },
13629
13606
  {
13630
13607
  id: "tools",
13631
- name: "Tools / Construction",
13632
- icon: "🔨"
13608
+ name: "Tools / Construction"
13633
13609
  },
13634
13610
  {
13635
13611
  id: "silence",
13636
- name: "Silence",
13637
- icon: "🤫"
13612
+ name: "Silence"
13638
13613
  }
13639
13614
  ];
13640
13615
  var YAMNET_TO_MACRO = {
@@ -16098,7 +16073,7 @@ var TrackEnvelopeSchema = object({
16098
16073
  * `snapshots[]` references — megabytes across a page of tracks. `slim`
16099
16074
  * keeps every scalar the list surfaces actually render (ids, class(es),
16100
16075
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16101
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16076
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16102
16077
  * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16103
16078
  * `getTrack`. Mirrors the event-store `projection` convention
16104
16079
  * (`getObjectEvents` et al.).
@@ -16393,6 +16368,35 @@ var TrackSchema = object({
16393
16368
  */
16394
16369
  hasFace: boolean().optional(),
16395
16370
  /**
16371
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding — a
16372
+ * face an operator could ASSIGN to an identity.
16373
+ *
16374
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
16375
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
16376
+ * branch, before every gate, and means no more than "a face detector produced
16377
+ * a face detail". This one is stamped at the single moment the gallery row
16378
+ * LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
16379
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
16380
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
16381
+ * the crop-store drop. Everything between the detector and that insert can
16382
+ * legitimately refuse the face, so a flag written any earlier promises the
16383
+ * operator something to assign and delivers nothing.
16384
+ *
16385
+ * **Independent of recognition.** A face collected but never auto-matched is
16386
+ * still assignable — it is in fact the face an operator most wants to reach —
16387
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
16388
+ * `subLabel`; this says only that the raw material exists.
16389
+ *
16390
+ * **Set once, never cleared.** A track that produced a gallery row produced
16391
+ * one; deleting the row later is the gallery's business, not this flag's.
16392
+ *
16393
+ * **Absent ≠ false**, the same rule as {@link hasFace}: every row written
16394
+ * before the column omits it, and so does every server that predates the
16395
+ * field. A consumer must test `=== true` and render nothing otherwise —
16396
+ * never infer "no assignable face".
16397
+ */
16398
+ hasEmbeddedFace: boolean().optional(),
16399
+ /**
16396
16400
  * This subject CONTAINS a folded rider — a person the rider-pairing step
16397
16401
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
16398
16402
  * so the passage is tracked once and as a VEHICLE.
@@ -17742,6 +17746,32 @@ var DetailResultSchema = object({
17742
17746
  /** FRAME-space bbox (already mapped back from crop space). */
17743
17747
  bbox: NativeCropBboxSchema.optional(),
17744
17748
  embedding: string().optional(),
17749
+ /**
17750
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
17751
+ * so an older runner that does not send it degrades to "unmeasurable", which
17752
+ * the consuming gate treats as accept — never as reject.
17753
+ */
17754
+ embeddingMagnitude: number().optional(),
17755
+ /**
17756
+ * Model that produced `embedding` — the SAME contract `labelModelId` has for
17757
+ * `label`, and for the same reason: the producing node is the only side that
17758
+ * knows which model actually ran, and re-deriving it downstream is exactly
17759
+ * the inference this model exists to forbid.
17760
+ *
17761
+ * Additive and optional, so a runner that predates it degrades to
17762
+ * "unmeasurable" rather than to a wrong answer — the consumer falls back to
17763
+ * its previous assumption instead of refusing.
17764
+ *
17765
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
17766
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
17767
+ * with nothing on the wire it took the id from the GALLERY, so the gate
17768
+ * compared the gallery against itself and could never fire. That turned the
17769
+ * one guard protecting the face feature space into a tautology, and it is
17770
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
17771
+ * gallery as the catalog comment predicts — it would have scored the new
17772
+ * model's vectors against the old model's samples in one cosine space.
17773
+ */
17774
+ embeddingModelId: string().optional(),
17745
17775
  label: string().optional(),
17746
17776
  /**
17747
17777
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -18617,6 +18647,12 @@ var CameraStatusSchema = object({
18617
18647
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
18618
18648
  fetchedAt: number()
18619
18649
  });
18650
+ var InferenceDeviceExclusionReasonSchema = _enum([
18651
+ "disabled",
18652
+ "unavailable",
18653
+ "cannot-host-camera-root",
18654
+ "accelerator-preferred"
18655
+ ]);
18620
18656
  var NodeInferenceDeviceSchema = object({
18621
18657
  /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
18622
18658
  key: string(),
@@ -18647,7 +18683,17 @@ var NodeInferenceDeviceSchema = object({
18647
18683
  * available per format; this is the stored selection that becomes the
18648
18684
  * default for EVERY camera landing on this accelerator.
18649
18685
  */
18650
- steps: record(string(), DeviceStepConfigSchema).optional()
18686
+ steps: record(string(), DeviceStepConfigSchema).optional(),
18687
+ /**
18688
+ * `null` when the device IS a camera-root candidate on this node; otherwise
18689
+ * the reason the dispatcher drops it. Computed by the SAME
18690
+ * `resolveInferenceDeviceEligibility` the dispatcher runs, so this view can
18691
+ * never disagree with the election — deriving it in the UI from
18692
+ * `enabled`/`available` would silently miss `cannot-host-camera-root` (needs
18693
+ * the node's model catalog) and `accelerator-preferred` (needs the node-wide
18694
+ * "an accelerator is serving" predicate).
18695
+ */
18696
+ exclusion: InferenceDeviceExclusionReasonSchema.nullable()
18651
18697
  });
18652
18698
  var NodeInferenceDevicesSchema = object({
18653
18699
  nodeId: string(),
@@ -19152,6 +19198,7 @@ DeviceType.Camera, method(object({
19152
19198
  isBattery: boolean(),
19153
19199
  reason: _enum([
19154
19200
  "disabled",
19201
+ "offline",
19155
19202
  "sleeping",
19156
19203
  "unreachable",
19157
19204
  "waking"
@@ -19197,9 +19244,17 @@ targets: array(object({
19197
19244
  sleeping: boolean(),
19198
19245
  /** Current device state rendered over the cached frame. State images
19199
19246
  * remain authoritative even when their photographic background is
19200
- * old; null means the link must carry a current camera frame. */
19247
+ * old; null means the link must carry a current camera frame.
19248
+ *
19249
+ * **This is the ONLY source a surface may derive an inactive tile
19250
+ * from.** A client that reads a device's `online`/`disabled` flags and
19251
+ * draws its own verdict will disagree with the pixels it is painting
19252
+ * — the frame comes from here, and so must the sentence over it
19253
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19254
+ * state. */
19201
19255
  stateReason: _enum([
19202
19256
  "disabled",
19257
+ "offline",
19203
19258
  "sleeping",
19204
19259
  "unreachable",
19205
19260
  "waking"
@@ -22441,7 +22496,12 @@ var ListResultSchema = object({
22441
22496
  probedAt: number()
22442
22497
  });
22443
22498
  var PreferredSchema = LocalInterfaceSchema.nullable();
22444
- var GetConnectionEndpointsResultSchema = object({ endpoints: array(object({
22499
+ /**
22500
+ * Candidate base URL for the SDK to race on connect. Order matters —
22501
+ * the SDK should attempt these top-to-bottom with a short per-candidate
22502
+ * timeout (e.g. 1500ms) and cache the winner for the session.
22503
+ */
22504
+ var ConnectionEndpointSchema = object({
22445
22505
  /** Operator-facing label (e.g. "LAN — en0", "Public tunnel"). */
22446
22506
  label: string(),
22447
22507
  /** Fully-formed base URL with scheme + host + port. */
@@ -22484,7 +22544,42 @@ var GetConnectionEndpointsResultSchema = object({ endpoints: array(object({
22484
22544
  * ordering between polls.
22485
22545
  */
22486
22546
  priority: number()
22487
- })).readonly() });
22547
+ });
22548
+ /**
22549
+ * Where the advertised local port came from. Ordered most → least
22550
+ * authoritative, and the whole point of returning it: a client must be able to
22551
+ * tell a FACT about the hub's socket from an echo of its own guess.
22552
+ */
22553
+ var LocalPortSourceEnum = _enum([
22554
+ "server-config",
22555
+ "server-env",
22556
+ "caller-hint",
22557
+ "default"
22558
+ ]);
22559
+ /** The port every LAN/loopback `baseUrl` in the same result was built with. */
22560
+ var AdvertisedLocalPortSchema = object({
22561
+ port: number().int().min(1).max(65535),
22562
+ source: LocalPortSourceEnum
22563
+ });
22564
+ var GetConnectionEndpointsResultSchema = object({
22565
+ endpoints: array(ConnectionEndpointSchema).readonly(),
22566
+ /**
22567
+ * The port the hub built the LAN/loopback URLs with, and where that number
22568
+ * came from.
22569
+ *
22570
+ * Returned rather than merely applied, because "the URL is right" and "the
22571
+ * client can KNOW the URL is right" are different properties. A client that
22572
+ * only sees a corrected URL cannot distinguish a hub that fixed the port from
22573
+ * a hub that echoed the port the client sent, so it cannot decide whether to
22574
+ * race the candidate or discard it. With `source` it can: anything but
22575
+ * `caller-hint` is the hub's own socket.
22576
+ *
22577
+ * Absent on hubs predating this field — a client that finds it missing is
22578
+ * talking to an echoing hub and must degrade exactly as it does for
22579
+ * `caller-hint`.
22580
+ */
22581
+ localPort: AdvertisedLocalPortSchema
22582
+ });
22488
22583
  /**
22489
22584
  * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
22490
22585
  * AUTO (resolved from the candidate ranking at send time); `resolved` reports
@@ -22505,8 +22600,13 @@ var AllowedAddressesSchema = object({
22505
22600
  */
22506
22601
  addresses: array(string()).readonly() });
22507
22602
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
22508
- /** Local hub HTTP port to use in base URLs. */
22509
- port: number().int().min(1).max(65535),
22603
+ /**
22604
+ * LEGACY HINT — do not send from new code. Kept optional so clients
22605
+ * written against the echoing contract keep working; the hub uses it
22606
+ * only when it cannot read its own port, and says so via
22607
+ * `localPort.source === 'caller-hint'`.
22608
+ */
22609
+ port: number().int().min(1).max(65535).optional(),
22510
22610
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
22511
22611
  * candidate. Default `true`. */
22512
22612
  includeLoopback: boolean().optional(),
@@ -33430,7 +33530,6 @@ var NC_AUDIO_DEFAULTS = {
33430
33530
  hitPercent: 60,
33431
33531
  samplingSeconds: 10
33432
33532
  };
33433
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
33434
33533
  new Set(["devices", "classes"]);
33435
33534
  NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
33436
33535
  /**
@@ -33664,6 +33763,39 @@ TimelapseRuleInputSchema.extend({
33664
33763
  createdAt: number(),
33665
33764
  updatedAt: number()
33666
33765
  });
33766
+ Object.freeze(Object.fromEntries([{
33767
+ stepId: "face-embedding",
33768
+ label: "Face recognition model",
33769
+ defaultModelId: "arcface-r100",
33770
+ indexName: "the enrolled face gallery",
33771
+ options: [
33772
+ {
33773
+ id: "arcface-r100",
33774
+ label: "ArcFace (ResNet34)"
33775
+ },
33776
+ {
33777
+ id: "auraface-r100",
33778
+ label: "AuraFace R100"
33779
+ },
33780
+ {
33781
+ id: "inception-resnet-v1",
33782
+ label: "Inception ResNet V1"
33783
+ }
33784
+ ]
33785
+ }, {
33786
+ stepId: "clip-embedding",
33787
+ label: "Semantic search model",
33788
+ defaultModelId: "mobileclip-s1",
33789
+ indexName: "the object semantic-search index",
33790
+ options: [{
33791
+ id: "mobileclip-s1",
33792
+ label: "MobileCLIP S1"
33793
+ }, {
33794
+ id: "mobileclip-s2",
33795
+ label: "MobileCLIP S2"
33796
+ }]
33797
+ }].map((s) => [s.stepId, s.defaultModelId])));
33798
+ string().min(1);
33667
33799
  object({
33668
33800
  /**
33669
33801
  * Fraction of the box's own size added on EACH side before cutting.
@@ -33684,10 +33816,21 @@ object({
33684
33816
  */
33685
33817
  square: boolean()
33686
33818
  });
33687
- ({
33819
+ /**
33820
+ * The convention in force when nobody has configured one — byte-for-byte the
33821
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
33822
+ */
33823
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
33688
33824
  paddingRatio: .15,
33689
33825
  square: false
33690
- }).paddingRatio;
33826
+ };
33827
+ Object.freeze({
33828
+ x: 0,
33829
+ y: 0,
33830
+ w: 1,
33831
+ h: 1
33832
+ });
33833
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
33691
33834
  /**
33692
33835
  * WHICH delivered frames the decode worker retains a native copy of.
33693
33836
  *
@@ -7551,7 +7551,7 @@ var RecordingBandSchema = object({
7551
7551
  postBufferSec: number().min(0).optional()
7552
7552
  });
7553
7553
  ({
7554
- preBufferSec: 10,
7554
+ preBufferSec: 15,
7555
7555
  postBufferSec: 30
7556
7556
  }).postBufferSec * 1e3;
7557
7557
  /**
@@ -13490,128 +13490,103 @@ var COCO_TO_MACRO = {
13490
13490
  var AUDIO_MACRO_LABELS = [
13491
13491
  {
13492
13492
  id: "speech",
13493
- name: "Speech",
13494
- icon: "🗣️"
13493
+ name: "Speech"
13495
13494
  },
13496
13495
  {
13497
13496
  id: "scream",
13498
- name: "Scream / Shout",
13499
- icon: "😱"
13497
+ name: "Scream / Shout"
13500
13498
  },
13501
13499
  {
13502
13500
  id: "crying",
13503
- name: "Crying / Baby",
13504
- icon: "😢"
13501
+ name: "Crying / Baby"
13505
13502
  },
13506
13503
  {
13507
13504
  id: "laughter",
13508
- name: "Laughter",
13509
- icon: "😂"
13505
+ name: "Laughter"
13510
13506
  },
13511
13507
  {
13512
13508
  id: "music",
13513
- name: "Music",
13514
- icon: "🎵"
13509
+ name: "Music"
13515
13510
  },
13516
13511
  {
13517
13512
  id: "dog",
13518
- name: "Dog",
13519
- icon: "🐕"
13513
+ name: "Dog"
13520
13514
  },
13521
13515
  {
13522
13516
  id: "cat",
13523
- name: "Cat",
13524
- icon: "🐈"
13517
+ name: "Cat"
13525
13518
  },
13526
13519
  {
13527
13520
  id: "bird",
13528
- name: "Bird",
13529
- icon: "🐦"
13521
+ name: "Bird"
13530
13522
  },
13531
13523
  {
13532
13524
  id: "animal",
13533
- name: "Animal (other)",
13534
- icon: "🐾"
13525
+ name: "Animal (other)"
13535
13526
  },
13536
13527
  {
13537
13528
  id: "alarm",
13538
- name: "Alarm / Siren",
13539
- icon: "🚨"
13529
+ name: "Alarm / Siren"
13540
13530
  },
13541
13531
  {
13542
13532
  id: "doorbell",
13543
- name: "Doorbell / Knock",
13544
- icon: "🔔"
13533
+ name: "Doorbell / Knock"
13545
13534
  },
13546
13535
  {
13547
13536
  id: "glass_breaking",
13548
- name: "Glass Breaking",
13549
- icon: "💥"
13537
+ name: "Glass Breaking"
13550
13538
  },
13551
13539
  {
13552
13540
  id: "gunshot",
13553
- name: "Gunshot / Explosion",
13554
- icon: "💣"
13541
+ name: "Gunshot / Explosion"
13555
13542
  },
13556
13543
  {
13557
13544
  id: "vehicle",
13558
- name: "Vehicle",
13559
- icon: "🚗"
13545
+ name: "Vehicle"
13560
13546
  },
13561
13547
  {
13562
13548
  id: "siren",
13563
- name: "Emergency Siren",
13564
- icon: "🚑"
13549
+ name: "Emergency Siren"
13565
13550
  },
13566
13551
  {
13567
13552
  id: "fire",
13568
- name: "Fire / Smoke",
13569
- icon: "🔥"
13553
+ name: "Fire / Smoke"
13570
13554
  },
13571
13555
  {
13572
13556
  id: "water",
13573
- name: "Water",
13574
- icon: "💧"
13557
+ name: "Water"
13575
13558
  },
13576
13559
  {
13577
13560
  id: "wind",
13578
- name: "Wind / Weather",
13579
- icon: "🌬️"
13561
+ name: "Wind / Weather"
13580
13562
  },
13581
13563
  {
13582
13564
  id: "door",
13583
- name: "Door",
13584
- icon: "🚪"
13565
+ name: "Door"
13585
13566
  },
13586
13567
  {
13587
13568
  id: "footsteps",
13588
- name: "Footsteps",
13589
- icon: "👣"
13569
+ name: "Footsteps"
13590
13570
  },
13591
13571
  {
13592
13572
  id: "crowd",
13593
- name: "Crowd / Chatter",
13594
- icon: "👥"
13573
+ name: "Crowd / Chatter"
13595
13574
  },
13596
13575
  {
13597
13576
  id: "telephone",
13598
- name: "Telephone",
13599
- icon: "📞"
13577
+ name: "Telephone"
13600
13578
  },
13601
13579
  {
13602
13580
  id: "engine",
13603
- name: "Engine / Motor",
13604
- icon: "⚙️"
13581
+ name: "Engine / Motor"
13605
13582
  },
13606
13583
  {
13607
13584
  id: "tools",
13608
- name: "Tools / Construction",
13609
- icon: "🔨"
13585
+ name: "Tools / Construction"
13610
13586
  },
13611
13587
  {
13612
13588
  id: "silence",
13613
- name: "Silence",
13614
- icon: "🤫"
13589
+ name: "Silence"
13615
13590
  }
13616
13591
  ];
13617
13592
  var YAMNET_TO_MACRO = {
@@ -16075,7 +16050,7 @@ var TrackEnvelopeSchema = object({
16075
16050
  * `snapshots[]` references — megabytes across a page of tracks. `slim`
16076
16051
  * keeps every scalar the list surfaces actually render (ids, class(es),
16077
16052
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16078
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16053
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16079
16054
  * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16080
16055
  * `getTrack`. Mirrors the event-store `projection` convention
16081
16056
  * (`getObjectEvents` et al.).
@@ -16370,6 +16345,35 @@ var TrackSchema = object({
16370
16345
  */
16371
16346
  hasFace: boolean().optional(),
16372
16347
  /**
16348
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding — a
16349
+ * face an operator could ASSIGN to an identity.
16350
+ *
16351
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
16352
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
16353
+ * branch, before every gate, and means no more than "a face detector produced
16354
+ * a face detail". This one is stamped at the single moment the gallery row
16355
+ * LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
16356
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
16357
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
16358
+ * the crop-store drop. Everything between the detector and that insert can
16359
+ * legitimately refuse the face, so a flag written any earlier promises the
16360
+ * operator something to assign and delivers nothing.
16361
+ *
16362
+ * **Independent of recognition.** A face collected but never auto-matched is
16363
+ * still assignable — it is in fact the face an operator most wants to reach —
16364
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
16365
+ * `subLabel`; this says only that the raw material exists.
16366
+ *
16367
+ * **Set once, never cleared.** A track that produced a gallery row produced
16368
+ * one; deleting the row later is the gallery's business, not this flag's.
16369
+ *
16370
+ * **Absent ≠ false**, the same rule as {@link hasFace}: every row written
16371
+ * before the column omits it, and so does every server that predates the
16372
+ * field. A consumer must test `=== true` and render nothing otherwise —
16373
+ * never infer "no assignable face".
16374
+ */
16375
+ hasEmbeddedFace: boolean().optional(),
16376
+ /**
16373
16377
  * This subject CONTAINS a folded rider — a person the rider-pairing step
16374
16378
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
16375
16379
  * so the passage is tracked once and as a VEHICLE.
@@ -17719,6 +17723,32 @@ var DetailResultSchema = object({
17719
17723
  /** FRAME-space bbox (already mapped back from crop space). */
17720
17724
  bbox: NativeCropBboxSchema.optional(),
17721
17725
  embedding: string().optional(),
17726
+ /**
17727
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
17728
+ * so an older runner that does not send it degrades to "unmeasurable", which
17729
+ * the consuming gate treats as accept — never as reject.
17730
+ */
17731
+ embeddingMagnitude: number().optional(),
17732
+ /**
17733
+ * Model that produced `embedding` — the SAME contract `labelModelId` has for
17734
+ * `label`, and for the same reason: the producing node is the only side that
17735
+ * knows which model actually ran, and re-deriving it downstream is exactly
17736
+ * the inference this model exists to forbid.
17737
+ *
17738
+ * Additive and optional, so a runner that predates it degrades to
17739
+ * "unmeasurable" rather than to a wrong answer — the consumer falls back to
17740
+ * its previous assumption instead of refusing.
17741
+ *
17742
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
17743
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
17744
+ * with nothing on the wire it took the id from the GALLERY, so the gate
17745
+ * compared the gallery against itself and could never fire. That turned the
17746
+ * one guard protecting the face feature space into a tautology, and it is
17747
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
17748
+ * gallery as the catalog comment predicts — it would have scored the new
17749
+ * model's vectors against the old model's samples in one cosine space.
17750
+ */
17751
+ embeddingModelId: string().optional(),
17722
17752
  label: string().optional(),
17723
17753
  /**
17724
17754
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -18594,6 +18624,12 @@ var CameraStatusSchema = object({
18594
18624
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
18595
18625
  fetchedAt: number()
18596
18626
  });
18627
+ var InferenceDeviceExclusionReasonSchema = _enum([
18628
+ "disabled",
18629
+ "unavailable",
18630
+ "cannot-host-camera-root",
18631
+ "accelerator-preferred"
18632
+ ]);
18597
18633
  var NodeInferenceDeviceSchema = object({
18598
18634
  /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
18599
18635
  key: string(),
@@ -18624,7 +18660,17 @@ var NodeInferenceDeviceSchema = object({
18624
18660
  * available per format; this is the stored selection that becomes the
18625
18661
  * default for EVERY camera landing on this accelerator.
18626
18662
  */
18627
- steps: record(string(), DeviceStepConfigSchema).optional()
18663
+ steps: record(string(), DeviceStepConfigSchema).optional(),
18664
+ /**
18665
+ * `null` when the device IS a camera-root candidate on this node; otherwise
18666
+ * the reason the dispatcher drops it. Computed by the SAME
18667
+ * `resolveInferenceDeviceEligibility` the dispatcher runs, so this view can
18668
+ * never disagree with the election — deriving it in the UI from
18669
+ * `enabled`/`available` would silently miss `cannot-host-camera-root` (needs
18670
+ * the node's model catalog) and `accelerator-preferred` (needs the node-wide
18671
+ * "an accelerator is serving" predicate).
18672
+ */
18673
+ exclusion: InferenceDeviceExclusionReasonSchema.nullable()
18628
18674
  });
18629
18675
  var NodeInferenceDevicesSchema = object({
18630
18676
  nodeId: string(),
@@ -19129,6 +19175,7 @@ DeviceType.Camera, method(object({
19129
19175
  isBattery: boolean(),
19130
19176
  reason: _enum([
19131
19177
  "disabled",
19178
+ "offline",
19132
19179
  "sleeping",
19133
19180
  "unreachable",
19134
19181
  "waking"
@@ -19174,9 +19221,17 @@ targets: array(object({
19174
19221
  sleeping: boolean(),
19175
19222
  /** Current device state rendered over the cached frame. State images
19176
19223
  * remain authoritative even when their photographic background is
19177
- * old; null means the link must carry a current camera frame. */
19224
+ * old; null means the link must carry a current camera frame.
19225
+ *
19226
+ * **This is the ONLY source a surface may derive an inactive tile
19227
+ * from.** A client that reads a device's `online`/`disabled` flags and
19228
+ * draws its own verdict will disagree with the pixels it is painting
19229
+ * — the frame comes from here, and so must the sentence over it
19230
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19231
+ * state. */
19178
19232
  stateReason: _enum([
19179
19233
  "disabled",
19234
+ "offline",
19180
19235
  "sleeping",
19181
19236
  "unreachable",
19182
19237
  "waking"
@@ -22418,7 +22473,12 @@ var ListResultSchema = object({
22418
22473
  probedAt: number()
22419
22474
  });
22420
22475
  var PreferredSchema = LocalInterfaceSchema.nullable();
22421
- var GetConnectionEndpointsResultSchema = object({ endpoints: array(object({
22476
+ /**
22477
+ * Candidate base URL for the SDK to race on connect. Order matters —
22478
+ * the SDK should attempt these top-to-bottom with a short per-candidate
22479
+ * timeout (e.g. 1500ms) and cache the winner for the session.
22480
+ */
22481
+ var ConnectionEndpointSchema = object({
22422
22482
  /** Operator-facing label (e.g. "LAN — en0", "Public tunnel"). */
22423
22483
  label: string(),
22424
22484
  /** Fully-formed base URL with scheme + host + port. */
@@ -22461,7 +22521,42 @@ var GetConnectionEndpointsResultSchema = object({ endpoints: array(object({
22461
22521
  * ordering between polls.
22462
22522
  */
22463
22523
  priority: number()
22464
- })).readonly() });
22524
+ });
22525
+ /**
22526
+ * Where the advertised local port came from. Ordered most → least
22527
+ * authoritative, and the whole point of returning it: a client must be able to
22528
+ * tell a FACT about the hub's socket from an echo of its own guess.
22529
+ */
22530
+ var LocalPortSourceEnum = _enum([
22531
+ "server-config",
22532
+ "server-env",
22533
+ "caller-hint",
22534
+ "default"
22535
+ ]);
22536
+ /** The port every LAN/loopback `baseUrl` in the same result was built with. */
22537
+ var AdvertisedLocalPortSchema = object({
22538
+ port: number().int().min(1).max(65535),
22539
+ source: LocalPortSourceEnum
22540
+ });
22541
+ var GetConnectionEndpointsResultSchema = object({
22542
+ endpoints: array(ConnectionEndpointSchema).readonly(),
22543
+ /**
22544
+ * The port the hub built the LAN/loopback URLs with, and where that number
22545
+ * came from.
22546
+ *
22547
+ * Returned rather than merely applied, because "the URL is right" and "the
22548
+ * client can KNOW the URL is right" are different properties. A client that
22549
+ * only sees a corrected URL cannot distinguish a hub that fixed the port from
22550
+ * a hub that echoed the port the client sent, so it cannot decide whether to
22551
+ * race the candidate or discard it. With `source` it can: anything but
22552
+ * `caller-hint` is the hub's own socket.
22553
+ *
22554
+ * Absent on hubs predating this field — a client that finds it missing is
22555
+ * talking to an echoing hub and must degrade exactly as it does for
22556
+ * `caller-hint`.
22557
+ */
22558
+ localPort: AdvertisedLocalPortSchema
22559
+ });
22465
22560
  /**
22466
22561
  * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
22467
22562
  * AUTO (resolved from the candidate ranking at send time); `resolved` reports
@@ -22482,8 +22577,13 @@ var AllowedAddressesSchema = object({
22482
22577
  */
22483
22578
  addresses: array(string()).readonly() });
22484
22579
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
22485
- /** Local hub HTTP port to use in base URLs. */
22486
- port: number().int().min(1).max(65535),
22580
+ /**
22581
+ * LEGACY HINT — do not send from new code. Kept optional so clients
22582
+ * written against the echoing contract keep working; the hub uses it
22583
+ * only when it cannot read its own port, and says so via
22584
+ * `localPort.source === 'caller-hint'`.
22585
+ */
22586
+ port: number().int().min(1).max(65535).optional(),
22487
22587
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
22488
22588
  * candidate. Default `true`. */
22489
22589
  includeLoopback: boolean().optional(),
@@ -33407,7 +33507,6 @@ var NC_AUDIO_DEFAULTS = {
33407
33507
  hitPercent: 60,
33408
33508
  samplingSeconds: 10
33409
33509
  };
33410
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
33411
33510
  new Set(["devices", "classes"]);
33412
33511
  NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
33413
33512
  /**
@@ -33641,6 +33740,39 @@ TimelapseRuleInputSchema.extend({
33641
33740
  createdAt: number(),
33642
33741
  updatedAt: number()
33643
33742
  });
33743
+ Object.freeze(Object.fromEntries([{
33744
+ stepId: "face-embedding",
33745
+ label: "Face recognition model",
33746
+ defaultModelId: "arcface-r100",
33747
+ indexName: "the enrolled face gallery",
33748
+ options: [
33749
+ {
33750
+ id: "arcface-r100",
33751
+ label: "ArcFace (ResNet34)"
33752
+ },
33753
+ {
33754
+ id: "auraface-r100",
33755
+ label: "AuraFace R100"
33756
+ },
33757
+ {
33758
+ id: "inception-resnet-v1",
33759
+ label: "Inception ResNet V1"
33760
+ }
33761
+ ]
33762
+ }, {
33763
+ stepId: "clip-embedding",
33764
+ label: "Semantic search model",
33765
+ defaultModelId: "mobileclip-s1",
33766
+ indexName: "the object semantic-search index",
33767
+ options: [{
33768
+ id: "mobileclip-s1",
33769
+ label: "MobileCLIP S1"
33770
+ }, {
33771
+ id: "mobileclip-s2",
33772
+ label: "MobileCLIP S2"
33773
+ }]
33774
+ }].map((s) => [s.stepId, s.defaultModelId])));
33775
+ string().min(1);
33644
33776
  object({
33645
33777
  /**
33646
33778
  * Fraction of the box's own size added on EACH side before cutting.
@@ -33661,10 +33793,21 @@ object({
33661
33793
  */
33662
33794
  square: boolean()
33663
33795
  });
33664
- ({
33796
+ /**
33797
+ * The convention in force when nobody has configured one — byte-for-byte the
33798
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
33799
+ */
33800
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
33665
33801
  paddingRatio: .15,
33666
33802
  square: false
33667
- }).paddingRatio;
33803
+ };
33804
+ Object.freeze({
33805
+ x: 0,
33806
+ y: 0,
33807
+ w: 1,
33808
+ h: 1
33809
+ });
33810
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
33668
33811
  /**
33669
33812
  * WHICH delivered frames the decode worker retains a native copy of.
33670
33813
  *
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_shared = require("./shared-BJAy3oN8.js");
5
+ const require_shared = require("./shared-CAxkUIT8.js");
6
6
  let node_stream = require("node:stream");
7
7
  let webdav = require("webdav");
8
8
  //#region src/providers/webdav/webdav-config-schema.ts
@@ -1,4 +1,4 @@
1
- import { a as safeJoinRemotePath, c as BaseAddon, i as rearmIdleAbort, o as scheduleIdleAbort, r as getRequiredBasePath, s as storageProviderCapability, t as createSessionId } from "./shared-BRLPgCy4.mjs";
1
+ import { a as safeJoinRemotePath, c as BaseAddon, i as rearmIdleAbort, o as scheduleIdleAbort, r as getRequiredBasePath, s as storageProviderCapability, t as createSessionId } from "./shared-CMeaUSWI.mjs";
2
2
  import { PassThrough } from "node:stream";
3
3
  import { AuthType, createClient } from "webdav";
4
4
  //#region src/providers/webdav/webdav-config-schema.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-remote-storage",
3
- "version": "1.2.22",
3
+ "version": "1.2.24",
4
4
  "description": "Remote storage providers (SFTP, S3, WebDAV) — unifies remote backends behind the storage-provider cap",
5
5
  "keywords": [
6
6
  "camstack",