@camstack/addon-remote-storage 1.2.21 → 1.2.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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-CrotCkhF.js");
5
+ const require_shared = require("./shared-COlcUch_.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-Toqenw3n.mjs";
1
+ import { c as BaseAddon, i as rearmIdleAbort, n as getOptionalBasePath, o as scheduleIdleAbort, s as storageProviderCapability, t as createSessionId } from "./shared-C5iPm_0G.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-CrotCkhF.js");
5
+ const require_shared = require("./shared-COlcUch_.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-Toqenw3n.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-C5iPm_0G.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
@@ -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
@@ -19129,6 +19159,7 @@ DeviceType.Camera, method(object({
19129
19159
  isBattery: boolean(),
19130
19160
  reason: _enum([
19131
19161
  "disabled",
19162
+ "offline",
19132
19163
  "sleeping",
19133
19164
  "unreachable",
19134
19165
  "waking"
@@ -19174,9 +19205,17 @@ targets: array(object({
19174
19205
  sleeping: boolean(),
19175
19206
  /** Current device state rendered over the cached frame. State images
19176
19207
  * remain authoritative even when their photographic background is
19177
- * old; null means the link must carry a current camera frame. */
19208
+ * old; null means the link must carry a current camera frame.
19209
+ *
19210
+ * **This is the ONLY source a surface may derive an inactive tile
19211
+ * from.** A client that reads a device's `online`/`disabled` flags and
19212
+ * draws its own verdict will disagree with the pixels it is painting
19213
+ * — the frame comes from here, and so must the sentence over it
19214
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19215
+ * state. */
19178
19216
  stateReason: _enum([
19179
19217
  "disabled",
19218
+ "offline",
19180
19219
  "sleeping",
19181
19220
  "unreachable",
19182
19221
  "waking"
@@ -24252,9 +24291,21 @@ var RecordingLocationUsageSchema = object({
24252
24291
  * previously rendered as two identical "disks" with a nonsensical used
24253
24292
  * split — hydrate attribution across aliases is arbitrary by nature. */
24254
24293
  locationIds: array(string()).optional(),
24255
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
24294
+ /**
24295
+ * Filesystem root of the physical volume this row accounts — the only
24296
+ * operator-legible identity when a location has no `displayName` yet, and
24297
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
24298
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
24299
+ * it, and this schema must keep validating that older provider's payload.
24300
+ */
24301
+ root: string().optional(),
24302
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
24303
+ * the footage's SHARE of the volume, not how full the volume is — the disk
24304
+ * also holds everything that is not recordings. Volume fill is
24305
+ * `(totalBytes - availableBytes) / totalBytes`. */
24256
24306
  usedBytes: number(),
24257
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
24307
+ /** Free bytes on the location's volume; null when capacity is unknown
24308
+ * (remote/unstattable — the recorder logs the statfs failure with the root). */
24258
24309
  availableBytes: number().nullable(),
24259
24310
  /** Total bytes of the location's volume; null when unknown. */
24260
24311
  totalBytes: number().nullable()
@@ -24266,7 +24317,15 @@ var RecordingStorageUsageSchema = object({
24266
24317
  nodeId: string(),
24267
24318
  totalUsedBytes: number(),
24268
24319
  devices: array(RecordingDeviceUsageSchema),
24269
- locations: array(RecordingLocationUsageSchema)
24320
+ /**
24321
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
24322
+ * of the payload without it: the hub serves this method through a BAKED
24323
+ * router, so a hub whose framework train predates a change to this array
24324
+ * strips it out of an answer a newer recorder happily produced. A UI that
24325
+ * dereferences it unconditionally crashes the whole Storage page over a
24326
+ * missing disk bar.
24327
+ */
24328
+ locations: array(RecordingLocationUsageSchema).optional()
24270
24329
  });
24271
24330
  /**
24272
24331
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -33382,8 +33441,13 @@ Object.freeze({
33382
33441
  "network-access": "ingress",
33383
33442
  "smtp-provider": "email"
33384
33443
  });
33385
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
33444
+ /** Schema defaults an untouched sub-field must author exactly these. */
33445
+ var NC_AUDIO_DEFAULTS = {
33446
+ hitPercent: 60,
33447
+ samplingSeconds: 10
33448
+ };
33386
33449
  new Set(["devices", "classes"]);
33450
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
33387
33451
  /**
33388
33452
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
33389
33453
  *
@@ -33615,6 +33679,39 @@ TimelapseRuleInputSchema.extend({
33615
33679
  createdAt: number(),
33616
33680
  updatedAt: number()
33617
33681
  });
33682
+ Object.freeze(Object.fromEntries([{
33683
+ stepId: "face-embedding",
33684
+ label: "Face recognition model",
33685
+ defaultModelId: "arcface-r100",
33686
+ indexName: "the enrolled face gallery",
33687
+ options: [
33688
+ {
33689
+ id: "arcface-r100",
33690
+ label: "ArcFace (ResNet34)"
33691
+ },
33692
+ {
33693
+ id: "auraface-r100",
33694
+ label: "AuraFace R100"
33695
+ },
33696
+ {
33697
+ id: "inception-resnet-v1",
33698
+ label: "Inception ResNet V1"
33699
+ }
33700
+ ]
33701
+ }, {
33702
+ stepId: "clip-embedding",
33703
+ label: "Semantic search model",
33704
+ defaultModelId: "mobileclip-s1",
33705
+ indexName: "the object semantic-search index",
33706
+ options: [{
33707
+ id: "mobileclip-s1",
33708
+ label: "MobileCLIP S1"
33709
+ }, {
33710
+ id: "mobileclip-s2",
33711
+ label: "MobileCLIP S2"
33712
+ }]
33713
+ }].map((s) => [s.stepId, s.defaultModelId])));
33714
+ string().min(1);
33618
33715
  object({
33619
33716
  /**
33620
33717
  * Fraction of the box's own size added on EACH side before cutting.
@@ -33635,10 +33732,21 @@ object({
33635
33732
  */
33636
33733
  square: boolean()
33637
33734
  });
33638
- ({
33735
+ /**
33736
+ * The convention in force when nobody has configured one — byte-for-byte the
33737
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
33738
+ */
33739
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
33639
33740
  paddingRatio: .15,
33640
33741
  square: false
33641
- }).paddingRatio;
33742
+ };
33743
+ Object.freeze({
33744
+ x: 0,
33745
+ y: 0,
33746
+ w: 1,
33747
+ h: 1
33748
+ });
33749
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
33642
33750
  /**
33643
33751
  * WHICH delivered frames the decode worker retains a native copy of.
33644
33752
  *
@@ -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
@@ -19152,6 +19182,7 @@ DeviceType.Camera, method(object({
19152
19182
  isBattery: boolean(),
19153
19183
  reason: _enum([
19154
19184
  "disabled",
19185
+ "offline",
19155
19186
  "sleeping",
19156
19187
  "unreachable",
19157
19188
  "waking"
@@ -19197,9 +19228,17 @@ targets: array(object({
19197
19228
  sleeping: boolean(),
19198
19229
  /** Current device state rendered over the cached frame. State images
19199
19230
  * remain authoritative even when their photographic background is
19200
- * old; null means the link must carry a current camera frame. */
19231
+ * old; null means the link must carry a current camera frame.
19232
+ *
19233
+ * **This is the ONLY source a surface may derive an inactive tile
19234
+ * from.** A client that reads a device's `online`/`disabled` flags and
19235
+ * draws its own verdict will disagree with the pixels it is painting
19236
+ * — the frame comes from here, and so must the sentence over it
19237
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19238
+ * state. */
19201
19239
  stateReason: _enum([
19202
19240
  "disabled",
19241
+ "offline",
19203
19242
  "sleeping",
19204
19243
  "unreachable",
19205
19244
  "waking"
@@ -24275,9 +24314,21 @@ var RecordingLocationUsageSchema = object({
24275
24314
  * previously rendered as two identical "disks" with a nonsensical used
24276
24315
  * split — hydrate attribution across aliases is arbitrary by nature. */
24277
24316
  locationIds: array(string()).optional(),
24278
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
24317
+ /**
24318
+ * Filesystem root of the physical volume this row accounts — the only
24319
+ * operator-legible identity when a location has no `displayName` yet, and
24320
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
24321
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
24322
+ * it, and this schema must keep validating that older provider's payload.
24323
+ */
24324
+ root: string().optional(),
24325
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
24326
+ * the footage's SHARE of the volume, not how full the volume is — the disk
24327
+ * also holds everything that is not recordings. Volume fill is
24328
+ * `(totalBytes - availableBytes) / totalBytes`. */
24279
24329
  usedBytes: number(),
24280
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
24330
+ /** Free bytes on the location's volume; null when capacity is unknown
24331
+ * (remote/unstattable — the recorder logs the statfs failure with the root). */
24281
24332
  availableBytes: number().nullable(),
24282
24333
  /** Total bytes of the location's volume; null when unknown. */
24283
24334
  totalBytes: number().nullable()
@@ -24289,7 +24340,15 @@ var RecordingStorageUsageSchema = object({
24289
24340
  nodeId: string(),
24290
24341
  totalUsedBytes: number(),
24291
24342
  devices: array(RecordingDeviceUsageSchema),
24292
- locations: array(RecordingLocationUsageSchema)
24343
+ /**
24344
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
24345
+ * of the payload without it: the hub serves this method through a BAKED
24346
+ * router, so a hub whose framework train predates a change to this array
24347
+ * strips it out of an answer a newer recorder happily produced. A UI that
24348
+ * dereferences it unconditionally crashes the whole Storage page over a
24349
+ * missing disk bar.
24350
+ */
24351
+ locations: array(RecordingLocationUsageSchema).optional()
24293
24352
  });
24294
24353
  /**
24295
24354
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -33405,8 +33464,13 @@ Object.freeze({
33405
33464
  "network-access": "ingress",
33406
33465
  "smtp-provider": "email"
33407
33466
  });
33408
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
33467
+ /** Schema defaults an untouched sub-field must author exactly these. */
33468
+ var NC_AUDIO_DEFAULTS = {
33469
+ hitPercent: 60,
33470
+ samplingSeconds: 10
33471
+ };
33409
33472
  new Set(["devices", "classes"]);
33473
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
33410
33474
  /**
33411
33475
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
33412
33476
  *
@@ -33638,6 +33702,39 @@ TimelapseRuleInputSchema.extend({
33638
33702
  createdAt: number(),
33639
33703
  updatedAt: number()
33640
33704
  });
33705
+ Object.freeze(Object.fromEntries([{
33706
+ stepId: "face-embedding",
33707
+ label: "Face recognition model",
33708
+ defaultModelId: "arcface-r100",
33709
+ indexName: "the enrolled face gallery",
33710
+ options: [
33711
+ {
33712
+ id: "arcface-r100",
33713
+ label: "ArcFace (ResNet34)"
33714
+ },
33715
+ {
33716
+ id: "auraface-r100",
33717
+ label: "AuraFace R100"
33718
+ },
33719
+ {
33720
+ id: "inception-resnet-v1",
33721
+ label: "Inception ResNet V1"
33722
+ }
33723
+ ]
33724
+ }, {
33725
+ stepId: "clip-embedding",
33726
+ label: "Semantic search model",
33727
+ defaultModelId: "mobileclip-s1",
33728
+ indexName: "the object semantic-search index",
33729
+ options: [{
33730
+ id: "mobileclip-s1",
33731
+ label: "MobileCLIP S1"
33732
+ }, {
33733
+ id: "mobileclip-s2",
33734
+ label: "MobileCLIP S2"
33735
+ }]
33736
+ }].map((s) => [s.stepId, s.defaultModelId])));
33737
+ string().min(1);
33641
33738
  object({
33642
33739
  /**
33643
33740
  * Fraction of the box's own size added on EACH side before cutting.
@@ -33658,10 +33755,21 @@ object({
33658
33755
  */
33659
33756
  square: boolean()
33660
33757
  });
33661
- ({
33758
+ /**
33759
+ * The convention in force when nobody has configured one — byte-for-byte the
33760
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
33761
+ */
33762
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
33662
33763
  paddingRatio: .15,
33663
33764
  square: false
33664
- }).paddingRatio;
33765
+ };
33766
+ Object.freeze({
33767
+ x: 0,
33768
+ y: 0,
33769
+ w: 1,
33770
+ h: 1
33771
+ });
33772
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
33665
33773
  /**
33666
33774
  * WHICH delivered frames the decode worker retains a native copy of.
33667
33775
  *
@@ -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-CrotCkhF.js");
5
+ const require_shared = require("./shared-COlcUch_.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-Toqenw3n.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-C5iPm_0G.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.21",
3
+ "version": "1.2.23",
4
4
  "description": "Remote storage providers (SFTP, S3, WebDAV) — unifies remote backends behind the storage-provider cap",
5
5
  "keywords": [
6
6
  "camstack",