camstack 1.2.108 → 1.2.110

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-IaOr7P-z.mjs
14525
+ // ../types/dist/sleep-Cfij6Jj9.mjs
14526
14526
  var WELL_KNOWN_TABS = [
14527
14527
  {
14528
14528
  id: "overview",
@@ -15693,7 +15693,8 @@ var HHMM = /^([01]\d|2[0-3]):[0-5]\d$/;
15693
15693
  var RecordingStorageModeSchema = external_exports.enum([
15694
15694
  "off",
15695
15695
  "events",
15696
- "continuous"
15696
+ "continuous",
15697
+ "on-device-decision"
15697
15698
  ]);
15698
15699
  var RecordingObjectTriggerClassSchema = external_exports.enum(FIRST_LEVEL_MACRO_CLASSES);
15699
15700
  var noDuplicates = (values) => new Set(values).size === values.length;
@@ -15730,22 +15731,7 @@ var RecordingTriggersSchema = external_exports.object({
15730
15731
  * il livello: un contatto trovato già aperto al riavvio del runner non fa
15731
15732
  * registrare.
15732
15733
  */
15733
- sensorDeviceIds: external_exports.array(external_exports.number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional(),
15734
- /**
15735
- * La camera registra per tutta la durata del SEGNALE che lei stessa
15736
- * pubblica — la cap `recording-signal` (`active: true` mentre il device è in
15737
- * funzione: un robot che pulisce). È un LIVELLO, non un fronte: la finestra
15738
- * resta aperta finché il segnale è alto e si chiude `postBufferSec` dopo la
15739
- * caduta, così una pulizia di quaranta minuti è UNA clip.
15740
- *
15741
- * Non nomina un device: il segnale è della camera stessa, tenuto fresco dal
15742
- * suo provider (D224); il recorder lo ascolta su `DeviceStateChanged` e lo
15743
- * riconcilia leggendo la slice via RPC, con un tetto oltre il quale un
15744
- * segnale mai abbassato (un evento perso) non può tenere aperta una
15745
- * registrazione (D11). Vedi `recorder/addon/band-decision.ts`
15746
- * (`holdTrigger` / `releaseTrigger`).
15747
- */
15748
- deviceSignal: external_exports.boolean().optional()
15734
+ sensorDeviceIds: external_exports.array(external_exports.number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
15749
15735
  });
15750
15736
  var RecordingBandModeSchema = external_exports.enum(["continuous", "events"]);
15751
15737
  var RecordingBandTriggersSchema = RecordingTriggersSchema;
@@ -15755,13 +15741,28 @@ var RecordingBandSchema = external_exports.object({
15755
15741
  end: external_exports.string().regex(HHMM),
15756
15742
  mode: RecordingBandModeSchema,
15757
15743
  triggers: RecordingBandTriggersSchema.optional(),
15744
+ /**
15745
+ * RETIRED (D381). A band no longer carries a pre-buffer of its own.
15746
+ *
15747
+ * It was the retroactive KEEP bound — which already-written segments survive
15748
+ * a trigger — and it had to be at least as wide as the widest pre-roll the
15749
+ * broker could serve, or the gate would delete the seconds the ring had just
15750
+ * handed the writer. That "at least as wide as" is the tell: it was a second
15751
+ * expression of the broker's retention, in different units, in a different
15752
+ * addon, with an invariant the operator had to maintain by hand. The keep
15753
+ * bound is now derived from the one prebuffer ceiling and there is nothing
15754
+ * left to configure here.
15755
+ *
15756
+ * The key survives in the SHAPE so a config written before that record still
15757
+ * parses and can be migrated deliberately — `RecordingBandSchema` is not
15758
+ * strict, so simply deleting it would strip an operator's value in silence on
15759
+ * the next save (the failure D380 came one commit from shipping). Nothing
15760
+ * reads it: {@link stripRetiredBandPreBufferSec} removes it on load.
15761
+ */
15758
15762
  preBufferSec: external_exports.number().min(0).optional(),
15759
15763
  postBufferSec: external_exports.number().min(0).optional()
15760
15764
  });
15761
- var DEFAULT_EVENTS_BAND_BUFFER_SEC = {
15762
- preBufferSec: 15,
15763
- postBufferSec: 30
15764
- };
15765
+ var DEFAULT_EVENTS_BAND_BUFFER_SEC = { postBufferSec: 30 };
15765
15766
  var VISIT_MERGE_GAP_MS = DEFAULT_EVENTS_BAND_BUFFER_SEC.postBufferSec * 1e3;
15766
15767
  var RecordingRetentionSchema = external_exports.object({
15767
15768
  maxAgeDays: external_exports.number().min(0).optional(),
@@ -15786,8 +15787,29 @@ var RecordingConfigSchema = external_exports.object({
15786
15787
  * "off" is the absence of a covering band, never a band value.
15787
15788
  */
15788
15789
  bands: external_exports.array(RecordingBandSchema).default([]),
15790
+ /**
15791
+ * THE device-decided intent: record for as long as the camera itself raises
15792
+ * `recording-signal` (`active: true` while the device is in function — a
15793
+ * robot that cleans). AUTHORED, unlike `mode`, and the only authored
15794
+ * recording intent that is not a band.
15795
+ *
15796
+ * It carries NO schedule on purpose. A band is an HOUR, and this feature has
15797
+ * no hour to program: the device decides. What it costs the operator is one
15798
+ * flag — "this camera can record on its own" — and what it buys is the same
15799
+ * hold/release the recorder already implements (D371, `holdTrigger` /
15800
+ * `releaseTrigger`): the window opens on the rise, stays open for the whole
15801
+ * job however long it is, and closes one pad after the fall.
15802
+ *
15803
+ * EXCLUSIVE with `bands` (below): two authorities deciding when the same
15804
+ * camera records is the D62 failure. `off` remains `enabled: false`, so an
15805
+ * operator switching this camera off is REPORTED off, never as broken.
15806
+ */
15807
+ deviceDecision: external_exports.boolean().optional(),
15789
15808
  retention: RecordingRetentionSchema.optional()
15790
- }).strict();
15809
+ }).strict().refine((config2) => config2.deviceDecision !== true || config2.bands.length === 0, {
15810
+ message: "deviceDecision is a whole-config mode and carries no schedule: it cannot be combined with bands",
15811
+ path: ["bands"]
15812
+ });
15791
15813
  var RelocateJobStateSchema = external_exports.enum([
15792
15814
  "queued",
15793
15815
  "running",
@@ -28844,11 +28866,7 @@ var CameraAudioStatusSchema = external_exports.object({
28844
28866
  nodeId: external_exports.string(),
28845
28867
  enabled: external_exports.boolean()
28846
28868
  });
28847
- var CameraRecordingModeSchema = external_exports.enum([
28848
- "off",
28849
- "continuous",
28850
- "events"
28851
- ]);
28869
+ var CameraRecordingModeSchema = RecordingStorageModeSchema;
28852
28870
  var CameraRecordingStatusSchema = external_exports.object({
28853
28871
  mode: CameraRecordingModeSchema,
28854
28872
  active: external_exports.boolean(),
@@ -37153,11 +37171,10 @@ var rebootCapability = {
37153
37171
  var RecordingStatusSchema = external_exports.object({
37154
37172
  deviceId: external_exports.number(),
37155
37173
  enabled: external_exports.boolean(),
37156
- activeMode: external_exports.enum([
37157
- "off",
37158
- "continuous",
37159
- "events"
37160
- ]),
37174
+ /** THE derived storage mode, from the one definition
37175
+ * (`deriveRecordingMode`) — never a second enum. A duplicated list is how
37176
+ * `on-device-decision` could have reached the recorder and not the status. */
37177
+ activeMode: RecordingStorageModeSchema,
37161
37178
  nodeId: external_exports.string(),
37162
37179
  storageBytes: external_exports.number()
37163
37180
  });
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runDiscover
4
- } from "./chunk-OLHRHGNY.js";
4
+ } from "./chunk-YK6NE5VI.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-4UETVHGT.js");
41
+ await import("./launcher-YBWRBM2B.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-4UETVHGT.js");
86
+ await import("./launcher-YBWRBM2B.js");
87
87
  }
88
88
 
89
89
  // src/commands/setup.ts
@@ -1130,7 +1130,7 @@ function isUnknown(_value) {
1130
1130
  return true;
1131
1131
  }
1132
1132
  async function resolveServerInteractive(presetNamespace) {
1133
- const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-MHBOYSVK.js");
1133
+ const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-6YJTDHZO.js");
1134
1134
  if (presetNamespace) {
1135
1135
  const spinner4 = clack.spinner();
1136
1136
  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-OLHRHGNY.js";
8
+ } from "./chunk-YK6NE5VI.js";
9
9
  import "./chunk-LMMQX4CK.js";
10
10
  export {
11
11
  DEFAULT_HUB_HTTPS_PORT,
@@ -23633,9 +23633,9 @@ var require_zod = __commonJS({
23633
23633
  }
23634
23634
  });
23635
23635
 
23636
- // ../system/dist/dist-BNaW68aZ.js
23637
- var require_dist_BNaW68aZ = __commonJS({
23638
- "../system/dist/dist-BNaW68aZ.js"(exports) {
23636
+ // ../system/dist/dist-KQ5D2wqr.js
23637
+ var require_dist_KQ5D2wqr = __commonJS({
23638
+ "../system/dist/dist-KQ5D2wqr.js"(exports) {
23639
23639
  "use strict";
23640
23640
  var zod = require_zod();
23641
23641
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
@@ -26036,21 +26036,21 @@ var require_dist_BNaW68aZ = __commonJS({
26036
26036
  for (const section of sectionsOf(schema)) for (const field of fieldsOf(section)) walkField(field, keys);
26037
26037
  return keys;
26038
26038
  }
26039
- function isRecord$2(value) {
26039
+ function isRecord$3(value) {
26040
26040
  return typeof value === "object" && value !== null && !Array.isArray(value);
26041
26041
  }
26042
26042
  function sectionsOf(schema) {
26043
- if (!isRecord$2(schema)) return [];
26043
+ if (!isRecord$3(schema)) return [];
26044
26044
  const sections = schema["sections"];
26045
26045
  return Array.isArray(sections) ? sections : [];
26046
26046
  }
26047
26047
  function fieldsOf(node) {
26048
- if (!isRecord$2(node)) return [];
26048
+ if (!isRecord$3(node)) return [];
26049
26049
  const fields = node["fields"];
26050
26050
  return Array.isArray(fields) ? fields : [];
26051
26051
  }
26052
26052
  function walkField(field, out) {
26053
- if (!isRecord$2(field)) return;
26053
+ if (!isRecord$3(field)) return;
26054
26054
  const type = field["type"];
26055
26055
  const key = field["key"];
26056
26056
  if ((type === "password" || field["secret"] === true) && typeof key === "string" && key.length > 0) out.add(key);
@@ -26192,7 +26192,8 @@ var require_dist_BNaW68aZ = __commonJS({
26192
26192
  var RecordingStorageModeSchema = zod.z.enum([
26193
26193
  "off",
26194
26194
  "events",
26195
- "continuous"
26195
+ "continuous",
26196
+ "on-device-decision"
26196
26197
  ]);
26197
26198
  var RecordingObjectTriggerClassSchema = zod.z.enum(FIRST_LEVEL_MACRO_CLASSES);
26198
26199
  var noDuplicates = (values) => new Set(values).size === values.length;
@@ -26229,22 +26230,7 @@ var require_dist_BNaW68aZ = __commonJS({
26229
26230
  * il livello: un contatto trovato già aperto al riavvio del runner non fa
26230
26231
  * registrare.
26231
26232
  */
26232
- sensorDeviceIds: zod.z.array(zod.z.number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional(),
26233
- /**
26234
- * La camera registra per tutta la durata del SEGNALE che lei stessa
26235
- * pubblica — la cap `recording-signal` (`active: true` mentre il device è in
26236
- * funzione: un robot che pulisce). È un LIVELLO, non un fronte: la finestra
26237
- * resta aperta finché il segnale è alto e si chiude `postBufferSec` dopo la
26238
- * caduta, così una pulizia di quaranta minuti è UNA clip.
26239
- *
26240
- * Non nomina un device: il segnale è della camera stessa, tenuto fresco dal
26241
- * suo provider (D224); il recorder lo ascolta su `DeviceStateChanged` e lo
26242
- * riconcilia leggendo la slice via RPC, con un tetto oltre il quale un
26243
- * segnale mai abbassato (un evento perso) non può tenere aperta una
26244
- * registrazione (D11). Vedi `recorder/addon/band-decision.ts`
26245
- * (`holdTrigger` / `releaseTrigger`).
26246
- */
26247
- deviceSignal: zod.z.boolean().optional()
26233
+ sensorDeviceIds: zod.z.array(zod.z.number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
26248
26234
  });
26249
26235
  var RecordingBandModeSchema = zod.z.enum(["continuous", "events"]);
26250
26236
  var RecordingBandTriggersSchema = RecordingTriggersSchema;
@@ -26254,13 +26240,28 @@ var require_dist_BNaW68aZ = __commonJS({
26254
26240
  end: zod.z.string().regex(HHMM),
26255
26241
  mode: RecordingBandModeSchema,
26256
26242
  triggers: RecordingBandTriggersSchema.optional(),
26243
+ /**
26244
+ * RETIRED (D381). A band no longer carries a pre-buffer of its own.
26245
+ *
26246
+ * It was the retroactive KEEP bound — which already-written segments survive
26247
+ * a trigger — and it had to be at least as wide as the widest pre-roll the
26248
+ * broker could serve, or the gate would delete the seconds the ring had just
26249
+ * handed the writer. That "at least as wide as" is the tell: it was a second
26250
+ * expression of the broker's retention, in different units, in a different
26251
+ * addon, with an invariant the operator had to maintain by hand. The keep
26252
+ * bound is now derived from the one prebuffer ceiling and there is nothing
26253
+ * left to configure here.
26254
+ *
26255
+ * The key survives in the SHAPE so a config written before that record still
26256
+ * parses and can be migrated deliberately — `RecordingBandSchema` is not
26257
+ * strict, so simply deleting it would strip an operator's value in silence on
26258
+ * the next save (the failure D380 came one commit from shipping). Nothing
26259
+ * reads it: {@link stripRetiredBandPreBufferSec} removes it on load.
26260
+ */
26257
26261
  preBufferSec: zod.z.number().min(0).optional(),
26258
26262
  postBufferSec: zod.z.number().min(0).optional()
26259
26263
  });
26260
- ({
26261
- preBufferSec: 15,
26262
- postBufferSec: 30
26263
- }).postBufferSec * 1e3;
26264
+ ({ postBufferSec: 30 }).postBufferSec * 1e3;
26264
26265
  var RecordingRetentionSchema = zod.z.object({
26265
26266
  maxAgeDays: zod.z.number().min(0).optional(),
26266
26267
  maxSizeGb: zod.z.number().min(0).optional()
@@ -26284,8 +26285,29 @@ var require_dist_BNaW68aZ = __commonJS({
26284
26285
  * "off" is the absence of a covering band, never a band value.
26285
26286
  */
26286
26287
  bands: zod.z.array(RecordingBandSchema).default([]),
26288
+ /**
26289
+ * THE device-decided intent: record for as long as the camera itself raises
26290
+ * `recording-signal` (`active: true` while the device is in function — a
26291
+ * robot that cleans). AUTHORED, unlike `mode`, and the only authored
26292
+ * recording intent that is not a band.
26293
+ *
26294
+ * It carries NO schedule on purpose. A band is an HOUR, and this feature has
26295
+ * no hour to program: the device decides. What it costs the operator is one
26296
+ * flag — "this camera can record on its own" — and what it buys is the same
26297
+ * hold/release the recorder already implements (D371, `holdTrigger` /
26298
+ * `releaseTrigger`): the window opens on the rise, stays open for the whole
26299
+ * job however long it is, and closes one pad after the fall.
26300
+ *
26301
+ * EXCLUSIVE with `bands` (below): two authorities deciding when the same
26302
+ * camera records is the D62 failure. `off` remains `enabled: false`, so an
26303
+ * operator switching this camera off is REPORTED off, never as broken.
26304
+ */
26305
+ deviceDecision: zod.z.boolean().optional(),
26287
26306
  retention: RecordingRetentionSchema.optional()
26288
- }).strict();
26307
+ }).strict().refine((config) => config.deviceDecision !== true || config.bands.length === 0, {
26308
+ message: "deviceDecision is a whole-config mode and carries no schedule: it cannot be combined with bands",
26309
+ path: ["bands"]
26310
+ });
26289
26311
  var RelocateJobStateSchema = zod.z.enum([
26290
26312
  "queued",
26291
26313
  "running",
@@ -39407,11 +39429,7 @@ var require_dist_BNaW68aZ = __commonJS({
39407
39429
  nodeId: zod.z.string(),
39408
39430
  enabled: zod.z.boolean()
39409
39431
  });
39410
- var CameraRecordingModeSchema = zod.z.enum([
39411
- "off",
39412
- "continuous",
39413
- "events"
39414
- ]);
39432
+ var CameraRecordingModeSchema = RecordingStorageModeSchema;
39415
39433
  var CameraRecordingStatusSchema = zod.z.object({
39416
39434
  mode: CameraRecordingModeSchema,
39417
39435
  active: zod.z.boolean(),
@@ -47712,11 +47730,10 @@ var require_dist_BNaW68aZ = __commonJS({
47712
47730
  var RecordingStatusSchema = zod.z.object({
47713
47731
  deviceId: zod.z.number(),
47714
47732
  enabled: zod.z.boolean(),
47715
- activeMode: zod.z.enum([
47716
- "off",
47717
- "continuous",
47718
- "events"
47719
- ]),
47733
+ /** THE derived storage mode, from the one definition
47734
+ * (`deriveRecordingMode`) — never a second enum. A duplicated list is how
47735
+ * `on-device-decision` could have reached the recorder and not the status. */
47736
+ activeMode: RecordingStorageModeSchema,
47720
47737
  nodeId: zod.z.string(),
47721
47738
  storageBytes: zod.z.number()
47722
47739
  });
@@ -60658,7 +60675,7 @@ var require_alerts_addon = __commonJS({
60658
60675
  [Symbol.toStringTag]: { value: "Module" }
60659
60676
  });
60660
60677
  require_chunk_Cek0wNdY();
60661
- var require_dist10 = require_dist_BNaW68aZ();
60678
+ var require_dist10 = require_dist_KQ5D2wqr();
60662
60679
  function selectExpired(alerts, cutoffMs) {
60663
60680
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
60664
60681
  }
@@ -61477,7 +61494,7 @@ var require_console_logging = __commonJS({
61477
61494
  [Symbol.toStringTag]: { value: "Module" }
61478
61495
  });
61479
61496
  require_chunk_Cek0wNdY();
61480
- var require_dist10 = require_dist_BNaW68aZ();
61497
+ var require_dist10 = require_dist_KQ5D2wqr();
61481
61498
  var require_formatter = require_formatter_DqAKDlvN();
61482
61499
  var LEVEL_RANK = {
61483
61500
  debug: 0,
@@ -61571,7 +61588,7 @@ var require_core_blocks_addon = __commonJS({
61571
61588
  "use strict";
61572
61589
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
61573
61590
  var require_chunk = require_chunk_Cek0wNdY();
61574
- var require_dist10 = require_dist_BNaW68aZ();
61591
+ var require_dist10 = require_dist_KQ5D2wqr();
61575
61592
  var node_crypto = __require("crypto");
61576
61593
  var node_fs_promises = __require("fs/promises");
61577
61594
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -62468,11 +62485,11 @@ var require_core_blocks = __commonJS({
62468
62485
  }
62469
62486
  });
62470
62487
 
62471
- // ../system/dist/retired-settings-keys-FwgzdSHJ.js
62472
- var require_retired_settings_keys_FwgzdSHJ = __commonJS({
62473
- "../system/dist/retired-settings-keys-FwgzdSHJ.js"(exports) {
62488
+ // ../system/dist/retired-settings-keys-2lWk7OeU.js
62489
+ var require_retired_settings_keys_2lWk7OeU = __commonJS({
62490
+ "../system/dist/retired-settings-keys-2lWk7OeU.js"(exports) {
62474
62491
  "use strict";
62475
- var require_dist10 = require_dist_BNaW68aZ();
62492
+ var require_dist10 = require_dist_KQ5D2wqr();
62476
62493
  function settingsStoreIsAuthoritativeHere(env) {
62477
62494
  const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
62478
62495
  return raw === "" || raw === "hub";
@@ -64686,8 +64703,8 @@ var require_device_manager_addon = __commonJS({
64686
64703
  [Symbol.toStringTag]: { value: "Module" }
64687
64704
  });
64688
64705
  require_chunk_Cek0wNdY();
64689
- var require_dist10 = require_dist_BNaW68aZ();
64690
- var require_retired_settings_keys = require_retired_settings_keys_FwgzdSHJ();
64706
+ var require_dist10 = require_dist_KQ5D2wqr();
64707
+ var require_retired_settings_keys = require_retired_settings_keys_2lWk7OeU();
64691
64708
  var node_crypto = __require("crypto");
64692
64709
  var _camstack_types_node = require_node();
64693
64710
  var JOB_HISTORY = 20;
@@ -70312,7 +70329,7 @@ var require_hub_forwarder = __commonJS({
70312
70329
  [Symbol.toStringTag]: { value: "Module" }
70313
70330
  });
70314
70331
  require_chunk_Cek0wNdY();
70315
- var require_dist10 = require_dist_BNaW68aZ();
70332
+ var require_dist10 = require_dist_KQ5D2wqr();
70316
70333
  var require_formatter = require_formatter_DqAKDlvN();
70317
70334
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
70318
70335
  var HubForwarderDestination = class {
@@ -70449,7 +70466,7 @@ var require_liveness_monitor_addon = __commonJS({
70449
70466
  "use strict";
70450
70467
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
70451
70468
  require_chunk_Cek0wNdY();
70452
- var require_dist10 = require_dist_BNaW68aZ();
70469
+ var require_dist10 = require_dist_KQ5D2wqr();
70453
70470
  var NO_DEVICES = "liveness:no-devices";
70454
70471
  var ALL_OFFLINE = "liveness:all-devices-offline";
70455
70472
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -70645,7 +70662,7 @@ var require_local_auth_addon = __commonJS({
70645
70662
  [Symbol.toStringTag]: { value: "Module" }
70646
70663
  });
70647
70664
  var require_chunk = require_chunk_Cek0wNdY();
70648
- var require_dist10 = require_dist_BNaW68aZ();
70665
+ var require_dist10 = require_dist_KQ5D2wqr();
70649
70666
  var node_crypto = __require("crypto");
70650
70667
  node_crypto = require_chunk.__toESM(node_crypto);
70651
70668
  var crypto$1 = __require("crypto");
@@ -78458,7 +78475,7 @@ var require_loki_logging = __commonJS({
78458
78475
  [Symbol.toStringTag]: { value: "Module" }
78459
78476
  });
78460
78477
  require_chunk_Cek0wNdY();
78461
- var require_dist10 = require_dist_BNaW68aZ();
78478
+ var require_dist10 = require_dist_KQ5D2wqr();
78462
78479
  function sanitizeLabelName(raw) {
78463
78480
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
78464
78481
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -79023,7 +79040,7 @@ var require_native_metrics_addon = __commonJS({
79023
79040
  [Symbol.toStringTag]: { value: "Module" }
79024
79041
  });
79025
79042
  var require_chunk = require_chunk_Cek0wNdY();
79026
- var require_dist10 = require_dist_BNaW68aZ();
79043
+ var require_dist10 = require_dist_KQ5D2wqr();
79027
79044
  var node_fs_promises = __require("fs/promises");
79028
79045
  var node_child_process = __require("child_process");
79029
79046
  var node_util = __require("util");
@@ -81607,7 +81624,7 @@ var require_filesystem_storage_addon = __commonJS({
81607
81624
  [Symbol.toStringTag]: { value: "Module" }
81608
81625
  });
81609
81626
  var require_chunk = require_chunk_Cek0wNdY();
81610
- var require_dist10 = require_dist_BNaW68aZ();
81627
+ var require_dist10 = require_dist_KQ5D2wqr();
81611
81628
  var node_crypto = __require("crypto");
81612
81629
  var node_fs_promises = __require("fs/promises");
81613
81630
  var node_path = __require("path");
@@ -82723,8 +82740,8 @@ var require_sqlite_settings_addon = __commonJS({
82723
82740
  [Symbol.toStringTag]: { value: "Module" }
82724
82741
  });
82725
82742
  var require_chunk = require_chunk_Cek0wNdY();
82726
- var require_dist10 = require_dist_BNaW68aZ();
82727
- var require_retired_settings_keys = require_retired_settings_keys_FwgzdSHJ();
82743
+ var require_dist10 = require_dist_KQ5D2wqr();
82744
+ var require_retired_settings_keys = require_retired_settings_keys_2lWk7OeU();
82728
82745
  var node_crypto = __require("crypto");
82729
82746
  var node_fs = __require("fs");
82730
82747
  var node_module = __require("module");
@@ -85214,7 +85231,7 @@ var require_storage_orchestrator_addon = __commonJS({
85214
85231
  [Symbol.toStringTag]: { value: "Module" }
85215
85232
  });
85216
85233
  var require_chunk = require_chunk_Cek0wNdY();
85217
- var require_dist10 = require_dist_BNaW68aZ();
85234
+ var require_dist10 = require_dist_KQ5D2wqr();
85218
85235
  var require_hub_cap_forward = require_hub_cap_forward_DmHNjbB0();
85219
85236
  var zod = require_zod();
85220
85237
  var node_crypto = __require("crypto");
@@ -88165,7 +88182,7 @@ var require_system_config_addon = __commonJS({
88165
88182
  [Symbol.toStringTag]: { value: "Module" }
88166
88183
  });
88167
88184
  require_chunk_Cek0wNdY();
88168
- var require_dist10 = require_dist_BNaW68aZ();
88185
+ var require_dist10 = require_dist_KQ5D2wqr();
88169
88186
  var SECTION_TITLES = {
88170
88187
  server: "Server",
88171
88188
  auth: "Authentication"
@@ -106226,7 +106243,7 @@ var require_winston_logging = __commonJS({
106226
106243
  [Symbol.toStringTag]: { value: "Module" }
106227
106244
  });
106228
106245
  var require_chunk = require_chunk_Cek0wNdY();
106229
- var require_dist10 = require_dist_BNaW68aZ();
106246
+ var require_dist10 = require_dist_KQ5D2wqr();
106230
106247
  var require_formatter = require_formatter_DqAKDlvN();
106231
106248
  var node_path = __require("path");
106232
106249
  node_path = require_chunk.__toESM(node_path);
@@ -108170,9 +108187,9 @@ var require_event_category_b8kBSOTT = __commonJS({
108170
108187
  }
108171
108188
  });
108172
108189
 
108173
- // ../types/dist/sleep-BGiOgxye.js
108174
- var require_sleep_BGiOgxye = __commonJS({
108175
- "../types/dist/sleep-BGiOgxye.js"(exports) {
108190
+ // ../types/dist/sleep-DDIFZGbc.js
108191
+ var require_sleep_DDIFZGbc = __commonJS({
108192
+ "../types/dist/sleep-DDIFZGbc.js"(exports) {
108176
108193
  "use strict";
108177
108194
  var require_event_category = require_event_category_b8kBSOTT();
108178
108195
  var zod = require_zod();
@@ -111299,6 +111316,7 @@ var require_sleep_BGiOgxye = __commonJS({
111299
111316
  "ptz",
111300
111317
  "ptz-autotrack",
111301
111318
  "reboot",
111319
+ "recording-signal",
111302
111320
  "scene-monitor",
111303
111321
  "script-runner",
111304
111322
  "smoke",
@@ -111903,7 +111921,7 @@ var require_addon = __commonJS({
111903
111921
  "use strict";
111904
111922
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
111905
111923
  var require_event_category = require_event_category_b8kBSOTT();
111906
- var require_sleep = require_sleep_BGiOgxye();
111924
+ var require_sleep = require_sleep_DDIFZGbc();
111907
111925
  var require_err_msg = require_err_msg_COpsHMw2();
111908
111926
  var CAP_INPUT_DEFAULTS = Object.freeze({
111909
111927
  "addons": { "getLogs": { "limit": 100 } },
@@ -130863,7 +130881,7 @@ var require_dist3 = __commonJS({
130863
130881
  "use strict";
130864
130882
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
130865
130883
  var require_chunk = require_chunk_Cek0wNdY();
130866
- var require_dist10 = require_dist_BNaW68aZ();
130884
+ var require_dist10 = require_dist_KQ5D2wqr();
130867
130885
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
130868
130886
  require_alerts();
130869
130887
  var require_formatter = require_formatter_DqAKDlvN();
@@ -211980,7 +211998,7 @@ var require_dist4 = __commonJS({
211980
211998
  "use strict";
211981
211999
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
211982
212000
  var require_event_category = require_event_category_b8kBSOTT();
211983
- var require_sleep = require_sleep_BGiOgxye();
212001
+ var require_sleep = require_sleep_DDIFZGbc();
211984
212002
  var require_canonical_hash = require_canonical_hash_DNV8S5ET();
211985
212003
  var require_enums2 = require_enums();
211986
212004
  var require_err_msg = require_err_msg_COpsHMw2();
@@ -212705,21 +212723,21 @@ var require_dist4 = __commonJS({
212705
212723
  for (const section of sectionsOf(schema)) if (fieldsOf(section).length > 0) return true;
212706
212724
  return false;
212707
212725
  }
212708
- function isRecord$2(value) {
212726
+ function isRecord$3(value) {
212709
212727
  return typeof value === "object" && value !== null && !Array.isArray(value);
212710
212728
  }
212711
212729
  function sectionsOf(schema) {
212712
- if (!isRecord$2(schema)) return [];
212730
+ if (!isRecord$3(schema)) return [];
212713
212731
  const sections = schema["sections"];
212714
212732
  return Array.isArray(sections) ? sections : [];
212715
212733
  }
212716
212734
  function fieldsOf(node) {
212717
- if (!isRecord$2(node)) return [];
212735
+ if (!isRecord$3(node)) return [];
212718
212736
  const fields = node["fields"];
212719
212737
  return Array.isArray(fields) ? fields : [];
212720
212738
  }
212721
212739
  function walkField(field, out) {
212722
- if (!isRecord$2(field)) return;
212740
+ if (!isRecord$3(field)) return;
212723
212741
  const type = field["type"];
212724
212742
  const key = field["key"];
212725
212743
  if ((type === "password" || field["secret"] === true) && typeof key === "string" && key.length > 0) out.add(key);
@@ -212787,12 +212805,12 @@ var require_dist4 = __commonJS({
212787
212805
  function isString2(v) {
212788
212806
  return typeof v === "string";
212789
212807
  }
212790
- function isRecord$1(v) {
212808
+ function isRecord$2(v) {
212791
212809
  return typeof v === "object" && v !== null && !Array.isArray(v);
212792
212810
  }
212793
212811
  function parseStreamEntry(v) {
212794
212812
  if (isString2(v) && v.trim()) return { url: v };
212795
- if (isRecord$1(v) && isString2(v["url"]) && v["url"].trim()) return {
212813
+ if (isRecord$2(v) && isString2(v["url"]) && v["url"].trim()) return {
212796
212814
  url: v["url"],
212797
212815
  label: isString2(v["label"]) ? v["label"] : void 0
212798
212816
  };
@@ -213197,7 +213215,8 @@ var require_dist4 = __commonJS({
213197
213215
  var RecordingStorageModeSchema = zod.z.enum([
213198
213216
  "off",
213199
213217
  "events",
213200
- "continuous"
213218
+ "continuous",
213219
+ "on-device-decision"
213201
213220
  ]);
213202
213221
  var RecordingObjectTriggerClassSchema = zod.z.enum(FIRST_LEVEL_MACRO_CLASSES);
213203
213222
  var noDuplicates = (values) => new Set(values).size === values.length;
@@ -213235,22 +213254,7 @@ var require_dist4 = __commonJS({
213235
213254
  * il livello: un contatto trovato già aperto al riavvio del runner non fa
213236
213255
  * registrare.
213237
213256
  */
213238
- sensorDeviceIds: zod.z.array(zod.z.number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional(),
213239
- /**
213240
- * La camera registra per tutta la durata del SEGNALE che lei stessa
213241
- * pubblica — la cap `recording-signal` (`active: true` mentre il device è in
213242
- * funzione: un robot che pulisce). È un LIVELLO, non un fronte: la finestra
213243
- * resta aperta finché il segnale è alto e si chiude `postBufferSec` dopo la
213244
- * caduta, così una pulizia di quaranta minuti è UNA clip.
213245
- *
213246
- * Non nomina un device: il segnale è della camera stessa, tenuto fresco dal
213247
- * suo provider (D224); il recorder lo ascolta su `DeviceStateChanged` e lo
213248
- * riconcilia leggendo la slice via RPC, con un tetto oltre il quale un
213249
- * segnale mai abbassato (un evento perso) non può tenere aperta una
213250
- * registrazione (D11). Vedi `recorder/addon/band-decision.ts`
213251
- * (`holdTrigger` / `releaseTrigger`).
213252
- */
213253
- deviceSignal: zod.z.boolean().optional()
213257
+ sensorDeviceIds: zod.z.array(zod.z.number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
213254
213258
  });
213255
213259
  var RecordingBandModeSchema = zod.z.enum(["continuous", "events"]);
213256
213260
  var RecordingBandTriggersSchema = RecordingTriggersSchema;
@@ -213260,13 +213264,48 @@ var require_dist4 = __commonJS({
213260
213264
  end: zod.z.string().regex(HHMM),
213261
213265
  mode: RecordingBandModeSchema,
213262
213266
  triggers: RecordingBandTriggersSchema.optional(),
213267
+ /**
213268
+ * RETIRED (D381). A band no longer carries a pre-buffer of its own.
213269
+ *
213270
+ * It was the retroactive KEEP bound — which already-written segments survive
213271
+ * a trigger — and it had to be at least as wide as the widest pre-roll the
213272
+ * broker could serve, or the gate would delete the seconds the ring had just
213273
+ * handed the writer. That "at least as wide as" is the tell: it was a second
213274
+ * expression of the broker's retention, in different units, in a different
213275
+ * addon, with an invariant the operator had to maintain by hand. The keep
213276
+ * bound is now derived from the one prebuffer ceiling and there is nothing
213277
+ * left to configure here.
213278
+ *
213279
+ * The key survives in the SHAPE so a config written before that record still
213280
+ * parses and can be migrated deliberately — `RecordingBandSchema` is not
213281
+ * strict, so simply deleting it would strip an operator's value in silence on
213282
+ * the next save (the failure D380 came one commit from shipping). Nothing
213283
+ * reads it: {@link stripRetiredBandPreBufferSec} removes it on load.
213284
+ */
213263
213285
  preBufferSec: zod.z.number().min(0).optional(),
213264
213286
  postBufferSec: zod.z.number().min(0).optional()
213265
213287
  });
213266
- var DEFAULT_EVENTS_BAND_BUFFER_SEC = {
213267
- preBufferSec: 15,
213268
- postBufferSec: 30
213269
- };
213288
+ var DEFAULT_EVENTS_BAND_BUFFER_SEC = { postBufferSec: 30 };
213289
+ function stripRetiredBandPreBufferSec(config) {
213290
+ const strippedBands = [];
213291
+ const bands = config.bands.map((band, index) => {
213292
+ if (band.preBufferSec === void 0) return band;
213293
+ strippedBands.push(index);
213294
+ const { preBufferSec: _retired, ...rest } = band;
213295
+ return rest;
213296
+ });
213297
+ if (strippedBands.length === 0) return {
213298
+ config,
213299
+ strippedBands
213300
+ };
213301
+ return {
213302
+ config: {
213303
+ ...config,
213304
+ bands
213305
+ },
213306
+ strippedBands
213307
+ };
213308
+ }
213270
213309
  var VISIT_MERGE_GAP_MS = DEFAULT_EVENTS_BAND_BUFFER_SEC.postBufferSec * 1e3;
213271
213310
  var RecordingRetentionSchema = zod.z.object({
213272
213311
  maxAgeDays: zod.z.number().min(0).optional(),
@@ -213291,10 +213330,33 @@ var require_dist4 = __commonJS({
213291
213330
  * "off" is the absence of a covering band, never a band value.
213292
213331
  */
213293
213332
  bands: zod.z.array(RecordingBandSchema).default([]),
213333
+ /**
213334
+ * THE device-decided intent: record for as long as the camera itself raises
213335
+ * `recording-signal` (`active: true` while the device is in function — a
213336
+ * robot that cleans). AUTHORED, unlike `mode`, and the only authored
213337
+ * recording intent that is not a band.
213338
+ *
213339
+ * It carries NO schedule on purpose. A band is an HOUR, and this feature has
213340
+ * no hour to program: the device decides. What it costs the operator is one
213341
+ * flag — "this camera can record on its own" — and what it buys is the same
213342
+ * hold/release the recorder already implements (D371, `holdTrigger` /
213343
+ * `releaseTrigger`): the window opens on the rise, stays open for the whole
213344
+ * job however long it is, and closes one pad after the fall.
213345
+ *
213346
+ * EXCLUSIVE with `bands` (below): two authorities deciding when the same
213347
+ * camera records is the D62 failure. `off` remains `enabled: false`, so an
213348
+ * operator switching this camera off is REPORTED off, never as broken.
213349
+ */
213350
+ deviceDecision: zod.z.boolean().optional(),
213294
213351
  retention: RecordingRetentionSchema.optional()
213295
- }).strict();
213352
+ }).strict().refine((config) => config.deviceDecision !== true || config.bands.length === 0, {
213353
+ message: "deviceDecision is a whole-config mode and carries no schedule: it cannot be combined with bands",
213354
+ path: ["bands"]
213355
+ });
213296
213356
  function deriveRecordingMode(config) {
213297
- if (!config.enabled || config.bands.length === 0) return "off";
213357
+ if (!config.enabled) return "off";
213358
+ if (config.deviceDecision === true) return "on-device-decision";
213359
+ if (config.bands.length === 0) return "off";
213298
213360
  if (config.bands.some((band) => band.mode === "continuous")) return "continuous";
213299
213361
  return "events";
213300
213362
  }
@@ -213307,6 +213369,67 @@ var require_dist4 = __commonJS({
213307
213369
  const preferred = assigned.filter((profile) => DEFAULT_RECORDING_PROFILES.includes(profile));
213308
213370
  return preferred.length > 0 ? preferred : [...assigned];
213309
213371
  }
213372
+ var SURVIVING_TRIGGER_KEYS = [
213373
+ "motion",
213374
+ "audioThresholdDbfs",
213375
+ "objectClasses",
213376
+ "sensorDeviceIds"
213377
+ ];
213378
+ function isRecord$1(value) {
213379
+ return typeof value === "object" && value !== null && !Array.isArray(value);
213380
+ }
213381
+ function listensToLegacySignal(band) {
213382
+ return isRecord$1(band) && isRecord$1(band.triggers) && band.triggers.deviceSignal === true;
213383
+ }
213384
+ function hasSurvivingTrigger(band) {
213385
+ const triggers = band.triggers;
213386
+ if (!isRecord$1(triggers)) return false;
213387
+ return SURVIVING_TRIGGER_KEYS.some((key) => triggers[key] !== void 0);
213388
+ }
213389
+ function withoutLegacySignal(band) {
213390
+ const triggers = band.triggers;
213391
+ if (!isRecord$1(triggers)) return band;
213392
+ const { deviceSignal: _retired, ...rest } = triggers;
213393
+ return {
213394
+ ...band,
213395
+ triggers: rest
213396
+ };
213397
+ }
213398
+ function migrateLegacyDeviceSignalConfig(raw) {
213399
+ const unchanged = {
213400
+ value: raw,
213401
+ migrated: false,
213402
+ strippedOnly: false
213403
+ };
213404
+ if (!isRecord$1(raw) || !Array.isArray(raw.bands)) return unchanged;
213405
+ if (!raw.bands.some(listensToLegacySignal)) return unchanged;
213406
+ const kept = [];
213407
+ for (const band of raw.bands) {
213408
+ if (!listensToLegacySignal(band) || !isRecord$1(band)) {
213409
+ kept.push(band);
213410
+ continue;
213411
+ }
213412
+ if (hasSurvivingTrigger(band)) kept.push(withoutLegacySignal(band));
213413
+ }
213414
+ if (kept.length > 0) return {
213415
+ value: {
213416
+ ...raw,
213417
+ bands: kept
213418
+ },
213419
+ migrated: false,
213420
+ strippedOnly: true
213421
+ };
213422
+ const { mode: _derived, ...rest } = raw;
213423
+ return {
213424
+ value: {
213425
+ ...rest,
213426
+ bands: [],
213427
+ deviceDecision: true
213428
+ },
213429
+ migrated: true,
213430
+ strippedOnly: false
213431
+ };
213432
+ }
213310
213433
  var RelocateJobStateSchema = zod.z.enum([
213311
213434
  "queued",
213312
213435
  "running",
@@ -228556,11 +228679,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
228556
228679
  nodeId: zod.z.string(),
228557
228680
  enabled: zod.z.boolean()
228558
228681
  });
228559
- var CameraRecordingModeSchema = zod.z.enum([
228560
- "off",
228561
- "continuous",
228562
- "events"
228563
- ]);
228682
+ var CameraRecordingModeSchema = RecordingStorageModeSchema;
228564
228683
  var CameraRecordingStatusSchema = zod.z.object({
228565
228684
  mode: CameraRecordingModeSchema,
228566
228685
  active: zod.z.boolean(),
@@ -237030,11 +237149,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
237030
237149
  var RecordingStatusSchema = zod.z.object({
237031
237150
  deviceId: zod.z.number(),
237032
237151
  enabled: zod.z.boolean(),
237033
- activeMode: zod.z.enum([
237034
- "off",
237035
- "continuous",
237036
- "events"
237037
- ]),
237152
+ /** THE derived storage mode, from the one definition
237153
+ * (`deriveRecordingMode`) — never a second enum. A duplicated list is how
237154
+ * `on-device-decision` could have reached the recorder and not the status. */
237155
+ activeMode: RecordingStorageModeSchema,
237038
237156
  nodeId: zod.z.string(),
237039
237157
  storageBytes: zod.z.number()
237040
237158
  });
@@ -257320,6 +257438,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257320
257438
  exports.method = require_sleep.method;
257321
257439
  exports.methodAccessForHttpMethod = methodAccessForHttpMethod;
257322
257440
  exports.metricsProviderCapability = metricsProviderCapability;
257441
+ exports.migrateLegacyDeviceSignalConfig = migrateLegacyDeviceSignalConfig;
257323
257442
  exports.modelConvertCapability = modelConvertCapability;
257324
257443
  exports.modelDistributorCapability = modelDistributorCapability;
257325
257444
  exports.modelFormatForRuntime = modelFormatForRuntime;
@@ -257467,6 +257586,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257467
257586
  exports.streamParamsCapability = streamParamsCapability;
257468
257587
  exports.streamPixels = streamPixels;
257469
257588
  exports.streamQualityLabel = streamQualityLabel;
257589
+ exports.stripRetiredBandPreBufferSec = stripRetiredBandPreBufferSec;
257470
257590
  exports.subKindsOf = subKindsOf;
257471
257591
  exports.summarisePrivacyAudio = summarisePrivacyAudio;
257472
257592
  exports.summarizeEffectiveScope = summarizeEffectiveScope;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "camstack",
3
- "version": "1.2.108",
3
+ "version": "1.2.110",
4
4
  "description": "CLI tool for managing and running CamStack server",
5
5
  "keywords": [
6
6
  "camstack",