@camstack/system 1.2.353 → 1.2.354

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.
Files changed (66) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.js +1 -1
  8. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  9. package/dist/builtins/autotrack/index.js +1 -1
  10. package/dist/builtins/autotrack/index.mjs +1 -1
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  13. package/dist/builtins/calendars/calendars.addon.js +1 -1
  14. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  15. package/dist/builtins/camera-grid/index.js +1 -1
  16. package/dist/builtins/camera-grid/index.mjs +1 -1
  17. package/dist/builtins/composer/composer.addon.js +13 -3
  18. package/dist/builtins/composer/composer.addon.mjs +13 -3
  19. package/dist/builtins/console-logging/index.js +1 -1
  20. package/dist/builtins/console-logging/index.mjs +1 -1
  21. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  22. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  23. package/dist/builtins/device-manager/device-manager.addon.js +3 -3
  24. package/dist/builtins/device-manager/device-manager.addon.mjs +3 -3
  25. package/dist/builtins/hub-forwarder/index.js +1 -1
  26. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  27. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  28. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  29. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  30. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  31. package/dist/builtins/local-network/local-network.addon.d.ts +21 -6
  32. package/dist/builtins/local-network/local-network.addon.js +81 -54
  33. package/dist/builtins/local-network/local-network.addon.mjs +81 -55
  34. package/dist/builtins/loki-logging/index.js +1 -1
  35. package/dist/builtins/loki-logging/index.mjs +1 -1
  36. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  37. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  38. package/dist/builtins/platform-probe/index.js +1 -1
  39. package/dist/builtins/platform-probe/index.mjs +1 -1
  40. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  41. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  42. package/dist/builtins/snapshot/index.js +1 -1
  43. package/dist/builtins/snapshot/index.mjs +1 -1
  44. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  45. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  46. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  47. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  48. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +2 -2
  49. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +2 -2
  50. package/dist/builtins/system-config/system-config.addon.js +1 -1
  51. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  52. package/dist/builtins/winston-logging/index.js +1 -1
  53. package/dist/builtins/winston-logging/index.mjs +1 -1
  54. package/dist/{child-cap-dispatch-C6IpRb4P.mjs → child-cap-dispatch-C1x1kNJK.mjs} +1 -1
  55. package/dist/{child-cap-dispatch-CvYlCq60.js → child-cap-dispatch-CRqYKHAb.js} +1 -1
  56. package/dist/{composition-sources-CAFDvTRs.js → composition-sources-0nuWOdNd.js} +1 -1
  57. package/dist/{composition-sources-BGlDi3CT.mjs → composition-sources-DzkEFd8q.mjs} +1 -1
  58. package/dist/{dist-Cm556q2j.mjs → dist-DVyXxn41.mjs} +145 -33
  59. package/dist/{dist-CXVXFdJX.js → dist-DePB7uwU.js} +156 -32
  60. package/dist/http/reverse-proxy.d.ts +11 -1
  61. package/dist/index.js +55 -12
  62. package/dist/index.mjs +55 -12
  63. package/dist/kernel/config-schema.d.ts +1 -0
  64. package/dist/{retired-settings-keys-D24IW4qo.js → retired-settings-keys-BTKZdPn6.js} +1 -1
  65. package/dist/{retired-settings-keys-DzkSqnH0.mjs → retired-settings-keys-DFur4hJF.mjs} +1 -1
  66. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_child_cap_dispatch = require("./child-cap-dispatch-CvYlCq60.js");
2
+ const require_child_cap_dispatch = require("./child-cap-dispatch-CRqYKHAb.js");
3
3
  const require_custom_action_registry = require("./custom-action-registry-acBY3mHA.js");
4
4
  let node_path = require("node:path");
5
5
  node_path = require_chunk.__toESM(node_path);
@@ -1,4 +1,4 @@
1
- import { Ft as installManifestNativeDeps, H as createUdsLoggerWithControl, It as resolveAddonClass, St as validateProviderRegistrations, Tn as emitHeapDiagnosticReport, U as LocalChildClient, _t as getWorkerNativeCapProvider, bt as setWorkerNativeCapsChangeListener, en as RUNNER_RSS_BUDGET_ENV, f as installManifestSystemDeps, g as createUdsAddonContext, i as killOwnRunnerGroupAfterParentLoss, n as createChildCapDispatch, p as installManifestPythonDeps, pn as startRunnerHeapWatch, u as startRunnerParentDeathWatchdog, vt as getWorkerNativeCapSnapshot } from "./child-cap-dispatch-C6IpRb4P.mjs";
1
+ import { Ft as installManifestNativeDeps, H as createUdsLoggerWithControl, It as resolveAddonClass, St as validateProviderRegistrations, Tn as emitHeapDiagnosticReport, U as LocalChildClient, _t as getWorkerNativeCapProvider, bt as setWorkerNativeCapsChangeListener, en as RUNNER_RSS_BUDGET_ENV, f as installManifestSystemDeps, g as createUdsAddonContext, i as killOwnRunnerGroupAfterParentLoss, n as createChildCapDispatch, p as installManifestPythonDeps, pn as startRunnerHeapWatch, u as startRunnerParentDeathWatchdog, vt as getWorkerNativeCapSnapshot } from "./child-cap-dispatch-C1x1kNJK.mjs";
2
2
  import { t as CustomActionRegistry } from "./custom-action-registry-B4Cf4O_X.mjs";
3
3
  import { register } from "node:module";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CXVXFdJX.js");
6
+ const require_dist = require("../../dist-DePB7uwU.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { H as addonPagesCapability, Jn as errMsg, Yn as BaseAddon, br as EventCategory } from "../../dist-Cm556q2j.mjs";
1
+ import { Sr as EventCategory, U as addonPagesCapability, Xn as errMsg, Zn as BaseAddon } from "../../dist-DVyXxn41.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CXVXFdJX.js");
6
+ const require_dist = require("../../dist-DePB7uwU.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { Jn as errMsg, W as addonWidgetsCapability, Yn as BaseAddon, br as EventCategory } from "../../dist-Cm556q2j.mjs";
1
+ import { G as addonWidgetsCapability, Sr as EventCategory, Xn as errMsg, Zn as BaseAddon } from "../../dist-DVyXxn41.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CXVXFdJX.js");
6
+ const require_dist = require("../../dist-DePB7uwU.js");
7
7
  //#region src/builtins/alerts/device-label.ts
8
8
  /**
9
9
  * Operator-facing device label for alert messages.
@@ -1,4 +1,4 @@
1
- import { G as alertsCapability, Jn as errMsg, Yn as BaseAddon, ar as createEvent, br as EventCategory, n as AlertSchema } from "../../dist-Cm556q2j.mjs";
1
+ import { K as alertsCapability, Sr as EventCategory, Xn as errMsg, Zn as BaseAddon, n as AlertSchema, sr as createEvent } from "../../dist-DVyXxn41.mjs";
2
2
  //#region src/builtins/alerts/device-label.ts
3
3
  /**
4
4
  * Operator-facing device label for alert messages.
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CXVXFdJX.js");
6
+ const require_dist = require("../../dist-DePB7uwU.js");
7
7
  //#region src/builtins/autotrack/autotrack-config.ts
8
8
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
9
9
  deadZoneFraction: .5,
@@ -1,4 +1,4 @@
1
- import { J as bareAddonId, Jn as errMsg, Yn as BaseAddon, br as EventCategory, dr as isEvent, on as ptzAutotrackCapability, x as FIRST_LEVEL_MACRO_CLASSES } from "../../dist-Cm556q2j.mjs";
1
+ import { S as FIRST_LEVEL_MACRO_CLASSES, Sr as EventCategory, Xn as errMsg, Y as bareAddonId, Zn as BaseAddon, cn as ptzAutotrackCapability, pr as isEvent } from "../../dist-DVyXxn41.mjs";
2
2
  //#region src/builtins/autotrack/autotrack-config.ts
3
3
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
4
4
  deadZoneFraction: .5,
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CXVXFdJX.js");
6
+ const require_dist = require("../../dist-DePB7uwU.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let buffer = require("buffer");
9
9
  let node_fs_promises = require("node:fs/promises");
@@ -1,4 +1,4 @@
1
- import { Cn as storageOccupancyCapability, Yn as BaseAddon, br as EventCategory, fr as nodePin, h as DATABASE_SNAPSHOT_SUFFIX, q as backupCapability, qt as mayWriteToLocation, yr as toNodeId } from "../../dist-Cm556q2j.mjs";
1
+ import { J as backupCapability, Jt as mayWriteToLocation, Sr as EventCategory, Tn as storageOccupancyCapability, Zn as BaseAddon, g as DATABASE_SNAPSHOT_SUFFIX, mr as nodePin, xr as toNodeId } from "../../dist-DVyXxn41.mjs";
2
2
  import { randomBytes, randomUUID } from "node:crypto";
3
3
  import { Buffer as Buffer$1 } from "buffer";
4
4
  import * as fsp from "node:fs/promises";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CXVXFdJX.js");
6
+ const require_dist = require("../../dist-DePB7uwU.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let zod = require("zod");
9
9
  //#region src/builtins/calendars/calendar-color.ts
@@ -1,4 +1,4 @@
1
- import { Q as calendarsCapability, Yn as BaseAddon, f as CalendarPreferencesSchema } from "../../dist-Cm556q2j.mjs";
1
+ import { $ as calendarsCapability, Zn as BaseAddon, p as CalendarPreferencesSchema } from "../../dist-DVyXxn41.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { z } from "zod";
4
4
  //#region src/builtins/calendars/calendar-color.ts
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CXVXFdJX.js");
6
+ const require_dist = require("../../dist-DePB7uwU.js");
7
7
  let zod = require("zod");
8
8
  let _camstack_types_node = require("@camstack/types/node");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { $ as cameraGridLayoutCapability, Gn as DeviceFeature, Jn as errMsg, Jt as memoizePinnedFfmpeg, Pn as buildFfmpegArgs, Tn as streamCatalogCapability, Yn as BaseAddon, Zt as motionCapability, ar as createEvent, bn as snapshotCapability, br as EventCategory, ft as declarationOwnerNodeId, i as BaseDevice, k as MOTION_CLOSE_AFTER_MS, lr as hydrateSchema, qn as DeviceType, v as DERIVED_CAMERA_SILENCED_CAP_NAMES, y as DeclaredDevices } from "../../dist-Cm556q2j.mjs";
1
+ import { A as MOTION_CLOSE_AFTER_MS, Dn as streamCatalogCapability, In as buildFfmpegArgs, Qt as motionCapability, Sn as snapshotCapability, Sr as EventCategory, Xn as errMsg, Yn as DeviceType, Yt as memoizePinnedFfmpeg, Zn as BaseAddon, b as DeclaredDevices, dr as hydrateSchema, et as cameraGridLayoutCapability, i as BaseDevice, pt as declarationOwnerNodeId, qn as DeviceFeature, sr as createEvent, y as DERIVED_CAMERA_SILENCED_CAP_NAMES } from "../../dist-DVyXxn41.mjs";
2
2
  import { z } from "zod";
3
3
  import { FfmpegProcess } from "@camstack/types/node";
4
4
  import { join } from "node:path";
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CXVXFdJX.js");
7
- const require_composition_sources = require("../../composition-sources-CAFDvTRs.js");
6
+ const require_dist = require("../../dist-DePB7uwU.js");
7
+ const require_composition_sources = require("../../composition-sources-0nuWOdNd.js");
8
8
  let zod = require("zod");
9
9
  //#region src/builtins/shared/device-state-changed.ts
10
10
  /** Structural narrowing helper for untrusted bus payloads. */
@@ -1308,6 +1308,16 @@ function ownFieldReading(records, key) {
1308
1308
  * - Derived fields are evaluated before accumulators, and every field reading
1309
1309
  * an own field that changed is re-evaluated in the same pass.
1310
1310
  */
1311
+ /**
1312
+ * Whether a `rose` call of this field has ever committed a level. Only such a
1313
+ * field can FLAP: a source that never answered (late at boot, or an
1314
+ * expression that never succeeded) has no level to protect, so its first
1315
+ * answered reading is a first observation, not a recovery, and must count.
1316
+ */
1317
+ function hasObservedRoseLevel(memory) {
1318
+ for (const call of memory.calls.values()) if (call.kind === "rose" && call.priorLevel !== void 0) return true;
1319
+ return false;
1320
+ }
1311
1321
  function strictFiniteAdvance(previous, next) {
1312
1322
  return typeof next === "number" && Number.isFinite(next) && (previous === null || next > previous);
1313
1323
  }
@@ -1355,7 +1365,7 @@ function evaluateFields(host, keys, now) {
1355
1365
  const record = next.get(key);
1356
1366
  if (record === void 0) continue;
1357
1367
  const candidateMemory = require_dist.cloneStatefulExpressionMemory(record.expressionMemory);
1358
- if (record.outcome?.state === "unavailable") require_dist.disarmRoseMemory(candidateMemory);
1368
+ if (record.outcome?.state === "unavailable" && hasObservedRoseLevel(record.expressionMemory)) require_dist.disarmRoseMemory(candidateMemory);
1359
1369
  const outcome = require_dist.evaluateCompositionField({
1360
1370
  source: record.plan.source,
1361
1371
  read,
@@ -1,5 +1,5 @@
1
- import { Bn as compositionSliceKey, Fn as cloneStatefulExpressionMemory, Hn as createStatefulExpressionMemory, In as composedDeviceRef, Jn as errMsg, Ln as composedDeviceStableId, Nn as COMPOSER_ADDON_ID, Rn as compositionFeatureEnabled, Un as disarmRoseMemory, Vn as compositionSourceKey, Wn as toExpressionValue, X as buildCapabilityLookup, Yn as BaseAddon, ar as createEvent, br as EventCategory, c as COMPOSED_ITEM_FIXED_FIELDS, i as BaseDevice, nt as compositionFieldKey, qn as DeviceType, rn as planComposition, t as ALL_CAPABILITY_DEFINITIONS, tt as composerCapability, wt as evaluateCompositionField, y as DeclaredDevices, zn as compositionItemFieldPath } from "../../dist-Cm556q2j.mjs";
2
- import { n as normalizedNativeOwner } from "../../composition-sources-BGlDi3CT.mjs";
1
+ import { Bn as compositionFeatureEnabled, Fn as COMPOSER_ADDON_ID, Gn as disarmRoseMemory, Hn as compositionSliceKey, Kn as toExpressionValue, Ln as cloneStatefulExpressionMemory, Rn as composedDeviceRef, Sr as EventCategory, Tt as evaluateCompositionField, Un as compositionSourceKey, Vn as compositionItemFieldPath, Wn as createStatefulExpressionMemory, Xn as errMsg, Yn as DeviceType, Z as buildCapabilityLookup, Zn as BaseAddon, an as planComposition, b as DeclaredDevices, i as BaseDevice, l as COMPOSED_ITEM_FIXED_FIELDS, nt as composerCapability, rt as compositionFieldKey, sr as createEvent, t as ALL_CAPABILITY_DEFINITIONS, zn as composedDeviceStableId } from "../../dist-DVyXxn41.mjs";
2
+ import { n as normalizedNativeOwner } from "../../composition-sources-DzkEFd8q.mjs";
3
3
  import { z } from "zod";
4
4
  //#region src/builtins/shared/device-state-changed.ts
5
5
  /** Structural narrowing helper for untrusted bus payloads. */
@@ -1303,6 +1303,16 @@ function ownFieldReading(records, key) {
1303
1303
  * - Derived fields are evaluated before accumulators, and every field reading
1304
1304
  * an own field that changed is re-evaluated in the same pass.
1305
1305
  */
1306
+ /**
1307
+ * Whether a `rose` call of this field has ever committed a level. Only such a
1308
+ * field can FLAP: a source that never answered (late at boot, or an
1309
+ * expression that never succeeded) has no level to protect, so its first
1310
+ * answered reading is a first observation, not a recovery, and must count.
1311
+ */
1312
+ function hasObservedRoseLevel(memory) {
1313
+ for (const call of memory.calls.values()) if (call.kind === "rose" && call.priorLevel !== void 0) return true;
1314
+ return false;
1315
+ }
1306
1316
  function strictFiniteAdvance(previous, next) {
1307
1317
  return typeof next === "number" && Number.isFinite(next) && (previous === null || next > previous);
1308
1318
  }
@@ -1350,7 +1360,7 @@ function evaluateFields(host, keys, now) {
1350
1360
  const record = next.get(key);
1351
1361
  if (record === void 0) continue;
1352
1362
  const candidateMemory = cloneStatefulExpressionMemory(record.expressionMemory);
1353
- if (record.outcome?.state === "unavailable") disarmRoseMemory(candidateMemory);
1363
+ if (record.outcome?.state === "unavailable" && hasObservedRoseLevel(record.expressionMemory)) disarmRoseMemory(candidateMemory);
1354
1364
  const outcome = evaluateCompositionField({
1355
1365
  source: record.plan.source,
1356
1366
  read,
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CXVXFdJX.js");
6
+ const require_dist = require("../../dist-DePB7uwU.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  //#region src/builtins/console-logging/console-destination.ts
9
9
  var LEVEL_RANK = {
@@ -1,4 +1,4 @@
1
- import { Ut as logDestinationCapability, Yn as BaseAddon } from "../../dist-Cm556q2j.mjs";
1
+ import { Wt as logDestinationCapability, Zn as BaseAddon } from "../../dist-DVyXxn41.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  //#region src/builtins/console-logging/console-destination.ts
4
4
  var LEVEL_RANK = {
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("../../chunk-Cek0wNdY.js");
3
- const require_dist = require("../../dist-CXVXFdJX.js");
4
- const require_composition_sources = require("../../composition-sources-CAFDvTRs.js");
3
+ const require_dist = require("../../dist-DePB7uwU.js");
4
+ const require_composition_sources = require("../../composition-sources-0nuWOdNd.js");
5
5
  let node_crypto = require("node:crypto");
6
6
  let _camstack_types_node = require("@camstack/types/node");
7
7
  let node_fs_promises = require("node:fs/promises");
@@ -1,5 +1,5 @@
1
- import { In as composedDeviceRef, Jn as errMsg, On as validateComposition, Qt as normalizeCoreBlockWrite, Vn as compositionSourceKey, X as buildCapabilityLookup, Yn as BaseAddon, at as coreBlockComposition, cn as replacedFieldKeys, ct as coreBlocksCapability, d as CORE_BLOCK_ADDON_PREFIX, dn as resolveCoreBlockFiles, gt as describeComposableCaps, it as coreBlockAddonId, l as COMPOSER_RUNNER_ID, lr as hydrateSchema, ot as coreBlockIdFromAddonId, p as CoreBlockSchema, rn as planComposition, rt as compositionSourceRefs, st as coreBlockSourceKind, t as ALL_CAPABILITY_DEFINITIONS, u as CORE_BLOCKS_ADDON_ID, un as resolveCoreBlockEntry, y as DeclaredDevices } from "../../dist-Cm556q2j.mjs";
2
- import { t as describeCompositionSources } from "../../composition-sources-BGlDi3CT.mjs";
1
+ import { $t as normalizeCoreBlockWrite, An as validateComposition, Rn as composedDeviceRef, Un as compositionSourceKey, Xn as errMsg, Z as buildCapabilityLookup, Zn as BaseAddon, _t as describeComposableCaps, an as planComposition, at as coreBlockAddonId, b as DeclaredDevices, ct as coreBlockSourceKind, d as CORE_BLOCKS_ADDON_ID, dr as hydrateSchema, f as CORE_BLOCK_ADDON_PREFIX, fn as resolveCoreBlockEntry, it as compositionSourceRefs, lt as coreBlocksCapability, m as CoreBlockSchema, ot as coreBlockComposition, pn as resolveCoreBlockFiles, st as coreBlockIdFromAddonId, t as ALL_CAPABILITY_DEFINITIONS, u as COMPOSER_RUNNER_ID, un as replacedFieldKeys } from "../../dist-DVyXxn41.mjs";
2
+ import { t as describeCompositionSources } from "../../composition-sources-DzkEFd8q.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { customizationBlockName } from "@camstack/types/node";
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CXVXFdJX.js");
7
- const require_retired_settings_keys = require("../../retired-settings-keys-D24IW4qo.js");
6
+ const require_dist = require("../../dist-DePB7uwU.js");
7
+ const require_retired_settings_keys = require("../../retired-settings-keys-BTKZdPn6.js");
8
8
  let zod = require("zod");
9
9
  let node_crypto = require("node:crypto");
10
10
  let _camstack_types_node = require("@camstack/types/node");
@@ -4898,7 +4898,7 @@ async function reloadMigratedDevices(pctx, targets) {
4898
4898
  * keyed by the number in a separate store, and until 2026-09-01 they simply
4899
4899
  * stayed put. Measured on the live hub after replacing a Hikvision (id 618)
4900
4900
  * with a Reolink: device 618 — Reolink hardware — was dialled at
4901
- * `192.168.x.x:80` with `deviceCache.model="DS-2DE2A404IW-DE3/W"`, the
4901
+ * `192.168.10.245:80` with `deviceCache.model="DS-2DE2A404IW-DE3/W"`, the
4902
4902
  * Hikvision's address, credentials and cached model, and never came online.
4903
4903
  * Device 4362 wore the Reolink's config on Hikvision hardware. The two devices
4904
4904
  * were wearing each other's identity.
@@ -1,5 +1,5 @@
1
- import { $t as normalizeUnit, At as formatMinutes, C as FieldClaimSchema, Ct as enumerateSchemaFields, E as LocationIconIdSchema, Et as expandContainer, F as STREAM_PROFILE_META, Gn as DeviceFeature, Ht as locationIconKey, Jn as errMsg, Kn as DeviceRole, O as MINUTES_PER_DAY, Rt as legacyAutoLinkIds, S as FieldClaimModeSchema, St as enumerateItemArrayFields, Yn as BaseAddon, Z as buildStreamParamsConfigSchema, _ as DAY_NAMES, _t as deviceExtensionCapability, b as DeviceStatusSchema, br as EventCategory, bt as deviceStatusCapability, lt as createDeviceExtensionProvider, mn as runtimeStatePolicyFor, mt as defineExtensionSlotProvider, nn as parseStreamParamsFormPatch, o as CAMERA_SWITCH_ORDER, qn as DeviceType, s as CAP_NAMES_WITH_STATUS, t as ALL_CAPABILITY_DEFINITIONS, tr as WELL_KNOWN_TAB_MAP, ur as isDeviceConfigCap, vr as sleep$1, vt as deviceManagerCapability, yn as siteZoneKey, yt as deviceStateCapability } from "../../dist-Cm556q2j.mjs";
2
- import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-DzkSqnH0.mjs";
1
+ import { C as FieldClaimModeSchema, Ct as enumerateItemArrayFields, D as LocationIconIdSchema, Dt as expandContainer, I as STREAM_PROFILE_META, Jn as DeviceRole, Q as buildStreamParamsConfigSchema, Sr as EventCategory, Ut as locationIconKey, Xn as errMsg, Yn as DeviceType, Zn as BaseAddon, br as sleep$1, bt as deviceStateCapability, c as CAP_NAMES_WITH_STATUS, en as normalizeUnit, fr as isDeviceConfigCap, gn as runtimeStatePolicyFor, ht as defineExtensionSlotProvider, jt as formatMinutes, k as MINUTES_PER_DAY, o as CAMERA_SWITCH_ORDER, qn as DeviceFeature, rn as parseStreamParamsFormPatch, rr as WELL_KNOWN_TAB_MAP, t as ALL_CAPABILITY_DEFINITIONS, ut as createDeviceExtensionProvider, v as DAY_NAMES, vt as deviceExtensionCapability, w as FieldClaimSchema, wt as enumerateSchemaFields, x as DeviceStatusSchema, xn as siteZoneKey, xt as deviceStatusCapability, yt as deviceManagerCapability, zt as legacyAutoLinkIds } from "../../dist-DVyXxn41.mjs";
2
+ import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-DFur4hJF.mjs";
3
3
  import { z } from "zod";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { canonicalDeviceFingerprint } from "@camstack/types/node";
@@ -4893,7 +4893,7 @@ async function reloadMigratedDevices(pctx, targets) {
4893
4893
  * keyed by the number in a separate store, and until 2026-09-01 they simply
4894
4894
  * stayed put. Measured on the live hub after replacing a Hikvision (id 618)
4895
4895
  * with a Reolink: device 618 — Reolink hardware — was dialled at
4896
- * `192.168.x.x:80` with `deviceCache.model="DS-2DE2A404IW-DE3/W"`, the
4896
+ * `192.168.10.245:80` with `deviceCache.model="DS-2DE2A404IW-DE3/W"`, the
4897
4897
  * Hikvision's address, credentials and cached model, and never came online.
4898
4898
  * Device 4362 wore the Reolink's config on Hikvision hardware. The two devices
4899
4899
  * were wearing each other's identity.
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CXVXFdJX.js");
6
+ const require_dist = require("../../dist-DePB7uwU.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  //#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
9
9
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
@@ -1,4 +1,4 @@
1
- import { Ut as logDestinationCapability, Yn as BaseAddon } from "../../dist-Cm556q2j.mjs";
1
+ import { Wt as logDestinationCapability, Zn as BaseAddon } from "../../dist-DVyXxn41.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  //#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
4
4
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../../chunk-Cek0wNdY.js");
3
- const require_dist = require("../../dist-CXVXFdJX.js");
3
+ const require_dist = require("../../dist-DePB7uwU.js");
4
4
  //#region src/builtins/liveness-monitor/liveness-checks.ts
5
5
  var NO_DEVICES = "liveness:no-devices";
6
6
  var ALL_OFFLINE = "liveness:all-devices-offline";
@@ -1,4 +1,4 @@
1
- import { A as RECORDING_SOURCE_CAMSTACK_ADDON, Jn as errMsg, N as RecordingStatusSchema, Yn as BaseAddon, ar as createEvent, br as EventCategory } from "../../dist-Cm556q2j.mjs";
1
+ import { P as RecordingStatusSchema, Sr as EventCategory, Xn as errMsg, Zn as BaseAddon, j as RECORDING_SOURCE_CAMSTACK_ADDON, sr as createEvent } from "../../dist-DVyXxn41.mjs";
2
2
  //#region src/builtins/liveness-monitor/liveness-checks.ts
3
3
  var NO_DEVICES = "liveness:no-devices";
4
4
  var ALL_OFFLINE = "liveness:all-devices-offline";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CXVXFdJX.js");
6
+ const require_dist = require("../../dist-DePB7uwU.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  node_crypto = require_chunk.__toESM(node_crypto);
9
9
  let crypto$1 = require("crypto");
@@ -1,5 +1,5 @@
1
1
  import { i as __require, o as __toESM, t as __commonJSMin } from "../../chunk-CNf5ZN-e.mjs";
2
- import { Dn as userManagementCapability, I as ScopedTokenSchema, K as authProviderCapability, V as UserRecordSchema, Yn as BaseAddon, r as ApiKeyRecordSchema } from "../../dist-Cm556q2j.mjs";
2
+ import { H as UserRecordSchema, L as ScopedTokenSchema, Zn as BaseAddon, kn as userManagementCapability, q as authProviderCapability, r as ApiKeyRecordSchema } from "../../dist-DVyXxn41.mjs";
3
3
  import * as crypto$2 from "node:crypto";
4
4
  import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
5
5
  import nodeCrypto from "crypto";
@@ -1,4 +1,4 @@
1
- import { ProviderRegistration, LocalInterface, ConnectionEndpoint, AdvertisedLocalPort, BaseAddon } from '@camstack/types';
1
+ import { AdvertisedLocalPort, ConnectionEndpoint, LocalInterface, ProviderRegistration, BaseAddon } from '@camstack/types';
2
2
  /**
3
3
  * Cached mesh-reachable endpoint, learned from the `mesh-network`
4
4
  * provider via the `MeshNetworkChanged` event-tail + pull-reconcile.
@@ -68,13 +68,20 @@ export declare class LocalNetworkAddon extends BaseAddon<LocalNetworkConfig> {
68
68
  private meshEndpoint;
69
69
  constructor();
70
70
  /**
71
- * What AUTO currently resolves to for outbound artifact links: the first
72
- * PUBLIC candidate, never loopback and never a LAN address — a link is
73
- * opened on someone's phone, off this network, possibly hours later.
74
- * `null` when nothing public is reachable (the caller then ships bytes only
75
- * rather than a link that 404s).
71
+ * The effective flagged notification address: the operator's explicit
72
+ * choice, else AUTO — the CamStack app link (D709, operator decision
73
+ * 2026-10-06; before it AUTO was the tunnel, then the mesh). The app link is
74
+ * not a hub address: the NC's signed media and buttons keep their own hub
75
+ * ladder when it is flagged; only viewer taps take the app form.
76
76
  */
77
77
  private resolveNotificationEndpoint;
78
+ /**
79
+ * The `hub=` an app link carries: the best public HTTPS address in this
80
+ * cap's own palette (tunnel, then mesh) — so it can never disagree with
81
+ * what the Network page lists. See `pickAppLinkHub`.
82
+ */
83
+ private resolveAppLinkHub;
84
+ private notificationEndpointSnapshot;
78
85
  private snapshotViewerEndpoints;
79
86
  /**
80
87
  * Palette shown in the Network tab: LAN IPv4, stable LAN IPv6, public,
@@ -205,6 +212,14 @@ export interface LanHttpAdvertisement {
205
212
  readonly httpsPort: number;
206
213
  readonly localHostname: string | null;
207
214
  }
215
+ /**
216
+ * The CamStack app link as a palette entry (D709): the one address on the
217
+ * Network page that is not this hub's. Flagging it for notifications (the
218
+ * default) makes viewer taps open the native app, with the hub carried as
219
+ * `hub=`. `kind: 'app-link'` keeps it out of every race and ranking; it is
220
+ * only emitted on `includeAppLink: true`.
221
+ */
222
+ export declare function appLinkEndpoint(): ConnectionEndpoint;
208
223
  export declare function buildEndpoints(interfaces: readonly LocalInterface[], port: number, includeLoopback: boolean, ipv4Only: boolean, publicHostname: string, scheme?: 'http' | 'https', meshEndpoint?: MeshEndpointCache | null, lanHttp?: LanHttpAdvertisement | null): ConnectionEndpoint[];
209
224
  /** AUTO viewer race: LAN IPv4 + the public tunnel. Never IPv6, mesh, or loopback. */
210
225
  export declare function isDefaultViewerEndpoint(endpoint: ConnectionEndpoint): boolean;
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("../../chunk-Cek0wNdY.js");
3
- const require_dist = require("../../dist-CXVXFdJX.js");
3
+ const require_dist = require("../../dist-DePB7uwU.js");
4
4
  const require_tls = require("../../tls-ue_Xefmv.js");
5
5
  let node_fs_promises = require("node:fs/promises");
6
6
  let node_path = require("node:path");
@@ -8,40 +8,6 @@ let node_os = require("node:os");
8
8
  node_os = require_chunk.__toESM(node_os);
9
9
  let node_fs = require("node:fs");
10
10
  let node_net = require("node:net");
11
- //#region src/builtins/local-network/local-hostname.ts
12
- var DNS_NAME = /^(?=.{1,253}$)([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])$/;
13
- /**
14
- * Parse the operator-typed local hostname.
15
- *
16
- * Empty / whitespace → `null` (advertise the raw LAN IP). A DNS name is
17
- * lowercased. A URL, port suffix, path, or bare IP is rejected so it cannot
18
- * leak into a SAN or a candidate URL.
19
- */
20
- function parseLocalHostname(raw) {
21
- const trimmed = raw.trim();
22
- if (trimmed === "") return {
23
- ok: true,
24
- value: null
25
- };
26
- if (/[\s/:?#]/.test(trimmed) || trimmed.includes("\\")) return {
27
- ok: false,
28
- error: "Enter a DNS name such as camstack.lan, without a scheme or port."
29
- };
30
- const lowered = trimmed.toLowerCase();
31
- if ((0, node_net.isIP)(lowered) !== 0) return {
32
- ok: false,
33
- error: "Use the address allowlist for IPs — this field is a DNS name."
34
- };
35
- if (!DNS_NAME.test(lowered)) return {
36
- ok: false,
37
- error: "Enter a DNS name such as camstack.lan, without a scheme or port."
38
- };
39
- return {
40
- ok: true,
41
- value: lowered
42
- };
43
- }
44
- //#endregion
45
11
  //#region src/builtins/local-network/ipv6-lan.ts
46
12
  /**
47
13
  * IPv6 helpers for LAN advertisement: prefix matching (privacy addresses
@@ -147,6 +113,40 @@ function parseIpv6Groups(address) {
147
113
  ];
148
114
  }
149
115
  //#endregion
116
+ //#region src/builtins/local-network/local-hostname.ts
117
+ var DNS_NAME = /^(?=.{1,253}$)([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])$/;
118
+ /**
119
+ * Parse the operator-typed local hostname.
120
+ *
121
+ * Empty / whitespace → `null` (advertise the raw LAN IP). A DNS name is
122
+ * lowercased. A URL, port suffix, path, or bare IP is rejected so it cannot
123
+ * leak into a SAN or a candidate URL.
124
+ */
125
+ function parseLocalHostname(raw) {
126
+ const trimmed = raw.trim();
127
+ if (trimmed === "") return {
128
+ ok: true,
129
+ value: null
130
+ };
131
+ if (/[\s/:?#]/.test(trimmed) || trimmed.includes("\\")) return {
132
+ ok: false,
133
+ error: "Enter a DNS name such as camstack.lan, without a scheme or port."
134
+ };
135
+ const lowered = trimmed.toLowerCase();
136
+ if ((0, node_net.isIP)(lowered) !== 0) return {
137
+ ok: false,
138
+ error: "Use the address allowlist for IPs — this field is a DNS name."
139
+ };
140
+ if (!DNS_NAME.test(lowered)) return {
141
+ ok: false,
142
+ error: "Enter a DNS name such as camstack.lan, without a scheme or port."
143
+ };
144
+ return {
145
+ ok: true,
146
+ value: lowered
147
+ };
148
+ }
149
+ //#endregion
150
150
  //#region src/builtins/local-network/local-network.addon.ts
151
151
  /**
152
152
  * local-network — hub-only system cap implementation.
@@ -207,19 +207,32 @@ var LocalNetworkAddon = class extends require_dist.BaseAddon {
207
207
  });
208
208
  }
209
209
  /**
210
- * What AUTO currently resolves to for outbound artifact links: the first
211
- * PUBLIC candidate, never loopback and never a LAN address — a link is
212
- * opened on someone's phone, off this network, possibly hours later.
213
- * `null` when nothing public is reachable (the caller then ships bytes only
214
- * rather than a link that 404s).
210
+ * The effective flagged notification address: the operator's explicit
211
+ * choice, else AUTO — the CamStack app link (D709, operator decision
212
+ * 2026-10-06; before it AUTO was the tunnel, then the mesh). The app link is
213
+ * not a hub address: the NC's signed media and buttons keep their own hub
214
+ * ladder when it is flagged; only viewer taps take the app form.
215
215
  */
216
216
  resolveNotificationEndpoint() {
217
217
  const explicit = this.config.notificationBaseUrl;
218
- if (explicit !== "") return explicit;
219
- if (this.publicHostname !== "") return `https://${this.publicHostname}`;
220
- const mesh = this.meshEndpoint;
221
- if (mesh !== null && mesh.host !== "") return `https://${mesh.host}:${mesh.port}`;
222
- return null;
218
+ return explicit !== "" ? explicit : require_dist.CAMSTACK_APP_LINK_ORIGIN;
219
+ }
220
+ /**
221
+ * The `hub=` an app link carries: the best public HTTPS address in this
222
+ * cap's own palette (tunnel, then mesh) — so it can never disagree with
223
+ * what the Network page lists. See `pickAppLinkHub`.
224
+ */
225
+ async resolveAppLinkHub() {
226
+ const port = (await this.resolveAdvertisedListenPort(null)).port;
227
+ return require_dist.pickAppLinkHub(await this.buildAdvertisedEndpoints(false, false, "https", port));
228
+ }
229
+ async notificationEndpointSnapshot() {
230
+ const explicit = this.config.notificationBaseUrl;
231
+ return {
232
+ baseUrl: explicit === "" ? null : explicit,
233
+ resolved: this.resolveNotificationEndpoint(),
234
+ appLinkHub: await this.resolveAppLinkHub()
235
+ };
223
236
  }
224
237
  async snapshotViewerEndpoints() {
225
238
  const selected = selectViewerEndpoints(await this.buildAdvertisedEndpoints(false, false, "http", (await this.resolveAdvertisedListenPort(null)).port), this.config.viewerBaseUrls);
@@ -271,22 +284,17 @@ var LocalNetworkAddon = class extends require_dist.BaseAddon {
271
284
  advertised: localPort.port,
272
285
  source: localPort.source
273
286
  } });
287
+ const endpoints = await this.buildAdvertisedEndpoints(includeLoopback, input.ipv4Only ?? false, scheme, localPort.port);
274
288
  return {
275
- endpoints: await this.buildAdvertisedEndpoints(includeLoopback, input.ipv4Only ?? false, scheme, localPort.port),
289
+ endpoints: input.includeAppLink === true ? [appLinkEndpoint(), ...endpoints] : endpoints,
276
290
  localPort
277
291
  };
278
292
  },
279
- getNotificationEndpoint: async () => ({
280
- baseUrl: this.config.notificationBaseUrl === "" ? null : this.config.notificationBaseUrl,
281
- resolved: this.resolveNotificationEndpoint()
282
- }),
293
+ getNotificationEndpoint: async () => this.notificationEndpointSnapshot(),
283
294
  setNotificationEndpoint: async ({ baseUrl }) => {
284
295
  await this.updateGlobalSettings({ notificationBaseUrl: baseUrl ?? "" });
285
296
  this.ctx.logger.info("local-network: notification endpoint set", { meta: { baseUrl: baseUrl ?? "(auto)" } });
286
- return {
287
- baseUrl: baseUrl === "" ? null : baseUrl,
288
- resolved: this.resolveNotificationEndpoint()
289
- };
297
+ return this.notificationEndpointSnapshot();
290
298
  },
291
299
  getViewerEndpoints: async () => this.snapshotViewerEndpoints(),
292
300
  setViewerEndpoints: async ({ baseUrls }) => {
@@ -729,6 +737,24 @@ function pickPreferred(interfaces) {
729
737
  return prefixLen(b.netmask) - prefixLen(a.netmask);
730
738
  })[0] ?? null;
731
739
  }
740
+ /**
741
+ * The CamStack app link as a palette entry (D709): the one address on the
742
+ * Network page that is not this hub's. Flagging it for notifications (the
743
+ * default) makes viewer taps open the native app, with the hub carried as
744
+ * `hub=`. `kind: 'app-link'` keeps it out of every race and ranking; it is
745
+ * only emitted on `includeAppLink: true`.
746
+ */
747
+ function appLinkEndpoint() {
748
+ return {
749
+ label: "CamStack app link",
750
+ baseUrl: require_dist.CAMSTACK_APP_LINK_ORIGIN,
751
+ kind: "app-link",
752
+ interfaceKind: "public",
753
+ plausible: true,
754
+ plausibleReason: "",
755
+ priority: -1
756
+ };
757
+ }
732
758
  function buildEndpoints(interfaces, port, includeLoopback, ipv4Only, publicHostname, scheme = "http", meshEndpoint = null, lanHttp = null) {
733
759
  const out = [];
734
760
  let priority = 0;
@@ -949,6 +975,7 @@ function readLinuxIpv6Flags() {
949
975
  //#endregion
950
976
  exports.ALLOWLIST_RECONCILE_INTERVAL_MS = ALLOWLIST_RECONCILE_INTERVAL_MS;
951
977
  exports.LocalNetworkAddon = LocalNetworkAddon;
978
+ exports.appLinkEndpoint = appLinkEndpoint;
952
979
  exports.applyAllowlist = applyAllowlist;
953
980
  exports.autoSeedAllowlist = autoSeedAllowlist;
954
981
  exports.buildEndpoints = buildEndpoints;