camstack 1.2.69 → 1.2.70

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-DcA-CgqX.mjs
14525
+ // ../types/dist/sleep-BBI0PDUc.mjs
14526
14526
  var WELL_KNOWN_TABS = [
14527
14527
  {
14528
14528
  id: "overview",
@@ -26591,6 +26591,39 @@ var RebuildStatusSchema = external_exports.object({
26591
26591
  /** Present when the pass ended by throwing. */
26592
26592
  error: external_exports.string().nullable()
26593
26593
  });
26594
+ var MediaReclaimStartResultSchema = external_exports.object({
26595
+ started: external_exports.boolean(),
26596
+ /** True when a pass was already running; the new request is ignored. */
26597
+ alreadyRunning: external_exports.boolean()
26598
+ });
26599
+ var MediaReclaimInputSchema = external_exports.object({
26600
+ mode: external_exports.enum(["report", "reclaim"]).default("report"),
26601
+ scopes: external_exports.array(external_exports.enum(["motion-still", "track-filmstrip"])).min(1).optional(),
26602
+ deviceIds: external_exports.array(external_exports.number().int()).min(1).optional(),
26603
+ restart: external_exports.boolean().optional(),
26604
+ pageSize: external_exports.number().int().min(50).max(5e3).optional(),
26605
+ maxRowsPerDevice: external_exports.number().int().min(1).max(5e5).optional(),
26606
+ maxReclaimPerDevice: external_exports.number().int().min(1).max(5e5).optional(),
26607
+ maxBytesPerRun: external_exports.number().int().min(1).optional(),
26608
+ budgetMinutes: external_exports.number().int().min(1).max(720).optional(),
26609
+ throttleBytesPerSec: external_exports.number().int().min(64 * 1024).optional(),
26610
+ graceMinutes: external_exports.number().int().min(1).max(10080).optional()
26611
+ });
26612
+ var MediaReclaimStatusSchema = external_exports.object({
26613
+ running: external_exports.boolean(),
26614
+ mode: external_exports.enum(["report", "reclaim"]).nullable(),
26615
+ totalExamined: external_exports.number(),
26616
+ totalEligible: external_exports.number(),
26617
+ totalReclaimed: external_exports.number(),
26618
+ totalBytesReclaimed: external_exports.number(),
26619
+ totalRefused: external_exports.number(),
26620
+ /** Device+scope windows finished in this pass. */
26621
+ devicesDone: external_exports.number(),
26622
+ complete: external_exports.boolean().nullable(),
26623
+ startedAtMs: external_exports.number().nullable(),
26624
+ finishedAtMs: external_exports.number().nullable(),
26625
+ error: external_exports.string().nullable()
26626
+ });
26594
26627
  var ReplayFrameInputSchema = external_exports.object({
26595
26628
  timestamp: external_exports.number(),
26596
26629
  frame: PipelineRunResultBridge
@@ -27014,6 +27047,20 @@ var pipelineAnalyticsCapability = {
27014
27047
  auth: "admin"
27015
27048
  }),
27016
27049
  /**
27050
+ * Reclaim the standing debug-media backlog (motion-visit stills + track
27051
+ * filmstrips). DETACHED: returns `{ started }` immediately. The pass is
27052
+ * tens of minutes; awaiting it is a timeout, not a verdict. Dry-run unless
27053
+ * `mode: 'reclaim'`. Poll `getMediaReclaimStatus`.
27054
+ */
27055
+ reclaimDebugMedia: method(MediaReclaimInputSchema, MediaReclaimStartResultSchema, {
27056
+ kind: "mutation",
27057
+ auth: "admin"
27058
+ }),
27059
+ getMediaReclaimStatus: method(external_exports.object({}), MediaReclaimStatusSchema, {
27060
+ kind: "query",
27061
+ auth: "admin"
27062
+ }),
27063
+ /**
27017
27064
  * The CHEAP QUESTION, asked before any media moves: how big is the dataset
27018
27065
  * the marked (`markForTrain`) tracks would produce?
27019
27066
  *
@@ -42203,6 +42250,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
42203
42250
  addonId: null,
42204
42251
  access: "view"
42205
42252
  },
42253
+ "pipelineAnalytics.getMediaReclaimStatus": {
42254
+ capName: "pipeline-analytics",
42255
+ capScope: "device",
42256
+ addonId: null,
42257
+ access: "view"
42258
+ },
42206
42259
  "pipelineAnalytics.getMotionEvents": {
42207
42260
  capName: "pipeline-analytics",
42208
42261
  capScope: "device",
@@ -42377,6 +42430,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
42377
42430
  addonId: null,
42378
42431
  access: "create"
42379
42432
  },
42433
+ "pipelineAnalytics.reclaimDebugMedia": {
42434
+ capName: "pipeline-analytics",
42435
+ capScope: "device",
42436
+ addonId: null,
42437
+ access: "create"
42438
+ },
42380
42439
  "pipelineAnalytics.reconcileFromDisk": {
42381
42440
  capName: "pipeline-analytics",
42382
42441
  capScope: "device",
@@ -45993,6 +46052,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
45993
46052
  form: "single",
45994
46053
  optional: true
45995
46054
  }],
46055
+ "pipelineAnalytics.reclaimDebugMedia": [{
46056
+ name: "deviceIds",
46057
+ form: "array",
46058
+ optional: true
46059
+ }],
45996
46060
  "pipelineAnalytics.reconcileFromDisk": [{
45997
46061
  name: "deviceId",
45998
46062
  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-VBTD2AIS.js";
4
+ } from "./chunk-45XQKO4Y.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-INC5TETK.js");
41
+ await import("./launcher-E2VZZ5O3.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-INC5TETK.js");
86
+ await import("./launcher-E2VZZ5O3.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-4S4WTMPM.js");
1133
+ const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-KE6GFVKY.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-VBTD2AIS.js";
8
+ } from "./chunk-45XQKO4Y.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-B29Skpzo.js
23637
- var require_dist_B29Skpzo = __commonJS({
23638
- "../system/dist/dist-B29Skpzo.js"(exports) {
23636
+ // ../system/dist/dist-BhE8zNfY.js
23637
+ var require_dist_BhE8zNfY = __commonJS({
23638
+ "../system/dist/dist-BhE8zNfY.js"(exports) {
23639
23639
  "use strict";
23640
23640
  var zod = require_zod();
23641
23641
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
@@ -37286,6 +37286,39 @@ var require_dist_B29Skpzo = __commonJS({
37286
37286
  /** Present when the pass ended by throwing. */
37287
37287
  error: zod.z.string().nullable()
37288
37288
  });
37289
+ var MediaReclaimStartResultSchema = zod.z.object({
37290
+ started: zod.z.boolean(),
37291
+ /** True when a pass was already running; the new request is ignored. */
37292
+ alreadyRunning: zod.z.boolean()
37293
+ });
37294
+ var MediaReclaimInputSchema = zod.z.object({
37295
+ mode: zod.z.enum(["report", "reclaim"]).default("report"),
37296
+ scopes: zod.z.array(zod.z.enum(["motion-still", "track-filmstrip"])).min(1).optional(),
37297
+ deviceIds: zod.z.array(zod.z.number().int()).min(1).optional(),
37298
+ restart: zod.z.boolean().optional(),
37299
+ pageSize: zod.z.number().int().min(50).max(5e3).optional(),
37300
+ maxRowsPerDevice: zod.z.number().int().min(1).max(5e5).optional(),
37301
+ maxReclaimPerDevice: zod.z.number().int().min(1).max(5e5).optional(),
37302
+ maxBytesPerRun: zod.z.number().int().min(1).optional(),
37303
+ budgetMinutes: zod.z.number().int().min(1).max(720).optional(),
37304
+ throttleBytesPerSec: zod.z.number().int().min(64 * 1024).optional(),
37305
+ graceMinutes: zod.z.number().int().min(1).max(10080).optional()
37306
+ });
37307
+ var MediaReclaimStatusSchema = zod.z.object({
37308
+ running: zod.z.boolean(),
37309
+ mode: zod.z.enum(["report", "reclaim"]).nullable(),
37310
+ totalExamined: zod.z.number(),
37311
+ totalEligible: zod.z.number(),
37312
+ totalReclaimed: zod.z.number(),
37313
+ totalBytesReclaimed: zod.z.number(),
37314
+ totalRefused: zod.z.number(),
37315
+ /** Device+scope windows finished in this pass. */
37316
+ devicesDone: zod.z.number(),
37317
+ complete: zod.z.boolean().nullable(),
37318
+ startedAtMs: zod.z.number().nullable(),
37319
+ finishedAtMs: zod.z.number().nullable(),
37320
+ error: zod.z.string().nullable()
37321
+ });
37289
37322
  var ReplayFrameInputSchema = zod.z.object({
37290
37323
  timestamp: zod.z.number(),
37291
37324
  frame: PipelineRunResultBridge
@@ -37709,6 +37742,20 @@ var require_dist_B29Skpzo = __commonJS({
37709
37742
  auth: "admin"
37710
37743
  }),
37711
37744
  /**
37745
+ * Reclaim the standing debug-media backlog (motion-visit stills + track
37746
+ * filmstrips). DETACHED: returns `{ started }` immediately. The pass is
37747
+ * tens of minutes; awaiting it is a timeout, not a verdict. Dry-run unless
37748
+ * `mode: 'reclaim'`. Poll `getMediaReclaimStatus`.
37749
+ */
37750
+ reclaimDebugMedia: method(MediaReclaimInputSchema, MediaReclaimStartResultSchema, {
37751
+ kind: "mutation",
37752
+ auth: "admin"
37753
+ }),
37754
+ getMediaReclaimStatus: method(zod.z.object({}), MediaReclaimStatusSchema, {
37755
+ kind: "query",
37756
+ auth: "admin"
37757
+ }),
37758
+ /**
37712
37759
  * The CHEAP QUESTION, asked before any media moves: how big is the dataset
37713
37760
  * the marked (`markForTrain`) tracks would produce?
37714
37761
  *
@@ -53519,6 +53566,12 @@ var require_dist_B29Skpzo = __commonJS({
53519
53566
  addonId: null,
53520
53567
  access: "view"
53521
53568
  },
53569
+ "pipelineAnalytics.getMediaReclaimStatus": {
53570
+ capName: "pipeline-analytics",
53571
+ capScope: "device",
53572
+ addonId: null,
53573
+ access: "view"
53574
+ },
53522
53575
  "pipelineAnalytics.getMotionEvents": {
53523
53576
  capName: "pipeline-analytics",
53524
53577
  capScope: "device",
@@ -53693,6 +53746,12 @@ var require_dist_B29Skpzo = __commonJS({
53693
53746
  addonId: null,
53694
53747
  access: "create"
53695
53748
  },
53749
+ "pipelineAnalytics.reclaimDebugMedia": {
53750
+ capName: "pipeline-analytics",
53751
+ capScope: "device",
53752
+ addonId: null,
53753
+ access: "create"
53754
+ },
53696
53755
  "pipelineAnalytics.reconcileFromDisk": {
53697
53756
  capName: "pipeline-analytics",
53698
53757
  capScope: "device",
@@ -57309,6 +57368,11 @@ var require_dist_B29Skpzo = __commonJS({
57309
57368
  form: "single",
57310
57369
  optional: true
57311
57370
  }],
57371
+ "pipelineAnalytics.reclaimDebugMedia": [{
57372
+ name: "deviceIds",
57373
+ form: "array",
57374
+ optional: true
57375
+ }],
57312
57376
  "pipelineAnalytics.reconcileFromDisk": [{
57313
57377
  name: "deviceId",
57314
57378
  form: "single",
@@ -59418,7 +59482,7 @@ var require_alerts_addon = __commonJS({
59418
59482
  [Symbol.toStringTag]: { value: "Module" }
59419
59483
  });
59420
59484
  require_chunk_Cek0wNdY();
59421
- var require_dist10 = require_dist_B29Skpzo();
59485
+ var require_dist10 = require_dist_BhE8zNfY();
59422
59486
  function selectExpired(alerts, cutoffMs) {
59423
59487
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
59424
59488
  }
@@ -60237,7 +60301,7 @@ var require_console_logging = __commonJS({
60237
60301
  [Symbol.toStringTag]: { value: "Module" }
60238
60302
  });
60239
60303
  require_chunk_Cek0wNdY();
60240
- var require_dist10 = require_dist_B29Skpzo();
60304
+ var require_dist10 = require_dist_BhE8zNfY();
60241
60305
  var require_formatter = require_formatter_DqAKDlvN();
60242
60306
  var LEVEL_RANK = {
60243
60307
  debug: 0,
@@ -60331,7 +60395,7 @@ var require_core_blocks_addon = __commonJS({
60331
60395
  "use strict";
60332
60396
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
60333
60397
  var require_chunk = require_chunk_Cek0wNdY();
60334
- var require_dist10 = require_dist_B29Skpzo();
60398
+ var require_dist10 = require_dist_BhE8zNfY();
60335
60399
  var node_crypto = __require("crypto");
60336
60400
  var node_fs_promises = __require("fs/promises");
60337
60401
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -61228,11 +61292,11 @@ var require_core_blocks = __commonJS({
61228
61292
  }
61229
61293
  });
61230
61294
 
61231
- // ../system/dist/retired-settings-keys-CRL0qOnU.js
61232
- var require_retired_settings_keys_CRL0qOnU = __commonJS({
61233
- "../system/dist/retired-settings-keys-CRL0qOnU.js"(exports) {
61295
+ // ../system/dist/retired-settings-keys-CqDbI-vK.js
61296
+ var require_retired_settings_keys_CqDbI_vK = __commonJS({
61297
+ "../system/dist/retired-settings-keys-CqDbI-vK.js"(exports) {
61234
61298
  "use strict";
61235
- var require_dist10 = require_dist_B29Skpzo();
61299
+ var require_dist10 = require_dist_BhE8zNfY();
61236
61300
  function settingsStoreIsAuthoritativeHere(env) {
61237
61301
  const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
61238
61302
  return raw === "" || raw === "hub";
@@ -63446,8 +63510,8 @@ var require_device_manager_addon = __commonJS({
63446
63510
  [Symbol.toStringTag]: { value: "Module" }
63447
63511
  });
63448
63512
  require_chunk_Cek0wNdY();
63449
- var require_dist10 = require_dist_B29Skpzo();
63450
- var require_retired_settings_keys = require_retired_settings_keys_CRL0qOnU();
63513
+ var require_dist10 = require_dist_BhE8zNfY();
63514
+ var require_retired_settings_keys = require_retired_settings_keys_CqDbI_vK();
63451
63515
  var node_crypto = __require("crypto");
63452
63516
  var _camstack_types_node = require_node();
63453
63517
  var JOB_HISTORY = 20;
@@ -64425,6 +64489,9 @@ var require_device_manager_addon = __commonJS({
64425
64489
  for (const f of features) if (DEVICE_FEATURE_VALUES.has(f)) out.push(f);
64426
64490
  return out;
64427
64491
  }
64492
+ function persistedIsCamera(type) {
64493
+ return type === require_dist10.DeviceType.Camera;
64494
+ }
64428
64495
  function buildSourceInfoFromConfig(persistedConfig, stableId, addonId) {
64429
64496
  const id = typeof persistedConfig["entityId"] === "string" ? persistedConfig["entityId"] : void 0;
64430
64497
  const system = typeof persistedConfig["system"] === "string" ? persistedConfig["system"] : void 0;
@@ -64571,7 +64638,7 @@ var require_device_manager_addon = __commonJS({
64571
64638
  online: pctx.host.resolveDeviceOnline(m.id, pctx.registry !== null),
64572
64639
  probed: pctx.host.resolveDeviceProbed(m.id),
64573
64640
  features: persistedFeatures(m.features),
64574
- isCamera: persistedType === require_dist10.DeviceType.Camera,
64641
+ isCamera: persistedIsCamera(persistedType),
64575
64642
  config: persistedConfig ?? {},
64576
64643
  metadata,
64577
64644
  ...m.integrationId !== void 0 ? { integrationId: m.integrationId } : {},
@@ -64616,7 +64683,7 @@ var require_device_manager_addon = __commonJS({
64616
64683
  online: pctx.host.resolveDeviceOnline(deviceId, true),
64617
64684
  probed: pctx.host.resolveDeviceProbed(deviceId),
64618
64685
  features: persistedFeatures(m.features),
64619
- isCamera: false,
64686
+ isCamera: persistedIsCamera(m.type),
64620
64687
  config: persistedConfig ?? {},
64621
64688
  metadata,
64622
64689
  ...m.integrationId !== void 0 ? { integrationId: m.integrationId } : {},
@@ -64664,7 +64731,7 @@ var require_device_manager_addon = __commonJS({
64664
64731
  online: pctx.host.resolveDeviceOnline(m.id, pctx.registry !== null),
64665
64732
  probed: pctx.host.resolveDeviceProbed(m.id),
64666
64733
  features: persistedFeatures(m.features),
64667
- isCamera: false,
64734
+ isCamera: persistedIsCamera(m.type),
64668
64735
  config: persistedConfig,
64669
64736
  metadata,
64670
64737
  ...m.integrationId !== void 0 ? { integrationId: m.integrationId } : {},
@@ -68260,7 +68327,7 @@ var require_hub_forwarder = __commonJS({
68260
68327
  [Symbol.toStringTag]: { value: "Module" }
68261
68328
  });
68262
68329
  require_chunk_Cek0wNdY();
68263
- var require_dist10 = require_dist_B29Skpzo();
68330
+ var require_dist10 = require_dist_BhE8zNfY();
68264
68331
  var require_formatter = require_formatter_DqAKDlvN();
68265
68332
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
68266
68333
  var HubForwarderDestination = class {
@@ -68397,7 +68464,7 @@ var require_liveness_monitor_addon = __commonJS({
68397
68464
  "use strict";
68398
68465
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
68399
68466
  require_chunk_Cek0wNdY();
68400
- var require_dist10 = require_dist_B29Skpzo();
68467
+ var require_dist10 = require_dist_BhE8zNfY();
68401
68468
  var NO_DEVICES = "liveness:no-devices";
68402
68469
  var ALL_OFFLINE = "liveness:all-devices-offline";
68403
68470
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -68587,7 +68654,7 @@ var require_local_auth_addon = __commonJS({
68587
68654
  [Symbol.toStringTag]: { value: "Module" }
68588
68655
  });
68589
68656
  var require_chunk = require_chunk_Cek0wNdY();
68590
- var require_dist10 = require_dist_B29Skpzo();
68657
+ var require_dist10 = require_dist_BhE8zNfY();
68591
68658
  var node_crypto = __require("crypto");
68592
68659
  node_crypto = require_chunk.__toESM(node_crypto);
68593
68660
  var crypto$1 = __require("crypto");
@@ -76400,7 +76467,7 @@ var require_loki_logging = __commonJS({
76400
76467
  [Symbol.toStringTag]: { value: "Module" }
76401
76468
  });
76402
76469
  require_chunk_Cek0wNdY();
76403
- var require_dist10 = require_dist_B29Skpzo();
76470
+ var require_dist10 = require_dist_BhE8zNfY();
76404
76471
  function sanitizeLabelName(raw) {
76405
76472
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
76406
76473
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -76965,7 +77032,7 @@ var require_native_metrics_addon = __commonJS({
76965
77032
  [Symbol.toStringTag]: { value: "Module" }
76966
77033
  });
76967
77034
  var require_chunk = require_chunk_Cek0wNdY();
76968
- var require_dist10 = require_dist_B29Skpzo();
77035
+ var require_dist10 = require_dist_BhE8zNfY();
76969
77036
  var node_fs_promises = __require("fs/promises");
76970
77037
  var node_child_process = __require("child_process");
76971
77038
  var node_util = __require("util");
@@ -79587,7 +79654,7 @@ var require_filesystem_storage_addon = __commonJS({
79587
79654
  [Symbol.toStringTag]: { value: "Module" }
79588
79655
  });
79589
79656
  var require_chunk = require_chunk_Cek0wNdY();
79590
- var require_dist10 = require_dist_B29Skpzo();
79657
+ var require_dist10 = require_dist_BhE8zNfY();
79591
79658
  var node_crypto = __require("crypto");
79592
79659
  var node_fs_promises = __require("fs/promises");
79593
79660
  var node_path = __require("path");
@@ -80703,8 +80770,8 @@ var require_sqlite_settings_addon = __commonJS({
80703
80770
  [Symbol.toStringTag]: { value: "Module" }
80704
80771
  });
80705
80772
  var require_chunk = require_chunk_Cek0wNdY();
80706
- var require_dist10 = require_dist_B29Skpzo();
80707
- var require_retired_settings_keys = require_retired_settings_keys_CRL0qOnU();
80773
+ var require_dist10 = require_dist_BhE8zNfY();
80774
+ var require_retired_settings_keys = require_retired_settings_keys_CqDbI_vK();
80708
80775
  var node_crypto = __require("crypto");
80709
80776
  var node_fs = __require("fs");
80710
80777
  var node_module = __require("module");
@@ -80740,6 +80807,14 @@ var require_sqlite_settings_addon = __commonJS({
80740
80807
  var SQLITE_PROFILE_REPORT_INTERVAL_MS = 6e4;
80741
80808
  var SQLITE_PROFILE_REPORT_FLOOR_MS = 250;
80742
80809
  var SQLITE_PROFILE_TOP_N = 5;
80810
+ var SQLITE_ENGINE_STORM_WALL_SHARE = 0.5;
80811
+ function sqliteEngineStorm(stats, windowMs) {
80812
+ if (windowMs <= 0) return null;
80813
+ const top = stats[0];
80814
+ if (top === void 0) return null;
80815
+ if (top.totalMs / windowMs < 0.5) return null;
80816
+ return top;
80817
+ }
80743
80818
  function rowsOf(value) {
80744
80819
  if (Array.isArray(value)) return value.length;
80745
80820
  if (value === void 0 || value === null) return 0;
@@ -80874,21 +80949,39 @@ var require_sqlite_settings_addon = __commonJS({
80874
80949
  const stats = this.drain();
80875
80950
  const busyMs = stats.reduce((acc, s) => acc + s.totalMs, 0);
80876
80951
  if (busyMs < this.reportFloorMs) return;
80952
+ const busyPct = Math.round(busyMs / windowMs * 100);
80953
+ const calls = stats.reduce((acc, s) => acc + s.calls, 0);
80954
+ const top = stats.slice(0, this.topN).map((s) => ({
80955
+ op: s.op,
80956
+ collection: s.collection,
80957
+ ...s.owner === void 0 ? {} : { owner: s.owner },
80958
+ ...s.shape === void 0 ? {} : { shape: s.shape },
80959
+ calls: s.calls,
80960
+ totalMs: Math.round(s.totalMs),
80961
+ maxMs: Math.round(s.maxMs),
80962
+ rows: s.rows
80963
+ }));
80877
80964
  this.logger.info("sqlite engine busy", { meta: {
80878
80965
  busyMs: Math.round(busyMs),
80879
80966
  windowMs: Math.round(windowMs),
80880
- busyPct: Math.round(busyMs / windowMs * 100),
80881
- calls: stats.reduce((acc, s) => acc + s.calls, 0),
80882
- top: stats.slice(0, this.topN).map((s) => ({
80883
- op: s.op,
80884
- collection: s.collection,
80885
- ...s.owner === void 0 ? {} : { owner: s.owner },
80886
- ...s.shape === void 0 ? {} : { shape: s.shape },
80887
- calls: s.calls,
80888
- totalMs: Math.round(s.totalMs),
80889
- maxMs: Math.round(s.maxMs),
80890
- rows: s.rows
80891
- }))
80967
+ busyPct,
80968
+ calls,
80969
+ top
80970
+ } });
80971
+ const storm = sqliteEngineStorm(stats, windowMs);
80972
+ if (storm !== null) this.logger.warn("sqlite engine storm", { meta: {
80973
+ busyMs: Math.round(busyMs),
80974
+ windowMs: Math.round(windowMs),
80975
+ busyPct,
80976
+ wallPct: Math.round(storm.totalMs / windowMs * 100),
80977
+ op: storm.op,
80978
+ collection: storm.collection,
80979
+ ...storm.owner === void 0 ? {} : { owner: storm.owner },
80980
+ ...storm.shape === void 0 ? {} : { shape: storm.shape },
80981
+ calls: storm.calls,
80982
+ totalMs: Math.round(storm.totalMs),
80983
+ maxMs: Math.round(storm.maxMs),
80984
+ rows: storm.rows
80892
80985
  } });
80893
80986
  }
80894
80987
  start() {
@@ -82968,6 +83061,7 @@ var require_sqlite_settings_addon = __commonJS({
82968
83061
  return this.vectorIndex;
82969
83062
  }
82970
83063
  };
83064
+ exports.SQLITE_ENGINE_STORM_WALL_SHARE = SQLITE_ENGINE_STORM_WALL_SHARE;
82971
83065
  exports.SQLITE_JOURNAL_SIZE_LIMIT_BYTES = SQLITE_JOURNAL_SIZE_LIMIT_BYTES;
82972
83066
  exports.SQLITE_MMAP_CEILING_BYTES = SQLITE_MMAP_CEILING_BYTES;
82973
83067
  exports.SQLITE_MMAP_FLOOR_BYTES = SQLITE_MMAP_FLOOR_BYTES;
@@ -82987,6 +83081,7 @@ var require_sqlite_settings_addon = __commonJS({
82987
83081
  exports.WAL_MAINTENANCE_INTERVAL_MS = WAL_MAINTENANCE_INTERVAL_MS;
82988
83082
  exports.WalMaintenance = WalMaintenance;
82989
83083
  exports.prefixRange = prefixRange;
83084
+ exports.sqliteEngineStorm = sqliteEngineStorm;
82990
83085
  exports.sqliteMmapSizeFor = sqliteMmapSizeFor;
82991
83086
  exports.sqlitePageCacheKibFor = sqlitePageCacheKibFor;
82992
83087
  }
@@ -83051,6 +83146,7 @@ var require_sqlite_storage = __commonJS({
83051
83146
  exports.DeviceStore$1 = DeviceStore;
83052
83147
  exports.FilesystemStorageAddon = require_builtins_sqlite_storage_filesystem_storage_addon.FilesystemStorageAddon;
83053
83148
  exports.FilesystemStorageProvider = require_builtins_sqlite_storage_filesystem_storage_addon.FilesystemStorageProvider;
83149
+ exports.SQLITE_ENGINE_STORM_WALL_SHARE = require_builtins_sqlite_storage_sqlite_settings_addon.SQLITE_ENGINE_STORM_WALL_SHARE;
83054
83150
  exports.SQLITE_JOURNAL_SIZE_LIMIT_BYTES = require_builtins_sqlite_storage_sqlite_settings_addon.SQLITE_JOURNAL_SIZE_LIMIT_BYTES;
83055
83151
  exports.SQLITE_MMAP_CEILING_BYTES = require_builtins_sqlite_storage_sqlite_settings_addon.SQLITE_MMAP_CEILING_BYTES;
83056
83152
  exports.SQLITE_MMAP_FLOOR_BYTES = require_builtins_sqlite_storage_sqlite_settings_addon.SQLITE_MMAP_FLOOR_BYTES;
@@ -83069,6 +83165,7 @@ var require_sqlite_storage = __commonJS({
83069
83165
  exports.WAL_MAINTENANCE_INTERVAL_MS = require_builtins_sqlite_storage_sqlite_settings_addon.WAL_MAINTENANCE_INTERVAL_MS;
83070
83166
  exports.WalMaintenance = require_builtins_sqlite_storage_sqlite_settings_addon.WalMaintenance;
83071
83167
  exports.default = require_builtins_sqlite_storage_filesystem_storage_addon.FilesystemStorageAddon;
83168
+ exports.sqliteEngineStorm = require_builtins_sqlite_storage_sqlite_settings_addon.sqliteEngineStorm;
83072
83169
  exports.sqliteMmapSizeFor = require_builtins_sqlite_storage_sqlite_settings_addon.sqliteMmapSizeFor;
83073
83170
  exports.sqlitePageCacheKibFor = require_builtins_sqlite_storage_sqlite_settings_addon.sqlitePageCacheKibFor;
83074
83171
  }
@@ -83083,7 +83180,7 @@ var require_storage_orchestrator_addon = __commonJS({
83083
83180
  [Symbol.toStringTag]: { value: "Module" }
83084
83181
  });
83085
83182
  var require_chunk = require_chunk_Cek0wNdY();
83086
- var require_dist10 = require_dist_B29Skpzo();
83183
+ var require_dist10 = require_dist_BhE8zNfY();
83087
83184
  var node_crypto = __require("crypto");
83088
83185
  var node_fs_promises = __require("fs/promises");
83089
83186
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -83267,17 +83364,13 @@ var require_storage_orchestrator_addon = __commonJS({
83267
83364
  "recordings",
83268
83365
  "recordingsLow",
83269
83366
  "eventMedia",
83270
- "backups",
83271
- "galleryMedia"
83367
+ "backups"
83272
83368
  ];
83273
83369
  var MOVER_CLASSES = [
83274
83370
  "recordings",
83275
83371
  "recordingsLow",
83276
- "eventMedia",
83277
- "galleryMedia"
83372
+ "eventMedia"
83278
83373
  ];
83279
- var BLOCKING_ONLY_CLASSES = ["galleryMedia"];
83280
- var GALLERY_FORBIDDEN_NEIGHBOUR_TYPES = ["recordings", "recordingsLow"];
83281
83374
  var MOVE_LANES = ["media", "footage"];
83282
83375
  var PARTICIPANTS = [
83283
83376
  "pipeline",
@@ -83302,6 +83395,7 @@ var require_storage_orchestrator_addon = __commonJS({
83302
83395
  this.deps = deps;
83303
83396
  }
83304
83397
  async plan(input) {
83398
+ refuseRetiredGalleryClass(input.destinations);
83305
83399
  const mode = input.mode ?? "blocking";
83306
83400
  const moves = [];
83307
83401
  const findings = [];
@@ -83315,8 +83409,6 @@ var require_storage_orchestrator_addon = __commonJS({
83315
83409
  if (target.type !== storageClass) throw new Error(`Storage location "${targetId}" is type "${target.type}", expected "${storageClass}"`);
83316
83410
  if (source.id === target.id) throw new Error(`Storage location "${targetId}" is already the "${storageClass}" default`);
83317
83411
  if (!MOVER_CLASSES.includes(storageClass)) throw new Error(`No mover owns "${storageClass}" \u2014 the migration can repoint its default but cannot move its bytes. Move it by hand, then repoint the default with upsertLocation.`);
83318
- if (mode === "nonBlocking" && BLOCKING_ONLY_CLASSES.includes(storageClass)) throw new Error(`"${storageClass}" is a single-cardinality storage class: it can never exist at two locations at once, so it cannot be repointed first and drained behind. Use mode "blocking".`);
83319
- await this.refuseGalleryOntoRecordingsVolume(storageClass, targetId);
83320
83412
  moves.push({
83321
83413
  storageClass,
83322
83414
  fromLocationId: source.id,
@@ -83326,11 +83418,6 @@ var require_storage_orchestrator_addon = __commonJS({
83326
83418
  error: null,
83327
83419
  progress: null
83328
83420
  });
83329
- if (BLOCKING_ONLY_CLASSES.includes(storageClass)) findings.push({
83330
- code: "blockingOnly",
83331
- storageClass,
83332
- message: `"${storageClass}" is single-cardinality: this move is stop-the-world for its whole duration, in every mode. It is a few KB per enrolled sample, which is why that is acceptable.`
83333
- });
83334
83421
  findings.push(...await this.deviceFindings(storageClass, source.id, target.id));
83335
83422
  }
83336
83423
  if (moves.length === 0) throw new Error("select at least one storage class");
@@ -83365,29 +83452,6 @@ var require_storage_orchestrator_addon = __commonJS({
83365
83452
  findings
83366
83453
  };
83367
83454
  }
83368
- /**
83369
- * HARD refusal: `galleryMedia` onto a volume a recordings class lives on.
83370
- *
83371
- * This is the one same-device case that is a refusal rather than a finding,
83372
- * because its consequence is silent and arrives months later — the gallery is
83373
- * wiped by the next footage wipe, quota eviction or recordings disk swap, and
83374
- * nothing at that moment points back at this migration.
83375
- *
83376
- * It can only refuse what it can SEE. `deviceKeyOf` is a realpath, so it
83377
- * catches a symlink, a bind mount and a literally-shared directory — and
83378
- * misses two distinct directories on one filesystem, and any location pinned
83379
- * to another node. Those come back `null`/distinct and produce a
83380
- * `deviceIdentityUnknown` finding instead.
83381
- */
83382
- async refuseGalleryOntoRecordingsVolume(storageClass, targetId) {
83383
- if (storageClass !== "galleryMedia") return;
83384
- const targetKey = await this.deviceKey(targetId);
83385
- if (targetKey === null) return;
83386
- for (const type of GALLERY_FORBIDDEN_NEIGHBOUR_TYPES) for (const neighbour of this.deps.locations.listLocations({ type })) {
83387
- if (await this.deviceKey(neighbour.id) !== targetKey) continue;
83388
- throw new Error(`Storage location "${targetId}" shares a volume with "${neighbour.id}" (${type}). galleryMedia is deliberately NOT on the recordings volume: enrolment images survive every retention sweep, so they must also survive a footage wipe, a quota eviction and a recordings disk swap. Choose a destination on another volume.`);
83389
- }
83390
- }
83391
83455
  /** Same-device observations that are reported, not refused. */
83392
83456
  async deviceFindings(storageClass, sourceId, targetId) {
83393
83457
  if (this.deps.deviceKeyOf === void 0) return [];
@@ -83519,7 +83583,7 @@ var require_storage_orchestrator_addon = __commonJS({
83519
83583
  if (laneOf(storageClass) === "media") {
83520
83584
  const count = await unanswerable(this.deps.participants.analytics.residue({
83521
83585
  toLocationId: target.id,
83522
- mode: storageClass === "galleryMedia" ? "gallery" : "move"
83586
+ mode: "move"
83523
83587
  }));
83524
83588
  if (count !== null && count.rows === 0) continue;
83525
83589
  out.push({
@@ -83799,9 +83863,7 @@ var require_storage_orchestrator_addon = __commonJS({
83799
83863
  *
83800
83864
  * Two lanes — the recorder's footage engine and post-analysis's media engine
83801
83865
  * — run in parallel with each other and strictly FIFO within themselves.
83802
- * `galleryMedia` shares the media lane with `eventMedia` because it shares
83803
- * the same `MediaRelocateEngine`, which refuses a second running job; starting
83804
- * both would fail the second one instantly.
83866
+ * `eventMedia` is the only class on the media lane.
83805
83867
  */
83806
83868
  async startOrResumeMoves(job) {
83807
83869
  if (job.cancelRequested) return;
@@ -83931,7 +83993,7 @@ var require_storage_orchestrator_addon = __commonJS({
83931
83993
  const input2 = {
83932
83994
  toLocationId: move.toLocationId,
83933
83995
  throttleMbps: job.throttleMbps,
83934
- mode: move.storageClass === "galleryMedia" ? "gallery" : "move"
83996
+ mode: "move"
83935
83997
  };
83936
83998
  return (unleased ? await this.deps.participants.analytics.startDrain(input2) : await this.deps.participants.analytics.startMove({
83937
83999
  ...input2,
@@ -83992,7 +84054,11 @@ var require_storage_orchestrator_addon = __commonJS({
83992
84054
  return job.phase === "done" || job.phase === "failed" || job.phase === "cancelled";
83993
84055
  }
83994
84056
  function laneOf(storageClass) {
83995
- return storageClass === "eventMedia" || storageClass === "galleryMedia" ? "media" : "footage";
84057
+ return storageClass === "eventMedia" ? "media" : "footage";
84058
+ }
84059
+ function refuseRetiredGalleryClass(destinations) {
84060
+ if (destinations.galleryMedia === void 0) return;
84061
+ throw new Error("galleryMedia is no longer a storage class. Enrolled gallery lives in the pipeline-analytics addon data directory, not a location the operator places.");
83996
84062
  }
83997
84063
  function runsUnleased(job) {
83998
84064
  if (job.phase === "sealing" || job.phase === "draining") return true;
@@ -84263,14 +84329,13 @@ var require_storage_orchestrator_addon = __commonJS({
84263
84329
  /**
84264
84330
  * Shout about a persisted row that is BOTH the type default and disabled.
84265
84331
  *
84266
- * `upsertLocation` cannot produce this (`resolveEnabled` force-enables a
84267
- * default) and neither can `setDefaultLocations` but hydrate writes rows
84268
- * straight into the map without either, so a hand-edited store, a partial
84269
- * migration or a row written by another build can. It matters because every
84270
- * bare-type ref resolves through {@link getDefaultLocation}: on such a row
84332
+ * `upsertLocation` can now produce this (enabled is the write set; `isDefault`
84333
+ * is store residue). Hydrate also writes rows straight into the map, so a
84334
+ * hand-edited store or a row written by another build can too. It matters
84335
+ * because every bare-type ref still resolves through {@link getDefaultLocation}
84336
+ * until Stage 5 of the enabled-write-set design: on such a row
84271
84337
  * `storage.write({ location: 'eventMedia' })` and the migration coordinator's
84272
- * drain destination both point at a disk the operator turned off. That is the
84273
- * one thing this model must never do silently.
84338
+ * drain destination both point at a disk the operator turned off.
84274
84339
  *
84275
84340
  * Reported, never repaired: flipping an operator's flag back on at boot would
84276
84341
  * be the system overruling the switch instead of obeying it. The coordinator
@@ -84555,6 +84620,7 @@ var require_storage_orchestrator_addon = __commonJS({
84555
84620
  createdAt: existing?.createdAt ?? now,
84556
84621
  updatedAt: now
84557
84622
  };
84623
+ refuseLastWriteTargetDisabled(existing, next, this.locations.values());
84558
84624
  const demoted = [];
84559
84625
  if (next.isDefault) {
84560
84626
  for (const [otherId, otherLoc] of this.locations) if (otherLoc.type === next.type && otherLoc.id !== next.id && otherLoc.isDefault) {
@@ -84849,9 +84915,20 @@ var require_storage_orchestrator_addon = __commonJS({
84849
84915
  if (existing) return {};
84850
84916
  return { enabled: input.isDefault || !typeAlreadyHasLocation };
84851
84917
  }
84852
- if (input.isDefault && requested === false) return { enabled: true };
84853
84918
  return { enabled: requested };
84854
84919
  }
84920
+ var OPTIONAL_WRITE_TYPES = /* @__PURE__ */ new Set(["backups"]);
84921
+ function refuseLastWriteTargetDisabled(existing, next, locations) {
84922
+ if (OPTIONAL_WRITE_TYPES.has(next.type)) return;
84923
+ if (next.enabled !== false) return;
84924
+ if (existing === void 0) return;
84925
+ if (existing.enabled === false) return;
84926
+ for (const loc of locations) {
84927
+ if (loc.id === next.id || loc.type !== next.type) continue;
84928
+ if (loc.enabled !== false) return;
84929
+ }
84930
+ throw new Error(`Cannot disable "${next.id}": it is the last enabled location of type "${next.type}". Enable another location of this type first.`);
84931
+ }
84855
84932
  var DEFAULT_MAX_ROUNDS = 8;
84856
84933
  var DEFAULT_HYSTERESIS_PERCENT = 1;
84857
84934
  var StoragePressureManager = class {
@@ -85680,7 +85757,7 @@ var require_system_config_addon = __commonJS({
85680
85757
  [Symbol.toStringTag]: { value: "Module" }
85681
85758
  });
85682
85759
  require_chunk_Cek0wNdY();
85683
- var require_dist10 = require_dist_B29Skpzo();
85760
+ var require_dist10 = require_dist_BhE8zNfY();
85684
85761
  var SECTION_TITLES = {
85685
85762
  server: "Server",
85686
85763
  auth: "Authentication"
@@ -103741,7 +103818,7 @@ var require_winston_logging = __commonJS({
103741
103818
  [Symbol.toStringTag]: { value: "Module" }
103742
103819
  });
103743
103820
  var require_chunk = require_chunk_Cek0wNdY();
103744
- var require_dist10 = require_dist_B29Skpzo();
103821
+ var require_dist10 = require_dist_BhE8zNfY();
103745
103822
  var require_formatter = require_formatter_DqAKDlvN();
103746
103823
  var node_path = __require("path");
103747
103824
  node_path = require_chunk.__toESM(node_path);
@@ -105684,9 +105761,9 @@ var require_event_category_BaEgqJNv = __commonJS({
105684
105761
  }
105685
105762
  });
105686
105763
 
105687
- // ../types/dist/sleep-DIg3xuEw.js
105688
- var require_sleep_DIg3xuEw = __commonJS({
105689
- "../types/dist/sleep-DIg3xuEw.js"(exports) {
105764
+ // ../types/dist/sleep-CqVyhcl-.js
105765
+ var require_sleep_CqVyhcl = __commonJS({
105766
+ "../types/dist/sleep-CqVyhcl-.js"(exports) {
105690
105767
  "use strict";
105691
105768
  var require_event_category = require_event_category_BaEgqJNv();
105692
105769
  var zod = require_zod();
@@ -108393,6 +108470,8 @@ var require_sleep_DIg3xuEw = __commonJS({
108393
108470
  listRelocateMediaJobs: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRelocateMediaJobs", "query", input),
108394
108471
  cancelRelocateMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "cancelRelocateMedia", "mutation", input),
108395
108472
  listOpsLog: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listOpsLog", "query", input),
108473
+ reclaimDebugMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "reclaimDebugMedia", "mutation", input),
108474
+ getMediaReclaimStatus: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getMediaReclaimStatus", "query", input),
108396
108475
  getTrainingExportSummary: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrainingExportSummary", "query", input),
108397
108476
  getTrainingExportUrl: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrainingExportUrl", "query", input),
108398
108477
  listRetrainStaging: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRetrainStaging", "query", input),
@@ -109357,7 +109436,7 @@ var require_addon = __commonJS({
109357
109436
  "use strict";
109358
109437
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
109359
109438
  var require_event_category = require_event_category_BaEgqJNv();
109360
- var require_sleep = require_sleep_DIg3xuEw();
109439
+ var require_sleep = require_sleep_CqVyhcl();
109361
109440
  var require_err_msg = require_err_msg_COpsHMw2();
109362
109441
  var CAP_INPUT_DEFAULTS = Object.freeze({
109363
109442
  "addons": { "getLogs": { "limit": 100 } },
@@ -109473,6 +109552,7 @@ var require_addon = __commonJS({
109473
109552
  "getSensorEvents": { "limit": 1e3 },
109474
109553
  "listGroups": { "limit": 40 },
109475
109554
  "listRecentTracks": { "limit": 200 },
109555
+ "reclaimDebugMedia": { "mode": "report" },
109476
109556
  "searchObjectEvents": {
109477
109557
  "limit": 50,
109478
109558
  "minScore": 0.2
@@ -116240,12 +116320,12 @@ var require_dist2 = __commonJS({
116240
116320
  }
116241
116321
  });
116242
116322
 
116243
- // ../system/dist/manifest-system-deps-DBje540e.js
116244
- var require_manifest_system_deps_DBje540e = __commonJS({
116245
- "../system/dist/manifest-system-deps-DBje540e.js"(exports) {
116323
+ // ../system/dist/manifest-system-deps-uflHvHDB.js
116324
+ var require_manifest_system_deps_uflHvHDB = __commonJS({
116325
+ "../system/dist/manifest-system-deps-uflHvHDB.js"(exports) {
116246
116326
  "use strict";
116247
116327
  var require_chunk = require_chunk_Cek0wNdY();
116248
- require_dist_B29Skpzo();
116328
+ require_dist_BhE8zNfY();
116249
116329
  var node_crypto = __require("crypto");
116250
116330
  node_crypto = require_chunk.__toESM(node_crypto);
116251
116331
  var _camstack_types_node = require_node();
@@ -123530,6 +123610,93 @@ var require_manifest_system_deps_DBje540e = __commonJS({
123530
123610
  }
123531
123611
  await deps.installPythonRequirements(reqAbs);
123532
123612
  }
123613
+ var DISTRO_PACKAGE_ALLOWLIST = {
123614
+ apt: ["smbclient"],
123615
+ apk: ["samba-client"],
123616
+ dnf: ["samba-client"]
123617
+ };
123618
+ function packageIsAllowlisted(manager, packageName) {
123619
+ if (manager === "brew") return true;
123620
+ if (packageName.length === 0) return false;
123621
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9+._-]*$/.test(packageName)) return false;
123622
+ return DISTRO_PACKAGE_ALLOWLIST[manager].includes(packageName);
123623
+ }
123624
+ function decidePackageInstall(input) {
123625
+ if (input.manager === "brew") return { kind: "local" };
123626
+ if (!packageIsAllowlisted(input.manager, input.packageName)) return {
123627
+ kind: "refuse",
123628
+ reason: "not-allowlisted"
123629
+ };
123630
+ if (!input.helperAvailable) return {
123631
+ kind: "refuse",
123632
+ reason: "helper-unavailable"
123633
+ };
123634
+ return { kind: "helper" };
123635
+ }
123636
+ function pkgdSocketPath() {
123637
+ return process.env["CAMSTACK_PKGD_SOCKET"] ?? "/run/camstack/pkgd.sock";
123638
+ }
123639
+ function privilegedHelperAvailable(socketPath = pkgdSocketPath()) {
123640
+ return (0, node_fs.existsSync)(socketPath);
123641
+ }
123642
+ function requestPrivilegedInstall(req, socketPath = pkgdSocketPath(), timeoutMs = 360 * 1e3) {
123643
+ return new Promise((resolve) => {
123644
+ const socket = (0, node_net.createConnection)({ path: socketPath });
123645
+ const chunks = [];
123646
+ const finish = (result) => {
123647
+ socket.destroy();
123648
+ resolve(result);
123649
+ };
123650
+ const timer = setTimeout(() => {
123651
+ finish({
123652
+ ok: false,
123653
+ error: `privileged helper timed out after ${timeoutMs}ms`
123654
+ });
123655
+ }, timeoutMs);
123656
+ socket.on("connect", () => {
123657
+ socket.write(`${JSON.stringify({
123658
+ v: 1,
123659
+ ...req
123660
+ })}
123661
+ `);
123662
+ });
123663
+ socket.on("data", (data) => {
123664
+ chunks.push(data);
123665
+ const text = Buffer.concat(chunks).toString("utf8");
123666
+ const nl = text.indexOf("\n");
123667
+ if (nl === -1) return;
123668
+ clearTimeout(timer);
123669
+ try {
123670
+ const parsed = JSON.parse(text.slice(0, nl));
123671
+ finish({
123672
+ ok: parsed.ok === true,
123673
+ ...parsed.error !== void 0 ? { error: parsed.error } : {}
123674
+ });
123675
+ } catch (err) {
123676
+ finish({
123677
+ ok: false,
123678
+ error: err instanceof Error ? err.message : String(err)
123679
+ });
123680
+ }
123681
+ });
123682
+ socket.on("error", (err) => {
123683
+ clearTimeout(timer);
123684
+ finish({
123685
+ ok: false,
123686
+ error: err.message
123687
+ });
123688
+ });
123689
+ socket.on("end", () => {
123690
+ if (chunks.length === 0) {
123691
+ clearTimeout(timer);
123692
+ finish({
123693
+ ok: false,
123694
+ error: "privileged helper closed without a reply"
123695
+ });
123696
+ }
123697
+ });
123698
+ });
123699
+ }
123533
123700
  var execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
123534
123701
  var INSTALL_TIMEOUT_MS = 300 * 1e3;
123535
123702
  var PROBE_TIMEOUT_MS = 1e4;
@@ -123540,12 +123707,16 @@ var require_manifest_system_deps_DBje540e = __commonJS({
123540
123707
  const detectManager = options.detectManager ?? defaultDetectManager;
123541
123708
  const run = options.run ?? defaultRun;
123542
123709
  const platform = options.platform ?? process.platform;
123710
+ const helperAvailable = options.helperAvailable ?? (async () => privilegedHelperAvailable());
123711
+ const requestInstall = options.requestInstall ?? ((req) => requestPrivilegedInstall(req));
123543
123712
  for (const dep of deps) try {
123544
123713
  await satisfyOne(dep, declaration.id, {
123545
123714
  hasBinary,
123546
123715
  detectManager,
123547
123716
  run,
123548
- platform
123717
+ platform,
123718
+ helperAvailable,
123719
+ requestInstall
123549
123720
  }, logger);
123550
123721
  } catch (err) {
123551
123722
  logger.warn("system dependency step failed", { meta: {
@@ -123583,15 +123754,43 @@ var require_manifest_system_deps_DBje540e = __commonJS({
123583
123754
  } });
123584
123755
  return;
123585
123756
  }
123586
- const plan = planFor(manager, packageName);
123757
+ const decision = decidePackageInstall({
123758
+ manager,
123759
+ packageName,
123760
+ helperAvailable: await rt.helperAvailable()
123761
+ });
123762
+ if (decision.kind === "refuse") {
123763
+ const message = decision.reason === "helper-unavailable" ? "system dependency missing and the privileged helper is not running \u2014 apt cannot run as uid 1001" : "system dependency missing and the package is not on the helper allowlist";
123764
+ logger.warn(message, { meta: {
123765
+ addonId,
123766
+ binary: dep.binary,
123767
+ manager,
123768
+ package: packageName,
123769
+ reason: decision.reason,
123770
+ ...dep.reason !== void 0 ? { reason: dep.reason } : {}
123771
+ } });
123772
+ return;
123773
+ }
123587
123774
  logger.info("installing system dependency", { meta: {
123588
123775
  addonId,
123589
123776
  binary: dep.binary,
123590
123777
  manager,
123591
- package: packageName
123778
+ package: packageName,
123779
+ via: decision.kind
123592
123780
  } });
123593
123781
  try {
123594
- for (const [command, args] of plan.steps) await rt.run(command, args);
123782
+ if (decision.kind === "helper") {
123783
+ const result = await rt.requestInstall({
123784
+ addonId,
123785
+ binary: dep.binary,
123786
+ manager,
123787
+ packageName
123788
+ });
123789
+ if (!result.ok) throw new Error(result.error ?? "privileged helper refused");
123790
+ } else {
123791
+ const plan = planFor(manager, packageName);
123792
+ for (const [command, args] of plan.steps) await rt.run(command, args);
123793
+ }
123595
123794
  } catch (err) {
123596
123795
  logger.warn("system dependency install failed \u2014 the addon loads, its capability must refuse", { meta: {
123597
123796
  addonId,
@@ -128274,7 +128473,7 @@ var require_dist3 = __commonJS({
128274
128473
  "use strict";
128275
128474
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
128276
128475
  var require_chunk = require_chunk_Cek0wNdY();
128277
- var require_dist10 = require_dist_B29Skpzo();
128476
+ var require_dist10 = require_dist_BhE8zNfY();
128278
128477
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
128279
128478
  require_alerts();
128280
128479
  var require_formatter = require_formatter_DqAKDlvN();
@@ -128300,7 +128499,7 @@ var require_dist3 = __commonJS({
128300
128499
  var require_builtins_winston_logging_index = require_winston_logging();
128301
128500
  var require_file_data_plane = require_file_data_plane_DO8KbxCe();
128302
128501
  var require_tls$1 = require_tls_BxQlomxd();
128303
- var require_manifest_system_deps = require_manifest_system_deps_DBje540e();
128502
+ var require_manifest_system_deps = require_manifest_system_deps_uflHvHDB();
128304
128503
  var require_resource_monitor = require_resource_monitor_CdnzxBLP();
128305
128504
  var require_custom_action_registry = require_custom_action_registry_jY0NOZK8();
128306
128505
  var zod = require_zod();
@@ -209142,7 +209341,7 @@ var require_dist4 = __commonJS({
209142
209341
  "use strict";
209143
209342
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
209144
209343
  var require_event_category = require_event_category_BaEgqJNv();
209145
- var require_sleep = require_sleep_DIg3xuEw();
209344
+ var require_sleep = require_sleep_CqVyhcl();
209146
209345
  var require_canonical_hash = require_canonical_hash_DNV8S5ET();
209147
209346
  var require_enums2 = require_enums();
209148
209347
  var require_err_msg = require_err_msg_COpsHMw2();
@@ -223483,6 +223682,39 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
223483
223682
  /** Present when the pass ended by throwing. */
223484
223683
  error: zod.z.string().nullable()
223485
223684
  });
223685
+ var MediaReclaimStartResultSchema = zod.z.object({
223686
+ started: zod.z.boolean(),
223687
+ /** True when a pass was already running; the new request is ignored. */
223688
+ alreadyRunning: zod.z.boolean()
223689
+ });
223690
+ var MediaReclaimInputSchema = zod.z.object({
223691
+ mode: zod.z.enum(["report", "reclaim"]).default("report"),
223692
+ scopes: zod.z.array(zod.z.enum(["motion-still", "track-filmstrip"])).min(1).optional(),
223693
+ deviceIds: zod.z.array(zod.z.number().int()).min(1).optional(),
223694
+ restart: zod.z.boolean().optional(),
223695
+ pageSize: zod.z.number().int().min(50).max(5e3).optional(),
223696
+ maxRowsPerDevice: zod.z.number().int().min(1).max(5e5).optional(),
223697
+ maxReclaimPerDevice: zod.z.number().int().min(1).max(5e5).optional(),
223698
+ maxBytesPerRun: zod.z.number().int().min(1).optional(),
223699
+ budgetMinutes: zod.z.number().int().min(1).max(720).optional(),
223700
+ throttleBytesPerSec: zod.z.number().int().min(64 * 1024).optional(),
223701
+ graceMinutes: zod.z.number().int().min(1).max(10080).optional()
223702
+ });
223703
+ var MediaReclaimStatusSchema = zod.z.object({
223704
+ running: zod.z.boolean(),
223705
+ mode: zod.z.enum(["report", "reclaim"]).nullable(),
223706
+ totalExamined: zod.z.number(),
223707
+ totalEligible: zod.z.number(),
223708
+ totalReclaimed: zod.z.number(),
223709
+ totalBytesReclaimed: zod.z.number(),
223710
+ totalRefused: zod.z.number(),
223711
+ /** Device+scope windows finished in this pass. */
223712
+ devicesDone: zod.z.number(),
223713
+ complete: zod.z.boolean().nullable(),
223714
+ startedAtMs: zod.z.number().nullable(),
223715
+ finishedAtMs: zod.z.number().nullable(),
223716
+ error: zod.z.string().nullable()
223717
+ });
223486
223718
  var ReplayFrameInputSchema = zod.z.object({
223487
223719
  timestamp: zod.z.number(),
223488
223720
  frame: PipelineRunResultBridge
@@ -223906,6 +224138,20 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
223906
224138
  auth: "admin"
223907
224139
  }),
223908
224140
  /**
224141
+ * Reclaim the standing debug-media backlog (motion-visit stills + track
224142
+ * filmstrips). DETACHED: returns `{ started }` immediately. The pass is
224143
+ * tens of minutes; awaiting it is a timeout, not a verdict. Dry-run unless
224144
+ * `mode: 'reclaim'`. Poll `getMediaReclaimStatus`.
224145
+ */
224146
+ reclaimDebugMedia: require_sleep.method(MediaReclaimInputSchema, MediaReclaimStartResultSchema, {
224147
+ kind: "mutation",
224148
+ auth: "admin"
224149
+ }),
224150
+ getMediaReclaimStatus: require_sleep.method(zod.z.object({}), MediaReclaimStatusSchema, {
224151
+ kind: "query",
224152
+ auth: "admin"
224153
+ }),
224154
+ /**
223909
224155
  * The CHEAP QUESTION, asked before any media moves: how big is the dataset
223910
224156
  * the marked (`markForTrain`) tracks would produce?
223911
224157
  *
@@ -242825,6 +243071,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
242825
243071
  addonId: null,
242826
243072
  access: "view"
242827
243073
  },
243074
+ "pipelineAnalytics.getMediaReclaimStatus": {
243075
+ capName: "pipeline-analytics",
243076
+ capScope: "device",
243077
+ addonId: null,
243078
+ access: "view"
243079
+ },
242828
243080
  "pipelineAnalytics.getMotionEvents": {
242829
243081
  capName: "pipeline-analytics",
242830
243082
  capScope: "device",
@@ -242999,6 +243251,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
242999
243251
  addonId: null,
243000
243252
  access: "create"
243001
243253
  },
243254
+ "pipelineAnalytics.reclaimDebugMedia": {
243255
+ capName: "pipeline-analytics",
243256
+ capScope: "device",
243257
+ addonId: null,
243258
+ access: "create"
243259
+ },
243002
243260
  "pipelineAnalytics.reconcileFromDisk": {
243003
243261
  capName: "pipeline-analytics",
243004
243262
  capScope: "device",
@@ -246873,6 +247131,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
246873
247131
  form: "single",
246874
247132
  optional: true
246875
247133
  }],
247134
+ "pipelineAnalytics.reclaimDebugMedia": [{
247135
+ name: "deviceIds",
247136
+ form: "array",
247137
+ optional: true
247138
+ }],
246876
247139
  "pipelineAnalytics.reconcileFromDisk": [{
246877
247140
  name: "deviceId",
246878
247141
  form: "single",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "camstack",
3
- "version": "1.2.69",
3
+ "version": "1.2.70",
4
4
  "description": "CLI tool for managing and running CamStack server",
5
5
  "keywords": [
6
6
  "camstack",