camstack 1.2.91 → 1.2.92

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.
@@ -20596,7 +20596,7 @@ var ConfigEntrySchema2 = external_exports.object({
20596
20596
  value: external_exports.unknown(),
20597
20597
  description: external_exports.string().optional()
20598
20598
  });
20599
- var LinkedDevicesModeSchema = external_exports.enum(["auto", "manual"]);
20599
+ var LinkedDevicesModeSchema = external_exports.enum(["manual"]);
20600
20600
  var LinkedDeviceSchema = external_exports.object({
20601
20601
  deviceId: external_exports.number(),
20602
20602
  name: external_exports.string(),
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runDiscover
4
- } from "./chunk-ECD5A36V.js";
4
+ } from "./chunk-KFUPFPP3.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-FFY5TY3C.js");
41
+ await import("./launcher-7Z35E2WM.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-FFY5TY3C.js");
86
+ await import("./launcher-7Z35E2WM.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-QUITQWRC.js");
1133
+ const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-5KWSHFNI.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-ECD5A36V.js";
8
+ } from "./chunk-KFUPFPP3.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-0fjBDzUu.js
23637
- var require_dist_0fjBDzUu = __commonJS({
23638
- "../system/dist/dist-0fjBDzUu.js"(exports) {
23636
+ // ../system/dist/dist-DNwhsXWi.js
23637
+ var require_dist_DNwhsXWi = __commonJS({
23638
+ "../system/dist/dist-DNwhsXWi.js"(exports) {
23639
23639
  "use strict";
23640
23640
  var zod = require_zod();
23641
23641
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
@@ -31309,7 +31309,7 @@ var require_dist_0fjBDzUu = __commonJS({
31309
31309
  value: zod.z.unknown(),
31310
31310
  description: zod.z.string().optional()
31311
31311
  });
31312
- var LinkedDevicesModeSchema = zod.z.enum(["auto", "manual"]);
31312
+ var LinkedDevicesModeSchema = zod.z.enum(["manual"]);
31313
31313
  var LinkedDeviceSchema = zod.z.object({
31314
31314
  deviceId: zod.z.number(),
31315
31315
  name: zod.z.string(),
@@ -60109,7 +60109,7 @@ var require_alerts_addon = __commonJS({
60109
60109
  [Symbol.toStringTag]: { value: "Module" }
60110
60110
  });
60111
60111
  require_chunk_Cek0wNdY();
60112
- var require_dist10 = require_dist_0fjBDzUu();
60112
+ var require_dist10 = require_dist_DNwhsXWi();
60113
60113
  function selectExpired(alerts, cutoffMs) {
60114
60114
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
60115
60115
  }
@@ -60928,7 +60928,7 @@ var require_console_logging = __commonJS({
60928
60928
  [Symbol.toStringTag]: { value: "Module" }
60929
60929
  });
60930
60930
  require_chunk_Cek0wNdY();
60931
- var require_dist10 = require_dist_0fjBDzUu();
60931
+ var require_dist10 = require_dist_DNwhsXWi();
60932
60932
  var require_formatter = require_formatter_DqAKDlvN();
60933
60933
  var LEVEL_RANK = {
60934
60934
  debug: 0,
@@ -61022,7 +61022,7 @@ var require_core_blocks_addon = __commonJS({
61022
61022
  "use strict";
61023
61023
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
61024
61024
  var require_chunk = require_chunk_Cek0wNdY();
61025
- var require_dist10 = require_dist_0fjBDzUu();
61025
+ var require_dist10 = require_dist_DNwhsXWi();
61026
61026
  var node_crypto = __require("crypto");
61027
61027
  var node_fs_promises = __require("fs/promises");
61028
61028
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -61919,11 +61919,11 @@ var require_core_blocks = __commonJS({
61919
61919
  }
61920
61920
  });
61921
61921
 
61922
- // ../system/dist/retired-settings-keys-pL2Nq6KT.js
61923
- var require_retired_settings_keys_pL2Nq6KT = __commonJS({
61924
- "../system/dist/retired-settings-keys-pL2Nq6KT.js"(exports) {
61922
+ // ../system/dist/retired-settings-keys-CUXClAIQ.js
61923
+ var require_retired_settings_keys_CUXClAIQ = __commonJS({
61924
+ "../system/dist/retired-settings-keys-CUXClAIQ.js"(exports) {
61925
61925
  "use strict";
61926
- var require_dist10 = require_dist_0fjBDzUu();
61926
+ var require_dist10 = require_dist_DNwhsXWi();
61927
61927
  function settingsStoreIsAuthoritativeHere(env) {
61928
61928
  const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
61929
61929
  return raw === "" || raw === "hub";
@@ -64137,8 +64137,8 @@ var require_device_manager_addon = __commonJS({
64137
64137
  [Symbol.toStringTag]: { value: "Module" }
64138
64138
  });
64139
64139
  require_chunk_Cek0wNdY();
64140
- var require_dist10 = require_dist_0fjBDzUu();
64141
- var require_retired_settings_keys = require_retired_settings_keys_pL2Nq6KT();
64140
+ var require_dist10 = require_dist_DNwhsXWi();
64141
+ var require_retired_settings_keys = require_retired_settings_keys_CUXClAIQ();
64142
64142
  var node_crypto = __require("crypto");
64143
64143
  var _camstack_types_node = require_node();
64144
64144
  var JOB_HISTORY = 20;
@@ -65759,7 +65759,7 @@ var require_device_manager_addon = __commonJS({
65759
65759
  var LINKED_IDS_CONFIG_KEY = "_linkedDeviceIds";
65760
65760
  var LINKED_TRACKED_IDS_CONFIG_KEY = "_linkedDeviceTrackedIds";
65761
65761
  function parseLinkedDevicesConfig(blob) {
65762
- const mode = blob["_linkedDevicesMode"] === "manual" ? "manual" : "auto";
65762
+ const mode = "manual";
65763
65763
  const rawIds = blob[LINKED_IDS_CONFIG_KEY];
65764
65764
  const manualIds = [];
65765
65765
  if (Array.isArray(rawIds)) for (const v of rawIds) {
@@ -65791,7 +65791,7 @@ var require_device_manager_addon = __commonJS({
65791
65791
  if (primary !== null) expandContainer(primary.id, byId, byParent, nextVisited, out);
65792
65792
  }
65793
65793
  function resolveLinkedDeviceIds(params) {
65794
- const { selfId, selfLocation, config, candidates } = params;
65794
+ const { selfId, config, candidates } = params;
65795
65795
  const byId = new Map(candidates.map((c) => [c.id, c]));
65796
65796
  const byParent = /* @__PURE__ */ new Map();
65797
65797
  for (const c of candidates) {
@@ -65803,99 +65803,52 @@ var require_device_manager_addon = __commonJS({
65803
65803
  const ids = /* @__PURE__ */ new Set();
65804
65804
  const expand = (id) => expandContainer(id, byId, byParent, /* @__PURE__ */ new Set(), ids);
65805
65805
  for (const c of candidates) if (c.parentDeviceId === selfId) expand(c.id);
65806
- if (config.mode === "auto") {
65807
- if (selfLocation !== null && selfLocation.length > 0) for (const c of candidates) {
65808
- if (c.type === require_dist10.DeviceType.Container) continue;
65809
- if (c.location !== selfLocation) continue;
65810
- const parent = c.parentDeviceId !== null ? byId.get(c.parentDeviceId) : void 0;
65811
- if (parent !== void 0 && parent.type === require_dist10.DeviceType.Container) {
65812
- expand(parent.id);
65813
- continue;
65814
- }
65815
- ids.add(c.id);
65816
- }
65817
- } else for (const id of config.manualIds) if (byId.has(id)) expand(id);
65806
+ for (const id of config.manualIds) if (byId.has(id)) expand(id);
65818
65807
  ids.delete(selfId);
65819
65808
  return [...ids];
65820
65809
  }
65821
- function resolveTrackedEventDeviceIds(config, linkedIds) {
65822
- const raw = config[LINKED_TRACKED_IDS_CONFIG_KEY];
65823
- if (!Array.isArray(raw)) return [];
65824
- const picked = /* @__PURE__ */ new Set();
65825
- for (const v of raw) {
65826
- const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
65827
- if (Number.isInteger(n)) picked.add(n);
65828
- }
65829
- return linkedIds.filter((id) => picked.has(id));
65830
- }
65831
- var LINK_CANDIDATE_PROJECTION = { projection: "slim" };
65832
- function findLocationInvisibleContainers(params) {
65833
- const { selfId, selfLocation, resolvedIds, candidates } = params;
65810
+ function legacyAutoLinkIds(params) {
65811
+ const { selfId, selfLocation, candidates } = params;
65834
65812
  if (selfLocation === null || selfLocation.length === 0) return [];
65813
+ const byId = new Map(candidates.map((c) => [c.id, c]));
65835
65814
  const byParent = /* @__PURE__ */ new Map();
65836
65815
  for (const c of candidates) {
65837
65816
  if (c.parentDeviceId === null) continue;
65838
- const bucket = byParent.get(c.parentDeviceId);
65839
- if (bucket) bucket.push(c);
65817
+ const siblings = byParent.get(c.parentDeviceId);
65818
+ if (siblings) siblings.push(c);
65840
65819
  else byParent.set(c.parentDeviceId, [c]);
65841
65820
  }
65842
- const out = [];
65821
+ const ids = /* @__PURE__ */ new Set();
65822
+ const expand = (id) => expandContainer(id, byId, byParent, /* @__PURE__ */ new Set(), ids);
65843
65823
  for (const c of candidates) {
65844
- if (c.type !== require_dist10.DeviceType.Container) continue;
65845
- if (c.id === selfId) continue;
65824
+ if (c.type === require_dist10.DeviceType.Container) continue;
65846
65825
  if (c.location !== selfLocation) continue;
65847
- let anyResolved = false;
65848
- let anyNullLocation = false;
65849
- let descendantCount = 0;
65850
- const visited = /* @__PURE__ */ new Set([c.id]);
65851
- let frontier = [c.id];
65852
- while (frontier.length > 0) {
65853
- const next = [];
65854
- for (const parentId of frontier) for (const child of byParent.get(parentId) ?? []) {
65855
- if (visited.has(child.id)) continue;
65856
- visited.add(child.id);
65857
- descendantCount += 1;
65858
- if (resolvedIds.has(child.id)) anyResolved = true;
65859
- if (child.location === null) anyNullLocation = true;
65860
- next.push(child.id);
65861
- }
65862
- frontier = next;
65863
- }
65864
- if (descendantCount > 0 && !anyResolved && anyNullLocation) out.push(c.id);
65826
+ if (c.parentDeviceId === selfId) continue;
65827
+ const parent = c.parentDeviceId !== null ? byId.get(c.parentDeviceId) : void 0;
65828
+ if (parent !== void 0 && parent.type === require_dist10.DeviceType.Container) {
65829
+ expand(parent.id);
65830
+ continue;
65831
+ }
65832
+ ids.add(c.id);
65865
65833
  }
65866
- return out;
65834
+ ids.delete(selfId);
65835
+ return [...ids];
65867
65836
  }
65868
- var INVISIBLE_CONTAINER_WARN_CAP = 4096;
65869
- var warnedInvisibleContainers = /* @__PURE__ */ new Set();
65870
- function warnLocationInvisibleContainers(pctx, cameraId, byId, all, resolved) {
65871
- if (resolved.mode !== "auto") return;
65872
- const selfLocation = byId.get(cameraId)?.location ?? null;
65873
- if (selfLocation === null || selfLocation.length === 0) return;
65874
- const invisible = findLocationInvisibleContainers({
65875
- selfId: cameraId,
65876
- selfLocation,
65877
- resolvedIds: new Set(resolved.devices.map((d) => d.deviceId)),
65878
- candidates: all
65879
- });
65880
- for (const containerId of invisible) {
65881
- const key = `${cameraId}:${containerId}`;
65882
- if (warnedInvisibleContainers.has(key)) continue;
65883
- if (warnedInvisibleContainers.size >= INVISIBLE_CONTAINER_WARN_CAP) return;
65884
- warnedInvisibleContainers.add(key);
65885
- pctx.host.ctx.logger.warn("getLinkedDevices: container matches the camera location but is invisible to auto-link \u2014 its children carry no location; re-save the container location to realign", {
65886
- tags: { deviceId: containerId },
65887
- meta: {
65888
- cameraId,
65889
- location: selfLocation
65890
- }
65891
- });
65837
+ function resolveTrackedEventDeviceIds(config, linkedIds) {
65838
+ const raw = config[LINKED_TRACKED_IDS_CONFIG_KEY];
65839
+ if (!Array.isArray(raw)) return [];
65840
+ const picked = /* @__PURE__ */ new Set();
65841
+ for (const v of raw) {
65842
+ const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
65843
+ if (Number.isInteger(n)) picked.add(n);
65892
65844
  }
65845
+ return linkedIds.filter((id) => picked.has(id));
65893
65846
  }
65847
+ var LINK_CANDIDATE_PROJECTION = { projection: "slim" };
65894
65848
  function resolveFor(deviceId, all, byId, blob) {
65895
65849
  const config = parseLinkedDevicesConfig(blob);
65896
65850
  const ids = resolveLinkedDeviceIds({
65897
65851
  selfId: deviceId,
65898
- selfLocation: byId.get(deviceId)?.location ?? null,
65899
65852
  config,
65900
65853
  candidates: all
65901
65854
  });
@@ -65920,10 +65873,7 @@ var require_device_manager_addon = __commonJS({
65920
65873
  async function getLinkedDevices(pctx, input) {
65921
65874
  const { deviceId } = input;
65922
65875
  const [all, blob] = await Promise.all([listAll(pctx, LINK_CANDIDATE_PROJECTION), pctx.settings.readDeviceStore(deviceId)]);
65923
- const byId = new Map(all.map((d) => [d.id, d]));
65924
- const resolved = resolveFor(deviceId, all, byId, blob);
65925
- warnLocationInvisibleContainers(pctx, deviceId, byId, all, resolved);
65926
- return resolved;
65876
+ return resolveFor(deviceId, all, new Map(all.map((d) => [d.id, d])), blob);
65927
65877
  }
65928
65878
  async function getLinkedDevicesBatch(pctx, input) {
65929
65879
  const deviceIds = [...new Set(input.deviceIds)];
@@ -65937,11 +65887,9 @@ var require_device_manager_addon = __commonJS({
65937
65887
  })))]);
65938
65888
  const byId = new Map(all.map((d) => [d.id, d]));
65939
65889
  return deviceIds.map((deviceId, index) => {
65940
- const resolved = resolveFor(deviceId, all, byId, blobs[index] ?? {});
65941
- warnLocationInvisibleContainers(pctx, deviceId, byId, all, resolved);
65942
65890
  return {
65943
65891
  deviceId,
65944
- ...resolved
65892
+ ...resolveFor(deviceId, all, byId, blobs[index] ?? {})
65945
65893
  };
65946
65894
  });
65947
65895
  }
@@ -65950,13 +65898,9 @@ var require_device_manager_addon = __commonJS({
65950
65898
  if (!persisted || persisted.meta.type !== require_dist10.DeviceType.Camera) return null;
65951
65899
  const [all, blob] = await Promise.all([listAll(pctx, LINK_CANDIDATE_PROJECTION), pctx.settings.readDeviceStore(deviceId)]);
65952
65900
  const config = parseLinkedDevicesConfig(blob);
65953
- const options = all.filter((d) => d.id !== deviceId && d.type !== require_dist10.DeviceType.Container).map((d) => ({
65954
- value: String(d.id),
65955
- label: d.location !== null ? `${d.name} (${d.location})` : d.name
65956
- }));
65901
+ const self2 = all.find((d) => d.id === deviceId);
65957
65902
  const linkedIds = resolveLinkedDeviceIds({
65958
65903
  selfId: deviceId,
65959
- selfLocation: all.find((d) => d.id === deviceId)?.location ?? null,
65960
65904
  config,
65961
65905
  candidates: all
65962
65906
  });
@@ -65973,49 +65917,31 @@ var require_device_manager_addon = __commonJS({
65973
65917
  return { sections: [{
65974
65918
  id: "linked-devices",
65975
65919
  title: "Linked devices",
65976
- description: "Companion devices associated with this camera. Device-tree children are always linked; auto mode also links every device sharing the camera location, manual mode links the picked list instead.",
65920
+ description: "Companion devices associated with this camera. Device-tree children are always linked; everything else is the list you pick below. Devices in the same location are suggested first, never linked on their own (D356).",
65977
65921
  order: 70,
65978
- fields: [
65979
- {
65980
- type: "select",
65981
- key: LINKED_MODE_CONFIG_KEY,
65982
- label: "Link mode",
65983
- description: "Auto: children + same-location devices. Manual: children + the list below.",
65984
- options: [{
65985
- value: "auto",
65986
- label: "Auto (location-based)"
65987
- }, {
65988
- value: "manual",
65989
- label: "Manual"
65990
- }],
65991
- value: config.mode
65992
- },
65993
- {
65994
- type: "multiselect",
65995
- key: LINKED_IDS_CONFIG_KEY,
65996
- label: "Manually linked devices",
65997
- description: "Used in manual mode (children stay linked regardless).",
65998
- showWhen: {
65999
- field: LINKED_MODE_CONFIG_KEY,
66000
- equals: "manual"
66001
- },
66002
- options,
66003
- value: config.manualIds.map(String)
65922
+ fields: [{
65923
+ type: "device-multiselect",
65924
+ key: LINKED_IDS_CONFIG_KEY,
65925
+ label: "Linked devices",
65926
+ description: "Pick the companions of this camera. Same-location devices are suggested; device-tree children stay linked regardless.",
65927
+ deviceFilter: {
65928
+ excludeDeviceId: deviceId,
65929
+ excludeTypes: [require_dist10.DeviceType.Container]
66004
65930
  },
66005
- {
66006
- type: "multiselect",
66007
- key: LINKED_TRACKED_IDS_CONFIG_KEY,
66008
- label: "Devices that produce tracked events",
66009
- description: "Linked devices whose state changes materialize a synthetic tracked event on this camera. Default: none (opt-in).",
66010
- options: trackedOptions,
66011
- value: trackedValue
66012
- }
66013
- ]
65931
+ suggestLocation: self2?.location ?? null,
65932
+ value: config.manualIds.map(String)
65933
+ }, {
65934
+ type: "multiselect",
65935
+ key: LINKED_TRACKED_IDS_CONFIG_KEY,
65936
+ label: "Devices that produce tracked events",
65937
+ description: "Linked devices whose state changes materialize a synthetic tracked event on this camera. Default: none (opt-in).",
65938
+ options: trackedOptions,
65939
+ value: trackedValue
65940
+ }]
66014
65941
  }] };
66015
65942
  }
66016
65943
  async function applyLinkedDevicesPatch(pctx, deviceId, patch) {
66017
65944
  const next = { ...await pctx.settings.readDeviceStore(deviceId) };
66018
- if ("_linkedDevicesMode" in patch) next[LINKED_MODE_CONFIG_KEY] = patch["_linkedDevicesMode"] === "manual" ? "manual" : "auto";
66019
65945
  if ("_linkedDeviceIds" in patch) next[LINKED_IDS_CONFIG_KEY] = [...parseLinkedDevicesConfig({ [LINKED_IDS_CONFIG_KEY]: patch[LINKED_IDS_CONFIG_KEY] }).manualIds];
66020
65946
  if ("_linkedDeviceTrackedIds" in patch) {
66021
65947
  const raw = patch[LINKED_TRACKED_IDS_CONFIG_KEY];
@@ -66979,7 +66905,7 @@ var require_device_manager_addon = __commonJS({
66979
66905
  });
66980
66906
  }
66981
66907
  const residual = planNullLocationFills((!repaired && bootRows !== void 0 ? bootRows : await pctx.metaStore.rows.listAll()).map((r) => r.meta));
66982
- for (const [ancestorId, fills] of groupByAncestor(residual)) logger.warn("location cascade misaligned \u2014 location-less descendants under a located ancestor never match location auto-link; re-save the ancestor location to realign", {
66908
+ for (const [ancestorId, fills] of groupByAncestor(residual)) logger.warn("location cascade misaligned \u2014 location-less descendants under a located ancestor never reach the same-location suggestions of the picker; re-save the ancestor location to realign", {
66983
66909
  tags: { deviceId: ancestorId },
66984
66910
  meta: {
66985
66911
  location: fills[0]?.location,
@@ -67876,6 +67802,64 @@ var require_device_manager_addon = __commonJS({
67876
67802
  }
67877
67803
  });
67878
67804
  }
67805
+ var LINKED_MANUAL_BACKFILL_MARKER_KEY = "_linkedDevicesManualBackfillVersion";
67806
+ function planManualBackfill(params) {
67807
+ const { selfId, selfLocation, blob, candidates } = params;
67808
+ const current = parseLinkedDevicesConfig(blob).manualIds;
67809
+ if (blob["_linkedDevicesMode"] === "manual") return {
67810
+ write: false,
67811
+ manualIds: current
67812
+ };
67813
+ const merged = [...current];
67814
+ for (const id of legacyAutoLinkIds({
67815
+ selfId,
67816
+ selfLocation,
67817
+ candidates
67818
+ })) if (!merged.includes(id)) merged.push(id);
67819
+ return {
67820
+ write: true,
67821
+ manualIds: merged
67822
+ };
67823
+ }
67824
+ async function runLinkedDevicesManualBackfillAtBoot(pctx) {
67825
+ const logger = pctx.host.ctx.logger;
67826
+ const addonStore = await pctx.settings.readAddonStore();
67827
+ const markerRaw = addonStore[LINKED_MANUAL_BACKFILL_MARKER_KEY];
67828
+ if ((typeof markerRaw === "number" ? markerRaw : 0) >= 1) return;
67829
+ const all = await listAll(pctx, LINK_CANDIDATE_PROJECTION);
67830
+ let written = 0;
67831
+ let linked = 0;
67832
+ for (const cam of all) {
67833
+ if (cam.type !== require_dist10.DeviceType.Camera) continue;
67834
+ const blob = await pctx.settings.readDeviceStore(cam.id);
67835
+ const plan = planManualBackfill({
67836
+ selfId: cam.id,
67837
+ selfLocation: cam.location ?? null,
67838
+ blob,
67839
+ candidates: all
67840
+ });
67841
+ if (!plan.write) continue;
67842
+ await pctx.settings.writeDeviceStore(cam.id, {
67843
+ ...blob,
67844
+ [LINKED_MODE_CONFIG_KEY]: "manual",
67845
+ [LINKED_IDS_CONFIG_KEY]: [...plan.manualIds]
67846
+ });
67847
+ written += 1;
67848
+ linked += plan.manualIds.length;
67849
+ logger.info("linked devices: auto links materialised into the manual list (D356)", {
67850
+ tags: { deviceId: cam.id },
67851
+ meta: { manualIds: plan.manualIds }
67852
+ });
67853
+ }
67854
+ await pctx.settings.writeAddonStore({
67855
+ ...addonStore,
67856
+ [LINKED_MANUAL_BACKFILL_MARKER_KEY]: 1
67857
+ });
67858
+ logger.info("linked devices: manual backfill complete (D356)", { meta: {
67859
+ camerasWritten: written,
67860
+ linksMaterialised: linked
67861
+ } });
67862
+ }
67879
67863
  function decodeAddonStore(raw) {
67880
67864
  const nextDeviceId = raw["nextDeviceId"];
67881
67865
  const locations = raw["locations"];
@@ -69429,6 +69413,11 @@ var require_device_manager_addon = __commonJS({
69429
69413
  } catch (err) {
69430
69414
  this.ctx.logger.warn("location backfill failed \u2014 fleet boots without it", { meta: { error: require_dist10.errMsg(err) } });
69431
69415
  }
69416
+ try {
69417
+ await runLinkedDevicesManualBackfillAtBoot(pctx);
69418
+ } catch (err) {
69419
+ this.ctx.logger.warn("linked-devices manual backfill failed \u2014 auto links are NOT materialised", { meta: { error: require_dist10.errMsg(err) } });
69420
+ }
69432
69421
  const provider = {
69433
69422
  resolveDeviceOwnerSync: (deviceId) => resolveDeviceOwnerSync(pctx, deviceId),
69434
69423
  resolveNativeCapOwnerSync: (capName, deviceId) => resolveNativeCapOwnerSync(pctx, capName, deviceId),
@@ -69664,7 +69653,7 @@ var require_hub_forwarder = __commonJS({
69664
69653
  [Symbol.toStringTag]: { value: "Module" }
69665
69654
  });
69666
69655
  require_chunk_Cek0wNdY();
69667
- var require_dist10 = require_dist_0fjBDzUu();
69656
+ var require_dist10 = require_dist_DNwhsXWi();
69668
69657
  var require_formatter = require_formatter_DqAKDlvN();
69669
69658
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
69670
69659
  var HubForwarderDestination = class {
@@ -69801,7 +69790,7 @@ var require_liveness_monitor_addon = __commonJS({
69801
69790
  "use strict";
69802
69791
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
69803
69792
  require_chunk_Cek0wNdY();
69804
- var require_dist10 = require_dist_0fjBDzUu();
69793
+ var require_dist10 = require_dist_DNwhsXWi();
69805
69794
  var NO_DEVICES = "liveness:no-devices";
69806
69795
  var ALL_OFFLINE = "liveness:all-devices-offline";
69807
69796
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -69991,7 +69980,7 @@ var require_local_auth_addon = __commonJS({
69991
69980
  [Symbol.toStringTag]: { value: "Module" }
69992
69981
  });
69993
69982
  var require_chunk = require_chunk_Cek0wNdY();
69994
- var require_dist10 = require_dist_0fjBDzUu();
69983
+ var require_dist10 = require_dist_DNwhsXWi();
69995
69984
  var node_crypto = __require("crypto");
69996
69985
  node_crypto = require_chunk.__toESM(node_crypto);
69997
69986
  var crypto$1 = __require("crypto");
@@ -77804,7 +77793,7 @@ var require_loki_logging = __commonJS({
77804
77793
  [Symbol.toStringTag]: { value: "Module" }
77805
77794
  });
77806
77795
  require_chunk_Cek0wNdY();
77807
- var require_dist10 = require_dist_0fjBDzUu();
77796
+ var require_dist10 = require_dist_DNwhsXWi();
77808
77797
  function sanitizeLabelName(raw) {
77809
77798
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
77810
77799
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -78369,7 +78358,7 @@ var require_native_metrics_addon = __commonJS({
78369
78358
  [Symbol.toStringTag]: { value: "Module" }
78370
78359
  });
78371
78360
  var require_chunk = require_chunk_Cek0wNdY();
78372
- var require_dist10 = require_dist_0fjBDzUu();
78361
+ var require_dist10 = require_dist_DNwhsXWi();
78373
78362
  var node_fs_promises = __require("fs/promises");
78374
78363
  var node_child_process = __require("child_process");
78375
78364
  var node_util = __require("util");
@@ -80953,7 +80942,7 @@ var require_filesystem_storage_addon = __commonJS({
80953
80942
  [Symbol.toStringTag]: { value: "Module" }
80954
80943
  });
80955
80944
  var require_chunk = require_chunk_Cek0wNdY();
80956
- var require_dist10 = require_dist_0fjBDzUu();
80945
+ var require_dist10 = require_dist_DNwhsXWi();
80957
80946
  var node_crypto = __require("crypto");
80958
80947
  var node_fs_promises = __require("fs/promises");
80959
80948
  var node_path = __require("path");
@@ -82069,8 +82058,8 @@ var require_sqlite_settings_addon = __commonJS({
82069
82058
  [Symbol.toStringTag]: { value: "Module" }
82070
82059
  });
82071
82060
  var require_chunk = require_chunk_Cek0wNdY();
82072
- var require_dist10 = require_dist_0fjBDzUu();
82073
- var require_retired_settings_keys = require_retired_settings_keys_pL2Nq6KT();
82061
+ var require_dist10 = require_dist_DNwhsXWi();
82062
+ var require_retired_settings_keys = require_retired_settings_keys_CUXClAIQ();
82074
82063
  var node_crypto = __require("crypto");
82075
82064
  var node_fs = __require("fs");
82076
82065
  var node_module = __require("module");
@@ -84560,7 +84549,7 @@ var require_storage_orchestrator_addon = __commonJS({
84560
84549
  [Symbol.toStringTag]: { value: "Module" }
84561
84550
  });
84562
84551
  var require_chunk = require_chunk_Cek0wNdY();
84563
- var require_dist10 = require_dist_0fjBDzUu();
84552
+ var require_dist10 = require_dist_DNwhsXWi();
84564
84553
  var require_hub_cap_forward = require_hub_cap_forward_DmHNjbB0();
84565
84554
  var zod = require_zod();
84566
84555
  var node_crypto = __require("crypto");
@@ -87511,7 +87500,7 @@ var require_system_config_addon = __commonJS({
87511
87500
  [Symbol.toStringTag]: { value: "Module" }
87512
87501
  });
87513
87502
  require_chunk_Cek0wNdY();
87514
- var require_dist10 = require_dist_0fjBDzUu();
87503
+ var require_dist10 = require_dist_DNwhsXWi();
87515
87504
  var SECTION_TITLES = {
87516
87505
  server: "Server",
87517
87506
  auth: "Authentication"
@@ -105572,7 +105561,7 @@ var require_winston_logging = __commonJS({
105572
105561
  [Symbol.toStringTag]: { value: "Module" }
105573
105562
  });
105574
105563
  var require_chunk = require_chunk_Cek0wNdY();
105575
- var require_dist10 = require_dist_0fjBDzUu();
105564
+ var require_dist10 = require_dist_DNwhsXWi();
105576
105565
  var require_formatter = require_formatter_DqAKDlvN();
105577
105566
  var node_path = __require("path");
105578
105567
  node_path = require_chunk.__toESM(node_path);
@@ -130153,7 +130142,7 @@ var require_dist3 = __commonJS({
130153
130142
  "use strict";
130154
130143
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
130155
130144
  var require_chunk = require_chunk_Cek0wNdY();
130156
- var require_dist10 = require_dist_0fjBDzUu();
130145
+ var require_dist10 = require_dist_DNwhsXWi();
130157
130146
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
130158
130147
  require_alerts();
130159
130148
  var require_formatter = require_formatter_DqAKDlvN();
@@ -218810,7 +218799,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
218810
218799
  value: zod.z.unknown(),
218811
218800
  description: zod.z.string().optional()
218812
218801
  });
218813
- var LinkedDevicesModeSchema = zod.z.enum(["auto", "manual"]);
218802
+ var LinkedDevicesModeSchema = zod.z.enum(["manual"]);
218814
218803
  var LinkedDeviceSchema = zod.z.object({
218815
218804
  deviceId: zod.z.number(),
218816
218805
  name: zod.z.string(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "camstack",
3
- "version": "1.2.91",
3
+ "version": "1.2.92",
4
4
  "description": "CLI tool for managing and running CamStack server",
5
5
  "keywords": [
6
6
  "camstack",