@camstack/addon-remote-storage 1.2.13 → 1.2.14

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-CgYcIB-Z.js");
5
+ const require_shared = require("./shared-BiN4gTjL.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-saei9-aP.mjs";
1
+ import { c as BaseAddon, i as rearmIdleAbort, n as getOptionalBasePath, o as scheduleIdleAbort, s as storageProviderCapability, t as createSessionId } from "./shared-EsnEAfgQ.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-CgYcIB-Z.js");
5
+ const require_shared = require("./shared-BiN4gTjL.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-saei9-aP.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-EsnEAfgQ.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
@@ -23636,13 +23636,24 @@ method(object({
23636
23636
  /** Playback-speed multiplier for the render (1 = realtime). */
23637
23637
  var ExportSpeedSchema = number().min(.25).max(32);
23638
23638
  /**
23639
- * One dense interval, in SECONDS FROM THE EXPORT'S OWN `fromMs`.
23639
+ * One dense interval, in WALL-CLOCK SECONDS FROM THE EXPORT'S OWN `fromMs`.
23640
23640
  *
23641
- * Relative and not absolute epoch on purpose: the renderer's frame-select
23642
- * expression sees ffmpeg's `t`, which starts at 0 for the export's source
23643
- * playlist. Handing it absolute epochs would make every call site responsible
23644
- * for the same subtraction, and the one that forgot would emit a filter that
23645
- * selects nothing silently, as a uniform timelapse.
23641
+ * **Wall clock, not ffmpeg's `t`** and the recorder translates. A caller
23642
+ * derives these bounds from things that happened at a TIME (a track's
23643
+ * `firstSeen`), while `t` runs over the source playlist: the concatenation of
23644
+ * every segment present for the range, with each recording GAP removed. The
23645
+ * two agree only on a window that recorded without one interruption, and only
23646
+ * the render side knows the segments, so the translation lives there
23647
+ * (`export-dense-map.ts`, addon-pipeline).
23648
+ *
23649
+ * It was not always so. These seconds were fed to `between(t,…)` verbatim, and
23650
+ * on a 10 h window holding 29,393 s of footage every range landed late by the
23651
+ * gap accumulated before it — up to 6,607 s, well past EOF. Nothing matched,
23652
+ * the video was a uniform timelapse, and the log line reported the five ranges
23653
+ * that had been ASKED for (2026-08-13, export `57d14363`, camera 615).
23654
+ *
23655
+ * Relative and not absolute epoch, because an absolute epoch would make every
23656
+ * call site responsible for the same subtraction.
23646
23657
  */
23647
23658
  var ExportDenseRangeSchema = object({
23648
23659
  fromSec: number().nonnegative(),
@@ -30772,25 +30783,32 @@ object({
30772
30783
  var NativeLeaseAdmissionSchema = _enum(["all", "inferred"]);
30773
30784
  object({
30774
30785
  /**
30775
- * How long a retained native frame is served before it counts as a miss.
30786
+ * How many delivered frames the worker HOLDS at once, waiting for each one's
30787
+ * detection result.
30776
30788
  *
30777
- * Must cover the FULL late-crop horizon: detection inference + the
30778
- * cross-process inference-result hop to hub post-analysis + tracking + the
30779
- * tRPC crop round-trip back. Below ~500 ms the busiest cameras' subject crops
30780
- * outrun it and fall back to the ≤640 detection frame; above ~3 s the resident
30781
- * RAM per busy camera grows linearly with no measured hit-rate gain.
30789
+ * This replaced a TTL on 2026-08-13, and the replacement is the whole point:
30790
+ * a time window was never related to the event the pixels were waiting for.
30791
+ * A held frame now lives from delivery until the runner has its `FrameResult`
30792
+ * at which moment the runner cuts the subject tiles it actually wanted and
30793
+ * releases the frame. The bound exists only so a runner that stops answering
30794
+ * cannot pin RAM: above it the OLDEST held frame is dropped and counted.
30795
+ *
30796
+ * Sizing: the steady state is `inferenceLatency × deliveredFps`, measured at
30797
+ * 40-160 ms × ≤25 fps = 1-4 frames. The default leaves headroom for a hiccup
30798
+ * without ever approaching the old resident set (43 frames × 24.9 MB at 4K).
30799
+ * Raising it does not buy hit rate — it buys tolerance for a slow runner, and
30800
+ * `holdOverflow` on the metrics line is what says you need it.
30782
30801
  */
30783
- ttlMs: number().int().min(250).max(1e4),
30802
+ holdFrames: number().int().min(1).max(64),
30784
30803
  /**
30785
30804
  * Hard per-decode-worker RAM ceiling for retained native frames, in MB.
30786
30805
  *
30787
- * Intended as a SAFETY ceiling with the TTL as the effective cap — but check
30788
- * which one is actually binding before reasoning from that. At the shipped
30789
- * 1024 MB and a 2 800 ms TTL, a 4K camera hits the CEILING first (~43 frames
30790
- * at ~24 MB each) and the TTL never gets to expire anything; `leaseMb` /
30791
- * `leaseFrames` on the metrics line say which. When the ceiling binds, a
30792
- * change that admits fewer frames buys retention WINDOW at constant RAM
30793
- * rather than giving RAM back — lower this knob if RAM is what you wanted.
30806
+ * Since 2026-08-13 this is a SAFETY ceiling and nothing else: `holdFrames`
30807
+ * is what decides how much is held, and the ceiling is the number above which
30808
+ * something is wrong. Before that it was the effective cap at 1024 MB with
30809
+ * a 2 800 ms TTL a 4K camera sat pinned at `leaseMb:1020, leaseFrames:43`
30810
+ * with the TTL expiring nothing, which is exactly the confusion the hold
30811
+ * removes. `leaseMb` / `leaseFrames` still say what is resident.
30794
30812
  * `0` DISABLES the lease entirely and falls the worker back to the tiny
30795
30813
  * leak-prone GPU surface ring (~85% crop miss; that is what the lease exists
30796
30814
  * to replace).
@@ -30816,22 +30834,45 @@ object({
30816
30834
  * there is the signal that some caller names frames outside the inference set
30817
30835
  * and that this must go back to `all`.
30818
30836
  */
30819
- admission: NativeLeaseAdmissionSchema
30837
+ admission: NativeLeaseAdmissionSchema,
30838
+ /**
30839
+ * RAM ceiling per decode worker, in MB, for the SUBJECT TILES — the
30840
+ * compressed native crops the worker cuts at the moment a frame's detection
30841
+ * result arrives, and keeps long after the frame itself is freed.
30842
+ *
30843
+ * This is the knob that replaced the old retention window, and it buys about
30844
+ * three orders of magnitude more of it: a tile is one subject at native
30845
+ * resolution, JPEG-encoded (~60-120 KB on a 4K person), against ~24.9 MB for
30846
+ * the frame it was cut from. A frame on which nothing was detected costs
30847
+ * nothing at all, which is the real change — the old lease paid per FRAME and
30848
+ * was interrogated per SUBJECT.
30849
+ *
30850
+ * `0` DISABLES tiles, leaving only the hold window and the ≤640 RAM
30851
+ * fallback — i.e. the pre-2026-08-13 miss profile. Set it there only to
30852
+ * reproduce that.
30853
+ */
30854
+ tileBudgetMb: number().int().min(0).max(1024)
30820
30855
  });
30821
30856
  /**
30822
- * The values in force when the operator has set nothing — byte-for-byte the
30823
- * constants the decode worker shipped with as env-var defaults, so making these
30824
- * settings changed no behaviour on the day it landed.
30857
+ * The values in force when the operator has set nothing.
30858
+ *
30859
+ * `budgetMb` stays at 1024 on the day the hold landed, deliberately: it stopped
30860
+ * being the retention window and became the OOM ceiling, and lowering a ceiling
30861
+ * in the same change that redefines it would make a regression and a retune
30862
+ * indistinguishable. Cut it once `tileHits` / `holdOverflow` have been read on
30863
+ * live traffic.
30825
30864
  */
30826
30865
  var DEFAULT_NATIVE_LEASE_SETTINGS = {
30827
- ttlMs: 1200,
30866
+ holdFrames: 8,
30828
30867
  budgetMb: 1024,
30829
30868
  activityMs: 15e3,
30869
+ tileBudgetMb: 64,
30830
30870
  admission: "inferred"
30831
30871
  };
30832
- DEFAULT_NATIVE_LEASE_SETTINGS.ttlMs;
30872
+ DEFAULT_NATIVE_LEASE_SETTINGS.holdFrames;
30833
30873
  DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
30834
30874
  DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
30875
+ DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
30835
30876
  DEFAULT_NATIVE_LEASE_SETTINGS.admission;
30836
30877
  //#endregion
30837
30878
  //#region src/shared.ts
@@ -23613,13 +23613,24 @@ method(object({
23613
23613
  /** Playback-speed multiplier for the render (1 = realtime). */
23614
23614
  var ExportSpeedSchema = number().min(.25).max(32);
23615
23615
  /**
23616
- * One dense interval, in SECONDS FROM THE EXPORT'S OWN `fromMs`.
23616
+ * One dense interval, in WALL-CLOCK SECONDS FROM THE EXPORT'S OWN `fromMs`.
23617
23617
  *
23618
- * Relative and not absolute epoch on purpose: the renderer's frame-select
23619
- * expression sees ffmpeg's `t`, which starts at 0 for the export's source
23620
- * playlist. Handing it absolute epochs would make every call site responsible
23621
- * for the same subtraction, and the one that forgot would emit a filter that
23622
- * selects nothing silently, as a uniform timelapse.
23618
+ * **Wall clock, not ffmpeg's `t`** and the recorder translates. A caller
23619
+ * derives these bounds from things that happened at a TIME (a track's
23620
+ * `firstSeen`), while `t` runs over the source playlist: the concatenation of
23621
+ * every segment present for the range, with each recording GAP removed. The
23622
+ * two agree only on a window that recorded without one interruption, and only
23623
+ * the render side knows the segments, so the translation lives there
23624
+ * (`export-dense-map.ts`, addon-pipeline).
23625
+ *
23626
+ * It was not always so. These seconds were fed to `between(t,…)` verbatim, and
23627
+ * on a 10 h window holding 29,393 s of footage every range landed late by the
23628
+ * gap accumulated before it — up to 6,607 s, well past EOF. Nothing matched,
23629
+ * the video was a uniform timelapse, and the log line reported the five ranges
23630
+ * that had been ASKED for (2026-08-13, export `57d14363`, camera 615).
23631
+ *
23632
+ * Relative and not absolute epoch, because an absolute epoch would make every
23633
+ * call site responsible for the same subtraction.
23623
23634
  */
23624
23635
  var ExportDenseRangeSchema = object({
23625
23636
  fromSec: number().nonnegative(),
@@ -30749,25 +30760,32 @@ object({
30749
30760
  var NativeLeaseAdmissionSchema = _enum(["all", "inferred"]);
30750
30761
  object({
30751
30762
  /**
30752
- * How long a retained native frame is served before it counts as a miss.
30763
+ * How many delivered frames the worker HOLDS at once, waiting for each one's
30764
+ * detection result.
30753
30765
  *
30754
- * Must cover the FULL late-crop horizon: detection inference + the
30755
- * cross-process inference-result hop to hub post-analysis + tracking + the
30756
- * tRPC crop round-trip back. Below ~500 ms the busiest cameras' subject crops
30757
- * outrun it and fall back to the ≤640 detection frame; above ~3 s the resident
30758
- * RAM per busy camera grows linearly with no measured hit-rate gain.
30766
+ * This replaced a TTL on 2026-08-13, and the replacement is the whole point:
30767
+ * a time window was never related to the event the pixels were waiting for.
30768
+ * A held frame now lives from delivery until the runner has its `FrameResult`
30769
+ * at which moment the runner cuts the subject tiles it actually wanted and
30770
+ * releases the frame. The bound exists only so a runner that stops answering
30771
+ * cannot pin RAM: above it the OLDEST held frame is dropped and counted.
30772
+ *
30773
+ * Sizing: the steady state is `inferenceLatency × deliveredFps`, measured at
30774
+ * 40-160 ms × ≤25 fps = 1-4 frames. The default leaves headroom for a hiccup
30775
+ * without ever approaching the old resident set (43 frames × 24.9 MB at 4K).
30776
+ * Raising it does not buy hit rate — it buys tolerance for a slow runner, and
30777
+ * `holdOverflow` on the metrics line is what says you need it.
30759
30778
  */
30760
- ttlMs: number().int().min(250).max(1e4),
30779
+ holdFrames: number().int().min(1).max(64),
30761
30780
  /**
30762
30781
  * Hard per-decode-worker RAM ceiling for retained native frames, in MB.
30763
30782
  *
30764
- * Intended as a SAFETY ceiling with the TTL as the effective cap — but check
30765
- * which one is actually binding before reasoning from that. At the shipped
30766
- * 1024 MB and a 2 800 ms TTL, a 4K camera hits the CEILING first (~43 frames
30767
- * at ~24 MB each) and the TTL never gets to expire anything; `leaseMb` /
30768
- * `leaseFrames` on the metrics line say which. When the ceiling binds, a
30769
- * change that admits fewer frames buys retention WINDOW at constant RAM
30770
- * rather than giving RAM back — lower this knob if RAM is what you wanted.
30783
+ * Since 2026-08-13 this is a SAFETY ceiling and nothing else: `holdFrames`
30784
+ * is what decides how much is held, and the ceiling is the number above which
30785
+ * something is wrong. Before that it was the effective cap at 1024 MB with
30786
+ * a 2 800 ms TTL a 4K camera sat pinned at `leaseMb:1020, leaseFrames:43`
30787
+ * with the TTL expiring nothing, which is exactly the confusion the hold
30788
+ * removes. `leaseMb` / `leaseFrames` still say what is resident.
30771
30789
  * `0` DISABLES the lease entirely and falls the worker back to the tiny
30772
30790
  * leak-prone GPU surface ring (~85% crop miss; that is what the lease exists
30773
30791
  * to replace).
@@ -30793,22 +30811,45 @@ object({
30793
30811
  * there is the signal that some caller names frames outside the inference set
30794
30812
  * and that this must go back to `all`.
30795
30813
  */
30796
- admission: NativeLeaseAdmissionSchema
30814
+ admission: NativeLeaseAdmissionSchema,
30815
+ /**
30816
+ * RAM ceiling per decode worker, in MB, for the SUBJECT TILES — the
30817
+ * compressed native crops the worker cuts at the moment a frame's detection
30818
+ * result arrives, and keeps long after the frame itself is freed.
30819
+ *
30820
+ * This is the knob that replaced the old retention window, and it buys about
30821
+ * three orders of magnitude more of it: a tile is one subject at native
30822
+ * resolution, JPEG-encoded (~60-120 KB on a 4K person), against ~24.9 MB for
30823
+ * the frame it was cut from. A frame on which nothing was detected costs
30824
+ * nothing at all, which is the real change — the old lease paid per FRAME and
30825
+ * was interrogated per SUBJECT.
30826
+ *
30827
+ * `0` DISABLES tiles, leaving only the hold window and the ≤640 RAM
30828
+ * fallback — i.e. the pre-2026-08-13 miss profile. Set it there only to
30829
+ * reproduce that.
30830
+ */
30831
+ tileBudgetMb: number().int().min(0).max(1024)
30797
30832
  });
30798
30833
  /**
30799
- * The values in force when the operator has set nothing — byte-for-byte the
30800
- * constants the decode worker shipped with as env-var defaults, so making these
30801
- * settings changed no behaviour on the day it landed.
30834
+ * The values in force when the operator has set nothing.
30835
+ *
30836
+ * `budgetMb` stays at 1024 on the day the hold landed, deliberately: it stopped
30837
+ * being the retention window and became the OOM ceiling, and lowering a ceiling
30838
+ * in the same change that redefines it would make a regression and a retune
30839
+ * indistinguishable. Cut it once `tileHits` / `holdOverflow` have been read on
30840
+ * live traffic.
30802
30841
  */
30803
30842
  var DEFAULT_NATIVE_LEASE_SETTINGS = {
30804
- ttlMs: 1200,
30843
+ holdFrames: 8,
30805
30844
  budgetMb: 1024,
30806
30845
  activityMs: 15e3,
30846
+ tileBudgetMb: 64,
30807
30847
  admission: "inferred"
30808
30848
  };
30809
- DEFAULT_NATIVE_LEASE_SETTINGS.ttlMs;
30849
+ DEFAULT_NATIVE_LEASE_SETTINGS.holdFrames;
30810
30850
  DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
30811
30851
  DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
30852
+ DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
30812
30853
  DEFAULT_NATIVE_LEASE_SETTINGS.admission;
30813
30854
  //#endregion
30814
30855
  //#region src/shared.ts
@@ -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-CgYcIB-Z.js");
5
+ const require_shared = require("./shared-BiN4gTjL.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-saei9-aP.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-EsnEAfgQ.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.13",
3
+ "version": "1.2.14",
4
4
  "description": "Remote storage providers (SFTP, S3, WebDAV) — unifies remote backends behind the storage-provider cap",
5
5
  "keywords": [
6
6
  "camstack",