camstack 1.2.154 → 1.2.155

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.
@@ -14522,7 +14522,7 @@ function date4(params) {
14522
14522
  // ../../node_modules/zod/v4/classic/external.js
14523
14523
  config(en_default());
14524
14524
 
14525
- // ../types/dist/sleep-BEyvfshj.mjs
14525
+ // ../types/dist/sleep-BDR76Ykr.mjs
14526
14526
  var AUDIO_CHUNK_FORMATS = [
14527
14527
  "f32le",
14528
14528
  "pcmu",
@@ -18812,6 +18812,21 @@ var streamSignalsCapability = {
18812
18812
  mode: "singleton",
18813
18813
  deviceTypes: Object.values(DeviceType),
18814
18814
  runtimeState: StreamSignalsStatusSchema,
18815
+ /**
18816
+ * Runtime-state durability: **session** — mirrored in RAM, never written.
18817
+ *
18818
+ * The slice holds what the DEVICE says it can emit. That is a probed fact,
18819
+ * not an operator choice: the provider re-declares it on every registration,
18820
+ * so losing it loses nothing and persisting it would freeze an answer the
18821
+ * camera is entitled to change. Measured the same day on the sibling case —
18822
+ * `native-object-detection.supportedClasses` was persisted, and a firmware
18823
+ * class the camera really detected stayed missing for the life of the row
18824
+ * because the fix could not reach it.
18825
+ *
18826
+ * See `RuntimeStateDurability`. Enforced by
18827
+ * `scripts/check-runtime-state-durability.ts`.
18828
+ */
18829
+ durability: "session",
18815
18830
  methods: {
18816
18831
  /**
18817
18832
  * What this device can emit. Empty is a valid and common answer — most
@@ -25592,6 +25607,29 @@ var NcAlarmConfigSchema = external_exports.object({
25592
25607
  settings: NcAlarmSettingsSchema,
25593
25608
  coverage: external_exports.array(NcAlarmModeCoverageSchema)
25594
25609
  });
25610
+ var NcClipRetentionAskSchema = external_exports.object({
25611
+ /**
25612
+ * The camera this ask is about. **Absent = every camera**, which is what a
25613
+ * rule with no `conditions.devices` means: it can fire anywhere, so it is
25614
+ * asking everywhere.
25615
+ */
25616
+ deviceId: external_exports.number().int().nonnegative().optional(),
25617
+ /** Seconds of history the rule needs held for it. Never zero — a rule that
25618
+ * needs nothing produces no ask at all. */
25619
+ seconds: external_exports.number().min(0).max(60),
25620
+ /** The profile the rule cuts from, when it named one. Absent = the cheapest
25621
+ * assigned, which is what the cut defaults to. */
25622
+ profile: CamProfileSchema.optional(),
25623
+ /** Who is asking — so a retention the operator did not expect names a rule. */
25624
+ ruleId: external_exports.string(),
25625
+ ruleName: external_exports.string(),
25626
+ /** Why this many seconds: the rule's own window, or the occupancy ceiling. */
25627
+ reason: external_exports.enum(["window", "occupancy"])
25628
+ });
25629
+ var NcClipRetentionPlanSchema = external_exports.object({
25630
+ rulesLoaded: external_exports.boolean(),
25631
+ asks: external_exports.array(NcClipRetentionAskSchema).readonly()
25632
+ });
25595
25633
  var notificationRulesCapability = {
25596
25634
  name: "notification-rules",
25597
25635
  scope: "system",
@@ -25624,6 +25662,23 @@ var notificationRulesCapability = {
25624
25662
  auth: "admin"
25625
25663
  }),
25626
25664
  /**
25665
+ * WHAT THE RULES ACTUALLY ASK the stream broker to retain, per camera.
25666
+ *
25667
+ * The notification centre owns the rules, so it is the only thing that can
25668
+ * say how much history a camera's notifications will ever reach back for.
25669
+ * Before this the broker guessed — a flat minute on every camera — and
25670
+ * learned the PROFILE reactively, after the first clip had already been cut
25671
+ * from the wrong one. This is the same ask stated once, in front.
25672
+ *
25673
+ * A QUERY, pulled by each node's broker, not a push: brokers are per node
25674
+ * (a camera's ring lives wherever its stream is ingested) while this cap is
25675
+ * a singleton, so a push would have to enumerate the cluster. The pull also
25676
+ * makes the failure mode right — a broker that cannot reach the centre
25677
+ * keeps the plan it has, and a plan that has never arrived is UNKNOWN
25678
+ * rather than empty (D49: a read that fails changes nothing).
25679
+ */
25680
+ getClipRetentionAsks: method(external_exports.object({}), NcClipRetentionPlanSchema, { auth: "admin" }),
25681
+ /**
25627
25682
  * PERMANENT per-camera mute — the notifications half of the per-camera
25628
25683
  * function switch group ([D61](../../../../docs/decisions/adr-0067.md)).
25629
25684
  *
@@ -27833,6 +27888,20 @@ var ReplayTrackSchema = external_exports.object({
27833
27888
  framesMatched: external_exports.number().int()
27834
27889
  });
27835
27890
  var RunReplayFrameProcessorResultSchema = external_exports.object({ tracks: external_exports.array(ReplayTrackSchema).readonly() });
27891
+ var AnalyticsLtsSeriesSchema = external_exports.enum([
27892
+ "motion",
27893
+ "audio-dbfs",
27894
+ "battery",
27895
+ "occupancy"
27896
+ ]);
27897
+ var LtsBucketSchema = external_exports.object({
27898
+ scope: external_exports.string(),
27899
+ bucketStart: external_exports.number().int(),
27900
+ samples: external_exports.number().int().nonnegative(),
27901
+ sum: external_exports.number(),
27902
+ min: external_exports.number(),
27903
+ max: external_exports.number()
27904
+ });
27836
27905
  var pipelineAnalyticsCapability = {
27837
27906
  name: "pipeline-analytics",
27838
27907
  scope: "device",
@@ -27976,6 +28045,30 @@ var pipelineAnalyticsCapability = {
27976
28045
  getKeyEventsBatch: method(KeyEventBatchQueryInput, external_exports.array(KeyEventsForDeviceSchema).readonly()),
27977
28046
  /** Server-side bucketed event counts for the 24-hour timeline.
27978
28047
  * Returns one entry per non-empty bucket; empty buckets are omitted. */
28048
+ /**
28049
+ * Read one camera's long-term series — 5-minute buckets, kept for a year.
28050
+ *
28051
+ * This is the history surface for every chart that used to be served from a
28052
+ * RAM ring: the ring dies with the process, cannot answer about last night,
28053
+ * and had a 60-minute horizon, while these rows are ~60 bytes and already
28054
+ * written. `scope` is the series' own dimension — for `occupancy`, spell it
28055
+ * with {@link occupancyScope} rather than by hand, and omit it to get every
28056
+ * scope back at once (the caller then groups with
28057
+ * {@link parseOccupancyScope}).
28058
+ *
28059
+ * Bounds are inclusive on the BUCKET START, so a range that ends mid-bucket
28060
+ * still returns the bucket it lands in — the alternative is a chart whose
28061
+ * last column silently disappears for five minutes out of every five.
28062
+ */
28063
+ readLongTermSeries: method(external_exports.object({
28064
+ deviceId: external_exports.number(),
28065
+ series: AnalyticsLtsSeriesSchema,
28066
+ /** Omit for EVERY scope of this series in the range. */
28067
+ scope: external_exports.string().optional(),
28068
+ from: external_exports.number(),
28069
+ to: external_exports.number(),
28070
+ limit: external_exports.number().int().positive().optional()
28071
+ }), external_exports.array(LtsBucketSchema).readonly()),
27979
28072
  getEventDensity: method(external_exports.object({
27980
28073
  deviceId: external_exports.number(),
27981
28074
  since: external_exports.number(),
@@ -29478,6 +29571,12 @@ var RunnerLocalMetricsSchema = external_exports.object({
29478
29571
  queueDepth: external_exports.number(),
29479
29572
  frameLazy: FrameLazyMetricsSchema.optional()
29480
29573
  });
29574
+ var OccupancyBurstRefusalSchema = external_exports.enum([
29575
+ "not-attached",
29576
+ "battery-asleep",
29577
+ "not-watching",
29578
+ "already-bursting"
29579
+ ]);
29481
29580
  var pipelineRunnerCapability = {
29482
29581
  name: "pipeline-runner",
29483
29582
  scope: "system",
@@ -29514,6 +29613,50 @@ var pipelineRunnerCapability = {
29514
29613
  /** List the deviceIds currently attached to this runner. */
29515
29614
  getLocalCameras: method(external_exports.void(), external_exports.array(external_exports.number()).readonly()),
29516
29615
  /**
29616
+ * Look at a camera NOW, out of band, because something just happened that
29617
+ * only a fresh look can settle.
29618
+ *
29619
+ * The periodic recheck (`occupancyRecheckSec`, 300 s) exists to watch a
29620
+ * still scene. It is the wrong instrument for a QUESTION that has just been
29621
+ * asked: on device 617 a parked car's departure was observed, a departure
29622
+ * strike was armed — and then the motion session ended, the strike decayed
29623
+ * after its 30 s TTL, and the next periodic look arrived up to five minutes
29624
+ * later with nothing left to confirm. Every one of those departures was
29625
+ * settled by the entry ageing out 6 to 10 minutes of observed time later,
29626
+ * and the notification's clip showed an empty space with nothing leaving
29627
+ * it.
29628
+ *
29629
+ * Two numbers make the ask specific, and a caller that ignores them wastes
29630
+ * the burst: a confirmation must land at least
29631
+ * `DEPARTURE_CONFIRM_MIN_GAP_MS` (3 s) after the read that armed the
29632
+ * strike — before that it is the same optical event and is refused — and
29633
+ * `DEPARTURE_ABSENCE_MIN_READS` (5) consecutive unassociated frames are
29634
+ * needed, while `occupancyRecheckFrames` defaults to FOUR. A burst of four
29635
+ * can never confirm an absence; that is why two periodic looks were always
29636
+ * required.
29637
+ *
29638
+ * The runner answers whether it actually started one. A refusal is NAMED,
29639
+ * never a silent `false`: a camera that is asleep on battery (D173 — this
29640
+ * must not become a self-initiated wake), detached, mid-session or already
29641
+ * bursting are four different facts, and a caller told only "no" cannot
29642
+ * tell a protection from a bug.
29643
+ */
29644
+ requestOccupancyBurst: method(external_exports.object({
29645
+ deviceId: external_exports.number(),
29646
+ /** How many frames to collect. The caller sizes this against what its
29647
+ * own confirmation needs; the runner clamps it to the field's range. */
29648
+ frames: external_exports.number().int().positive().optional(),
29649
+ /** Why, for the log. A burst nobody can attribute is a cost nobody can
29650
+ * defend — the periodic one at least has a timer to point at. */
29651
+ reason: external_exports.string()
29652
+ }), external_exports.object({
29653
+ started: external_exports.boolean(),
29654
+ refusedBecause: OccupancyBurstRefusalSchema.optional()
29655
+ }), {
29656
+ auth: "admin",
29657
+ kind: "mutation"
29658
+ }),
29659
+ /**
29517
29660
  * Best-effort NATIVE-resolution crop of a retention-ring frame. Given the
29518
29661
  * `FrameHandle` that rode an inference-result event and a normalized `bbox`,
29519
29662
  * the runner asks the decode worker still holding that frame's NATIVE
@@ -41041,7 +41184,28 @@ var PerScopeBreakdownSchema = external_exports.object({
41041
41184
  /** Total tracked objects in this scope (frame / zone / unzoned). */
41042
41185
  totalObjects: external_exports.number().int().nonnegative(),
41043
41186
  /** Per-class count. Keys are macro class names (e.g. `person`, `car`). */
41044
- byClass: external_exports.record(external_exports.string(), external_exports.number().int().nonnegative())
41187
+ byClass: external_exports.record(external_exports.string(), external_exports.number().int().nonnegative()),
41188
+ /**
41189
+ * Of `totalObjects`, how many are STANDING — objects the census holds,
41190
+ * present but not going anywhere (a parked car, a bin, a statue).
41191
+ *
41192
+ * The operator's question about a scene has two halves and they answer
41193
+ * different things: "what is parked here" is stable for hours and must not
41194
+ * flap, while "who is walking through" is the thing an alert is about. One
41195
+ * number could only serve one of them, and `totalObjects` served the first
41196
+ * badly — a passer-by moved it and every occupancy rule saw a change.
41197
+ *
41198
+ * `standing + transient === totalObjects`, always. The total keeps its old
41199
+ * meaning exactly, so no rule written against it changes behaviour.
41200
+ *
41201
+ * ABSENT means UNKNOWN, never zero (D393): a snapshot from a node older than
41202
+ * this field cannot say, and a reader that folds absence in as 0 reports "no
41203
+ * parked objects here" about a camera whose lot is full.
41204
+ */
41205
+ standingObjects: external_exports.number().int().nonnegative().optional(),
41206
+ /** Of `totalObjects`, how many are passing through. See `standingObjects` —
41207
+ * same absence rule. */
41208
+ transientObjects: external_exports.number().int().nonnegative().optional()
41045
41209
  });
41046
41210
  var ZoneScopeBreakdownSchema = PerScopeBreakdownSchema.extend({
41047
41211
  zoneId: external_exports.string(),
@@ -44362,6 +44526,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
44362
44526
  addonId: null,
44363
44527
  access: "view"
44364
44528
  },
44529
+ "notificationRules.getClipRetentionAsks": {
44530
+ capName: "notification-rules",
44531
+ capScope: "system",
44532
+ addonId: null,
44533
+ access: "view"
44534
+ },
44365
44535
  "notificationRules.getConditionCatalog": {
44366
44536
  capName: "notification-rules",
44367
44537
  capScope: "system",
@@ -44872,6 +45042,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
44872
45042
  addonId: null,
44873
45043
  access: "create"
44874
45044
  },
45045
+ "pipelineAnalytics.readLongTermSeries": {
45046
+ capName: "pipeline-analytics",
45047
+ capScope: "device",
45048
+ addonId: null,
45049
+ access: "view"
45050
+ },
44875
45051
  "pipelineAnalytics.rebuildObjectEmbeddings": {
44876
45052
  capName: "pipeline-analytics",
44877
45053
  capScope: "device",
@@ -45544,6 +45720,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
45544
45720
  addonId: null,
45545
45721
  access: "create"
45546
45722
  },
45723
+ "pipelineRunner.requestOccupancyBurst": {
45724
+ capName: "pipeline-runner",
45725
+ capScope: "system",
45726
+ addonId: null,
45727
+ access: "create"
45728
+ },
45547
45729
  "pipelineRunner.runDetailSubtree": {
45548
45730
  capName: "pipeline-runner",
45549
45731
  capScope: "system",
@@ -48688,6 +48870,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
48688
48870
  form: "single",
48689
48871
  optional: false
48690
48872
  }],
48873
+ "pipelineAnalytics.readLongTermSeries": [{
48874
+ name: "deviceId",
48875
+ form: "single",
48876
+ optional: false
48877
+ }],
48691
48878
  "pipelineAnalytics.rebuildObjectEmbeddings": [{
48692
48879
  name: "deviceId",
48693
48880
  form: "single",
@@ -48878,6 +49065,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
48878
49065
  form: "single",
48879
49066
  optional: false
48880
49067
  }],
49068
+ "pipelineRunner.requestOccupancyBurst": [{
49069
+ name: "deviceId",
49070
+ form: "single",
49071
+ optional: false
49072
+ }],
48881
49073
  "pipelineRunner.runDetailSubtree": [{
48882
49074
  name: "deviceId",
48883
49075
  form: "single",
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runDiscover
4
- } from "./chunk-G3ME646K.js";
4
+ } from "./chunk-NL37AEPX.js";
5
5
  import "./chunk-LMMQX4CK.js";
6
6
 
7
7
  // src/cli.ts
@@ -38,7 +38,7 @@ async function runServe(args) {
38
38
  ...typeof values.data === "string" ? { data: values.data } : {}
39
39
  };
40
40
  Object.assign(process.env, buildServeEnv(opts));
41
- await import("./launcher-ZQZHWQ6F.js");
41
+ await import("./launcher-QNK4R2TG.js");
42
42
  }
43
43
 
44
44
  // src/commands/agent.ts
@@ -83,7 +83,7 @@ async function runAgent(args) {
83
83
  ...typeof values.port === "string" ? { port: values.port } : {}
84
84
  };
85
85
  Object.assign(process.env, buildAgentEnv(opts));
86
- await import("./launcher-ZQZHWQ6F.js");
86
+ await import("./launcher-QNK4R2TG.js");
87
87
  }
88
88
 
89
89
  // src/commands/setup.ts
@@ -1140,7 +1140,7 @@ function isUnknown(_value) {
1140
1140
  return true;
1141
1141
  }
1142
1142
  async function resolveServerInteractive(presetNamespace) {
1143
- const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-DFMZ7HZD.js");
1143
+ const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-FFHB2Q76.js");
1144
1144
  if (presetNamespace) {
1145
1145
  const spinner4 = clack.spinner();
1146
1146
  spinner4.start(`Discovering hub on LAN (namespace "${presetNamespace}")`);
@@ -5,7 +5,7 @@ import {
5
5
  filterHubNodes,
6
6
  resolveHubFromDiscovered,
7
7
  runDiscover
8
- } from "./chunk-G3ME646K.js";
8
+ } from "./chunk-NL37AEPX.js";
9
9
  import "./chunk-LMMQX4CK.js";
10
10
  export {
11
11
  DEFAULT_HUB_HTTPS_PORT,