@camstack/system 1.0.2

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 (262) hide show
  1. package/dist/addon/addon-api-factory.d.ts +35 -0
  2. package/dist/addon-routes/addon-route-registry.d.ts +37 -0
  3. package/dist/addon-runner.js +599 -0
  4. package/dist/addon-runner.mjs +597 -0
  5. package/dist/auth/api-key-manager.d.ts +26 -0
  6. package/dist/auth/auth-manager.d.ts +109 -0
  7. package/dist/auth/parse-record.d.ts +18 -0
  8. package/dist/auth/scope-matcher.d.ts +7 -0
  9. package/dist/auth/scoped-token-manager.d.ts +40 -0
  10. package/dist/auth/totp-manager.d.ts +51 -0
  11. package/dist/auth/user-manager.d.ts +34 -0
  12. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.d.ts +53 -0
  13. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +259 -0
  14. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +251 -0
  15. package/dist/builtins/addon-pages-aggregator/dedupe-pages.d.ts +6 -0
  16. package/dist/builtins/addon-pages-aggregator/index.d.ts +1 -0
  17. package/dist/builtins/addon-pages-aggregator/index.js +8 -0
  18. package/dist/builtins/addon-pages-aggregator/index.mjs +2 -0
  19. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts +47 -0
  20. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +228 -0
  21. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +220 -0
  22. package/dist/builtins/addon-widgets-aggregator/index.d.ts +1 -0
  23. package/dist/builtins/addon-widgets-aggregator/index.js +8 -0
  24. package/dist/builtins/addon-widgets-aggregator/index.mjs +2 -0
  25. package/dist/builtins/alerts/alerts.addon.d.ts +81 -0
  26. package/dist/builtins/alerts/alerts.addon.js +601 -0
  27. package/dist/builtins/alerts/alerts.addon.mjs +595 -0
  28. package/dist/builtins/alerts/index.d.ts +1 -0
  29. package/dist/builtins/alerts/index.js +4 -0
  30. package/dist/builtins/alerts/index.mjs +2 -0
  31. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +147 -0
  32. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2229 -0
  33. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2220 -0
  34. package/dist/builtins/backup-orchestrator/cron-helpers.d.ts +23 -0
  35. package/dist/builtins/backup-orchestrator/destination-policy.d.ts +72 -0
  36. package/dist/builtins/backup-orchestrator/download-helpers.d.ts +12 -0
  37. package/dist/builtins/backup-orchestrator/index.d.ts +2 -0
  38. package/dist/builtins/backup-orchestrator/index.js +8 -0
  39. package/dist/builtins/backup-orchestrator/index.mjs +2 -0
  40. package/dist/builtins/backup-orchestrator/manifest-store.d.ts +77 -0
  41. package/dist/builtins/console-logging/console-destination.d.ts +13 -0
  42. package/dist/builtins/console-logging/console-logging.addon.d.ts +25 -0
  43. package/dist/builtins/console-logging/index.d.ts +3 -0
  44. package/dist/builtins/console-logging/index.js +104 -0
  45. package/dist/builtins/console-logging/index.mjs +95 -0
  46. package/dist/builtins/device-manager/device-config-contribution.d.ts +32 -0
  47. package/dist/builtins/device-manager/device-event-propagator.d.ts +26 -0
  48. package/dist/builtins/device-manager/device-link-overlay.d.ts +23 -0
  49. package/dist/builtins/device-manager/device-link-resolver.d.ts +15 -0
  50. package/dist/builtins/device-manager/device-manager.addon.d.ts +452 -0
  51. package/dist/builtins/device-manager/device-manager.addon.js +3299 -0
  52. package/dist/builtins/device-manager/device-manager.addon.mjs +3292 -0
  53. package/dist/builtins/device-manager/index.d.ts +2 -0
  54. package/dist/builtins/device-manager/index.js +8 -0
  55. package/dist/builtins/device-manager/index.mjs +2 -0
  56. package/dist/builtins/hub-forwarder/hub-forwarder-destination.d.ts +44 -0
  57. package/dist/builtins/hub-forwarder/hub-forwarder.addon.d.ts +15 -0
  58. package/dist/builtins/hub-forwarder/index.d.ts +3 -0
  59. package/dist/builtins/hub-forwarder/index.js +154 -0
  60. package/dist/builtins/hub-forwarder/index.mjs +145 -0
  61. package/dist/builtins/local-auth/auth-schema.d.ts +26 -0
  62. package/dist/builtins/local-auth/index.d.ts +1 -0
  63. package/dist/builtins/local-auth/index.js +4 -0
  64. package/dist/builtins/local-auth/index.mjs +2 -0
  65. package/dist/builtins/local-auth/local-auth.addon.d.ts +18 -0
  66. package/dist/builtins/local-auth/local-auth.addon.js +8094 -0
  67. package/dist/builtins/local-auth/local-auth.addon.mjs +8063 -0
  68. package/dist/builtins/local-auth/oauth-grants.d.ts +45 -0
  69. package/dist/builtins/local-auth/oauth-session-manager.d.ts +50 -0
  70. package/dist/builtins/local-network/index.d.ts +2 -0
  71. package/dist/builtins/local-network/index.js +10 -0
  72. package/dist/builtins/local-network/index.mjs +2 -0
  73. package/dist/builtins/local-network/local-network.addon.d.ts +150 -0
  74. package/dist/builtins/local-network/local-network.addon.js +489 -0
  75. package/dist/builtins/local-network/local-network.addon.mjs +477 -0
  76. package/dist/builtins/native-metrics/index.d.ts +2 -0
  77. package/dist/builtins/native-metrics/native-metrics-provider.d.ts +48 -0
  78. package/dist/builtins/native-metrics/native-metrics.addon.d.ts +73 -0
  79. package/dist/builtins/native-metrics/native-metrics.addon.js +922 -0
  80. package/dist/builtins/native-metrics/native-metrics.addon.mjs +914 -0
  81. package/dist/builtins/platform-probe/hardware-decode-accel-probe.d.ts +37 -0
  82. package/dist/builtins/platform-probe/hardware-encoder-probe.d.ts +13 -0
  83. package/dist/builtins/platform-probe/index.d.ts +22 -0
  84. package/dist/builtins/platform-probe/index.js +834 -0
  85. package/dist/builtins/platform-probe/index.mjs +822 -0
  86. package/dist/builtins/platform-probe/inference-config-resolver.d.ts +29 -0
  87. package/dist/builtins/platform-probe/intel-accelerators.d.ts +11 -0
  88. package/dist/builtins/platform-probe/platform-scorer.d.ts +30 -0
  89. package/dist/builtins/platform-probe/runtime-packages.d.ts +6 -0
  90. package/dist/builtins/remote-access-orchestrator/enabled-providers-reconcile.d.ts +96 -0
  91. package/dist/builtins/remote-access-orchestrator/index.d.ts +1 -0
  92. package/dist/builtins/remote-access-orchestrator/index.js +8 -0
  93. package/dist/builtins/remote-access-orchestrator/index.mjs +2 -0
  94. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts +40 -0
  95. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +214 -0
  96. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +208 -0
  97. package/dist/builtins/shared/settle-sources.d.ts +22 -0
  98. package/dist/builtins/snapshot/index.d.ts +2 -0
  99. package/dist/builtins/snapshot/index.js +494 -0
  100. package/dist/builtins/snapshot/index.mjs +488 -0
  101. package/dist/builtins/snapshot/snapshot.addon.d.ts +120 -0
  102. package/dist/builtins/sqlite-storage/config-store.d.ts +8 -0
  103. package/dist/builtins/sqlite-storage/device-store.d.ts +23 -0
  104. package/dist/builtins/sqlite-storage/filesystem-browse-provider.d.ts +25 -0
  105. package/dist/builtins/sqlite-storage/filesystem-storage-provider.d.ts +83 -0
  106. package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.ts +32 -0
  107. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +396 -0
  108. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +388 -0
  109. package/dist/builtins/sqlite-storage/index.d.ts +8 -0
  110. package/dist/builtins/sqlite-storage/index.js +62 -0
  111. package/dist/builtins/sqlite-storage/index.mjs +49 -0
  112. package/dist/builtins/sqlite-storage/integration-registry.d.ts +27 -0
  113. package/dist/builtins/sqlite-storage/path-guard.d.ts +4 -0
  114. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +102 -0
  115. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +14 -0
  116. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +644 -0
  117. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +636 -0
  118. package/dist/builtins/storage-orchestrator/index.d.ts +6 -0
  119. package/dist/builtins/storage-orchestrator/index.js +10 -0
  120. package/dist/builtins/storage-orchestrator/index.mjs +2 -0
  121. package/dist/builtins/storage-orchestrator/location-store.d.ts +49 -0
  122. package/dist/builtins/storage-orchestrator/provider-discovery.d.ts +10 -0
  123. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +103 -0
  124. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1138 -0
  125. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1128 -0
  126. package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +236 -0
  127. package/dist/builtins/storage-orchestrator/storage-pressure-manager.d.ts +38 -0
  128. package/dist/builtins/system-backup/system-backup.service.d.ts +137 -0
  129. package/dist/builtins/system-config/index.d.ts +1 -0
  130. package/dist/builtins/system-config/index.js +8 -0
  131. package/dist/builtins/system-config/index.mjs +2 -0
  132. package/dist/builtins/system-config/system-config.addon.d.ts +10 -0
  133. package/dist/builtins/system-config/system-config.addon.js +232 -0
  134. package/dist/builtins/system-config/system-config.addon.mjs +226 -0
  135. package/dist/builtins/winston-logging/index.d.ts +3 -0
  136. package/dist/builtins/winston-logging/index.js +156 -0
  137. package/dist/builtins/winston-logging/index.mjs +144 -0
  138. package/dist/builtins/winston-logging/winston-destination.d.ts +21 -0
  139. package/dist/builtins/winston-logging/winston-logging.addon.d.ts +19 -0
  140. package/dist/chunk-CNf5ZN-e.mjs +37 -0
  141. package/dist/chunk-Cek0wNdY.js +64 -0
  142. package/dist/download/model-download-service.d.ts +41 -0
  143. package/dist/download/model-downloader.d.ts +31 -0
  144. package/dist/events/event-bus.d.ts +10 -0
  145. package/dist/events/system-event-bus.d.ts +14 -0
  146. package/dist/feature/feature-manager.d.ts +11 -0
  147. package/dist/formatter-B7qW8bPJ.mjs +162 -0
  148. package/dist/formatter-DqAKDlvN.js +167 -0
  149. package/dist/http/authenticated-file-server.d.ts +53 -0
  150. package/dist/http/data-plane-registry.d.ts +23 -0
  151. package/dist/http/file-data-plane.d.ts +10 -0
  152. package/dist/http/reverse-proxy.d.ts +15 -0
  153. package/dist/index.d.ts +82 -0
  154. package/dist/index.js +93485 -0
  155. package/dist/index.mjs +93179 -0
  156. package/dist/intel-accelerators-Gg0P5mnl.js +20 -0
  157. package/dist/intel-accelerators-hGgpZ0pX.mjs +19 -0
  158. package/dist/kernel/addon-class-resolver.d.ts +4 -0
  159. package/dist/kernel/addon-engine-manager.d.ts +22 -0
  160. package/dist/kernel/addon-health-monitor.d.ts +154 -0
  161. package/dist/kernel/addon-installer.d.ts +208 -0
  162. package/dist/kernel/addon-loader.d.ts +106 -0
  163. package/dist/kernel/addon-manifest.d.ts +77 -0
  164. package/dist/kernel/capability-handle.d.ts +46 -0
  165. package/dist/kernel/capability-registry.d.ts +412 -0
  166. package/dist/kernel/config-manager.d.ts +212 -0
  167. package/dist/kernel/config-schema.d.ts +93 -0
  168. package/dist/kernel/custom-action-registry.d.ts +23 -0
  169. package/dist/kernel/deps/addon-deps-manager.d.ts +19 -0
  170. package/dist/kernel/deps/manifest-native-deps.d.ts +25 -0
  171. package/dist/kernel/deps/manifest-python-deps.d.ts +20 -0
  172. package/dist/kernel/device-registry.d.ts +29 -0
  173. package/dist/kernel/fs-utils.d.ts +41 -0
  174. package/dist/kernel/hwaccel/hwaccel-resolver.d.ts +19 -0
  175. package/dist/kernel/hwaccel/hwaccel-service.d.ts +4 -0
  176. package/dist/kernel/index.d.ts +74 -0
  177. package/dist/kernel/infra-capabilities.d.ts +13 -0
  178. package/dist/kernel/moleculer/addon-context-factory.d.ts +91 -0
  179. package/dist/kernel/moleculer/addon-data-plane-facility.d.ts +19 -0
  180. package/dist/kernel/moleculer/addon-runner.d.ts +1 -0
  181. package/dist/kernel/moleculer/addon-service-factory.d.ts +50 -0
  182. package/dist/kernel/moleculer/broker-factory.d.ts +50 -0
  183. package/dist/kernel/moleculer/cap-usage-registry.d.ts +46 -0
  184. package/dist/kernel/moleculer/capabilities-access.d.ts +21 -0
  185. package/dist/kernel/moleculer/child-addon-call-dispatch.d.ts +46 -0
  186. package/dist/kernel/moleculer/child-cap-dispatch.d.ts +20 -0
  187. package/dist/kernel/moleculer/cluster-secret.d.ts +15 -0
  188. package/dist/kernel/moleculer/core-cap-service.d.ts +50 -0
  189. package/dist/kernel/moleculer/crash-supervisor.d.ts +50 -0
  190. package/dist/kernel/moleculer/device-cap-proxy.d.ts +79 -0
  191. package/dist/kernel/moleculer/event-bus-core.d.ts +53 -0
  192. package/dist/kernel/moleculer/event-bus.d.ts +53 -0
  193. package/dist/kernel/moleculer/hub-log-forwarder.d.ts +36 -0
  194. package/dist/kernel/moleculer/hub-service.d.ts +35 -0
  195. package/dist/kernel/moleculer/node-registry.d.ts +126 -0
  196. package/dist/kernel/moleculer/process-context.d.ts +4 -0
  197. package/dist/kernel/moleculer/process-service.d.ts +72 -0
  198. package/dist/kernel/moleculer/provider-registry.d.ts +28 -0
  199. package/dist/kernel/moleculer/readiness-context.d.ts +62 -0
  200. package/dist/kernel/moleculer/readiness-service.d.ts +7 -0
  201. package/dist/kernel/moleculer/register-node-client.d.ts +35 -0
  202. package/dist/kernel/moleculer/remote-logger.d.ts +43 -0
  203. package/dist/kernel/moleculer/resilient-cap-call.d.ts +28 -0
  204. package/dist/kernel/moleculer/stream-probe-service.d.ts +9 -0
  205. package/dist/kernel/moleculer/trpc-links.d.ts +189 -0
  206. package/dist/kernel/moleculer/typed-array-serde.d.ts +25 -0
  207. package/dist/kernel/moleculer/worker-device-restore.d.ts +10 -0
  208. package/dist/kernel/provider-kind-drift.d.ts +12 -0
  209. package/dist/kernel/restart-coordinator.d.ts +90 -0
  210. package/dist/kernel/storage-location-registry.d.ts +40 -0
  211. package/dist/kernel/transport/cap-action-name.d.ts +100 -0
  212. package/dist/kernel/transport/cap-route-resolver.d.ts +148 -0
  213. package/dist/kernel/transport/cap-route.d.ts +148 -0
  214. package/dist/kernel/transport/child-cap-protocol.d.ts +136 -0
  215. package/dist/kernel/transport/create-local-transport.d.ts +7 -0
  216. package/dist/kernel/transport/frame-codec.d.ts +7 -0
  217. package/dist/kernel/transport/index.d.ts +27 -0
  218. package/dist/kernel/transport/local-child-client.d.ts +136 -0
  219. package/dist/kernel/transport/local-child-registry.d.ts +179 -0
  220. package/dist/kernel/transport/local-endpoint-path.d.ts +6 -0
  221. package/dist/kernel/transport/local-transport.d.ts +46 -0
  222. package/dist/kernel/transport/parent-unowned-call.d.ts +75 -0
  223. package/dist/kernel/transport/socket-channel.d.ts +27 -0
  224. package/dist/kernel/transport/uds-event-bridge.d.ts +36 -0
  225. package/dist/kernel/transport/uds-event-bus.d.ts +22 -0
  226. package/dist/kernel/transport/uds-local-transport.d.ts +18 -0
  227. package/dist/kernel/transport/uds-log-ingest.d.ts +28 -0
  228. package/dist/kernel/transport/uds-logger.d.ts +44 -0
  229. package/dist/kernel/utils/ring-buffer.d.ts +15 -0
  230. package/dist/kernel/workspace-detect.d.ts +9 -0
  231. package/dist/lifecycle/lifecycle-state-machine.d.ts +28 -0
  232. package/dist/logging/formatter.d.ts +30 -0
  233. package/dist/logging/log-manager.d.ts +54 -0
  234. package/dist/logging/log-ring-buffer.d.ts +47 -0
  235. package/dist/logging/partitioned-log-buffer.d.ts +35 -0
  236. package/dist/logging/scoped-logger.d.ts +17 -0
  237. package/dist/main-DNnMW7Z2.js +9983 -0
  238. package/dist/main-rtjOwPBR.mjs +9976 -0
  239. package/dist/manifest-python-deps-D1DbAQEv.js +6724 -0
  240. package/dist/manifest-python-deps-DZsKTbs1.mjs +6315 -0
  241. package/dist/network/network-quality.d.ts +11 -0
  242. package/dist/notification/notification-service.d.ts +37 -0
  243. package/dist/notification/toast-service.d.ts +22 -0
  244. package/dist/pipeline/engine-manager-resolver.d.ts +15 -0
  245. package/dist/pipeline/pipeline-runner.d.ts +8 -0
  246. package/dist/pipeline/pipeline-validator.d.ts +13 -0
  247. package/dist/process/resource-monitor.d.ts +11 -0
  248. package/dist/python/python-env-manager.d.ts +12 -0
  249. package/dist/repl/interfaces.d.ts +31 -0
  250. package/dist/repl/repl-engine.d.ts +8 -0
  251. package/dist/resource-monitor-ClDGFyf6.mjs +57 -0
  252. package/dist/resource-monitor-IIEanuJt.js +74 -0
  253. package/dist/settle-sources-Bhsy57y-.js +38 -0
  254. package/dist/settle-sources-CDtNC8ub.mjs +33 -0
  255. package/dist/storage/fs-storage-backend.d.ts +40 -0
  256. package/dist/storage/storage-location-manager.d.ts +23 -0
  257. package/dist/storage/storage-manager.d.ts +83 -0
  258. package/dist/tar-BgAEMRBR.js +5434 -0
  259. package/dist/tar-ByMOPNM0.mjs +5429 -0
  260. package/dist/tls/cert-manager.d.ts +26 -0
  261. package/dist/tls/index.d.ts +1 -0
  262. package/package.json +343 -0
@@ -0,0 +1,489 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_chunk = require("../../chunk-Cek0wNdY.js");
3
+ let _camstack_types = require("@camstack/types");
4
+ let node_os = require("node:os");
5
+ node_os = require_chunk.__toESM(node_os);
6
+ //#region src/builtins/local-network/local-network.addon.ts
7
+ /**
8
+ * local-network — hub-only system cap implementation.
9
+ *
10
+ * Wraps `os.networkInterfaces()` with:
11
+ * - Coarse kind classification (lan/wifi/docker/vpn/loopback/other)
12
+ * - Auto-select heuristic for the outbound interface
13
+ * - Periodic poll (30s) + diff to emit `LocalNetworkChanged` events
14
+ * so subscribers can react to DHCP renewals, VPN connect, etc.
15
+ * - `getConnectionEndpoints()` — ranked URL list for SDK clients
16
+ *
17
+ * Does NOT poll the cloudflare-tunnel state directly; the public
18
+ * tunnel hostname (if any) is provided by `network-access` consumers
19
+ * via `NetworkTunnelStarted/Stopped` events on the bus, so the cap
20
+ * stays free of cross-addon dependencies.
21
+ */
22
+ /**
23
+ * Forked `mesh-network` provider addon ids `local-network` pull-reconciles
24
+ * against. `mesh-network` is a COLLECTION cap, so a hub builtin's local
25
+ * registry can't enumerate forked providers — we resolve each by addonId
26
+ * via `getProviderByAddon`. New mesh providers (Headscale, ZeroTier) add
27
+ * their id here.
28
+ */
29
+ var MESH_PROVIDER_ADDON_IDS = ["tailscale-client"];
30
+ var POLL_INTERVAL_MS = 3e4;
31
+ var LocalNetworkAddon = class extends _camstack_types.BaseAddon {
32
+ pollTimer = null;
33
+ lastSnapshotKey = "";
34
+ /** Optional public hostname tracked from `NetworkTunnelStarted`/
35
+ * `Stopped` events on the bus. */
36
+ publicHostname = "";
37
+ /**
38
+ * Mesh-reachable endpoint (Tailscale MagicDNS / 100.x), learned from
39
+ * the `MeshNetworkChanged` event-tail and refreshed by a pull-reconcile
40
+ * before each `getConnectionEndpoints` build (events are lossy — D8).
41
+ * `null` when no mesh provider is joined.
42
+ */
43
+ meshEndpoint = null;
44
+ constructor() {
45
+ super({
46
+ allowedAddresses: [],
47
+ bootSeeded: false
48
+ });
49
+ }
50
+ async onInitialize() {
51
+ if (!this.config.bootSeeded) {
52
+ const seed = autoSeedAllowlist(this.enumerate());
53
+ await this.updateGlobalSettings({
54
+ allowedAddresses: seed,
55
+ bootSeeded: true
56
+ });
57
+ this.ctx.logger.info("local-network: first-boot auto-seed", { meta: { addresses: seed } });
58
+ }
59
+ const provider = {
60
+ list: async () => ({
61
+ interfaces: this.enumerate(),
62
+ probedAt: Date.now()
63
+ }),
64
+ getPreferred: async () => pickPreferred(applyAllowlist(this.enumerate(), this.config.allowedAddresses)),
65
+ getConnectionEndpoints: async (input) => {
66
+ const includeLoopback = input.includeLoopback ?? true;
67
+ const ipv4Only = input.ipv4Only ?? false;
68
+ const scheme = input.scheme ?? "http";
69
+ const allow = this.config.allowedAddresses;
70
+ const interfaces = applyAllowlist(this.enumerate(), allow);
71
+ await this.reconcileMeshEndpoint();
72
+ return { endpoints: buildEndpoints(interfaces, input.port, includeLoopback, ipv4Only, this.publicHostname, scheme, this.meshEndpoint) };
73
+ },
74
+ getAllowedAddresses: async () => ({ addresses: this.config.allowedAddresses }),
75
+ resetAllowlistToBestMatch: async () => {
76
+ const seed = autoSeedAllowlist(this.enumerate());
77
+ await this.updateGlobalSettings({
78
+ allowedAddresses: seed,
79
+ bootSeeded: true
80
+ });
81
+ this.ctx.logger.info("local-network: allowlist reset to auto-seed", { meta: { count: seed.length } });
82
+ return { addresses: seed };
83
+ },
84
+ setAllowedAddresses: async ({ addresses }) => {
85
+ const known = new Set(this.enumerate().map((i) => i.address));
86
+ const cleaned = [...new Set(addresses)].filter((a) => known.has(a));
87
+ await this.updateGlobalSettings({ allowedAddresses: cleaned });
88
+ this.ctx.logger.info("local-network: allowlist updated", { meta: {
89
+ count: cleaned.length,
90
+ dropped: addresses.length - cleaned.length
91
+ } });
92
+ return { success: true };
93
+ }
94
+ };
95
+ this.lastSnapshotKey = snapshotKey(this.enumerate());
96
+ this.pollTimer = setInterval(() => this.detectChanges(), POLL_INTERVAL_MS);
97
+ this.pollTimer.unref?.();
98
+ this.ctx.eventBus?.subscribe({ category: _camstack_types.EventCategory.NetworkTunnelStarted }, (event) => {
99
+ const data = event.data ?? {};
100
+ if (typeof data.url === "string") try {
101
+ const hostname = new URL(data.url).hostname;
102
+ if (hostname && !hostname.endsWith(".placeholder") && !hostname.startsWith("pending.")) this.setPublicHostname(hostname);
103
+ } catch {}
104
+ });
105
+ this.ctx.eventBus?.subscribe({ category: _camstack_types.EventCategory.NetworkTunnelStopped }, () => this.setPublicHostname(""));
106
+ this.ctx.eventBus?.subscribe({ category: _camstack_types.EventCategory.MeshNetworkChanged }, (event) => {
107
+ const data = event.data ?? {};
108
+ const host = typeof data.host === "string" ? data.host : "";
109
+ const port = typeof data.port === "number" ? data.port : 0;
110
+ this.setMeshEndpoint(host && port > 0 ? {
111
+ host,
112
+ port
113
+ } : null);
114
+ });
115
+ this.ctx.logger.info("local-network initialized", { meta: { interfaceCount: this.enumerate().length } });
116
+ return [{
117
+ capability: _camstack_types.localNetworkCapability,
118
+ provider
119
+ }];
120
+ }
121
+ async onShutdown() {
122
+ if (this.pollTimer) {
123
+ clearInterval(this.pollTimer);
124
+ this.pollTimer = null;
125
+ }
126
+ }
127
+ /**
128
+ * Other hub addons (e.g. cloudflare-tunnel) signal the active public
129
+ * FQDN by emitting `NetworkTunnelStarted` on the bus — handled in
130
+ * `onInitialize`. This setter exists for tests + future direct
131
+ * callers; cleared by passing an empty string.
132
+ */
133
+ setPublicHostname(hostname) {
134
+ if (this.publicHostname === hostname) return;
135
+ this.publicHostname = hostname;
136
+ this.ctx.logger.info("local-network: public hostname updated", { meta: { hostname: hostname || "(cleared)" } });
137
+ }
138
+ /**
139
+ * Replace the cached mesh endpoint. Set from the `MeshNetworkChanged`
140
+ * event-tail + the pull-reconcile; exposed for tests + future direct
141
+ * callers. Pass `null` to clear (mesh left / no provider joined).
142
+ */
143
+ setMeshEndpoint(endpoint) {
144
+ const prev = this.meshEndpoint;
145
+ if (prev?.host === endpoint?.host && prev?.port === endpoint?.port) return;
146
+ this.meshEndpoint = endpoint;
147
+ this.ctx.logger.info("local-network: mesh endpoint updated", { meta: {
148
+ host: endpoint?.host || "(cleared)",
149
+ port: endpoint?.port ?? 0
150
+ } });
151
+ }
152
+ /**
153
+ * Refresh the cached mesh endpoint from the authoritative forked
154
+ * `mesh-network` provider(s). `mesh-network` is a COLLECTION cap on a
155
+ * forked addon, so the hub builtin can't see it via `ctx.api` /
156
+ * `getCollectionEntries` — we resolve each provider by addonId through
157
+ * the hub-side `capabilityRegistry.getProviderByAddon` resolver (the
158
+ * same mechanism `device-manager` uses for cross-process exporter
159
+ * contributions). Best-effort: a provider that's absent / errors /
160
+ * not joined simply contributes nothing.
161
+ */
162
+ async reconcileMeshEndpoint() {
163
+ const registry = this.ctx.kernel.capabilityRegistry;
164
+ if (!registry) return;
165
+ for (const addonId of MESH_PROVIDER_ADDON_IDS) {
166
+ const provider = registry.getProviderByAddon("mesh-network", addonId);
167
+ if (!provider) continue;
168
+ try {
169
+ const status = await provider.getStatus();
170
+ if (!status.joined) {
171
+ this.setMeshEndpoint(null);
172
+ continue;
173
+ }
174
+ const host = status.magicDnsHostname || status.meshIp;
175
+ const port = (status.endpoints.find((e) => e.id === "magicdns") ?? status.endpoints.find((e) => e.id === "mesh-ipv4"))?.port ?? 0;
176
+ this.setMeshEndpoint(host && port > 0 ? {
177
+ host,
178
+ port
179
+ } : null);
180
+ return;
181
+ } catch (err) {
182
+ this.ctx.logger.debug("local-network: mesh reconcile skipped", { meta: {
183
+ addonId,
184
+ error: err instanceof Error ? err.message : String(err)
185
+ } });
186
+ }
187
+ }
188
+ }
189
+ enumerate() {
190
+ return enumerateOsInterfaces(node_os.networkInterfaces());
191
+ }
192
+ detectChanges() {
193
+ const interfaces = this.enumerate();
194
+ const key = snapshotKey(interfaces);
195
+ if (key === this.lastSnapshotKey) return;
196
+ this.ctx.logger.info("local-network: interface set changed", { meta: {
197
+ count: interfaces.length,
198
+ key
199
+ } });
200
+ this.lastSnapshotKey = key;
201
+ this.ctx.eventBus?.emit({
202
+ id: `local-network-changed-${Date.now()}`,
203
+ timestamp: /* @__PURE__ */ new Date(),
204
+ source: {
205
+ type: "core",
206
+ id: "local-network"
207
+ },
208
+ category: _camstack_types.EventCategory.LocalNetworkChanged,
209
+ data: { count: interfaces.length }
210
+ });
211
+ }
212
+ };
213
+ function enumerateOsInterfaces(ifaces) {
214
+ const raw = [];
215
+ for (const [name, addrs] of Object.entries(ifaces)) {
216
+ if (!addrs) continue;
217
+ for (const a of addrs) {
218
+ if (a.family !== "IPv4" && a.family !== "IPv6") continue;
219
+ raw.push({
220
+ name,
221
+ family: a.family,
222
+ address: a.address,
223
+ cidr: a.cidr ?? "",
224
+ netmask: a.netmask,
225
+ internal: a.internal,
226
+ mac: a.mac
227
+ });
228
+ }
229
+ }
230
+ const classified = raw.map((r) => {
231
+ const kind = classifyKind(r.name, r.address, r.internal);
232
+ const reachableKind = kind === "lan" || kind === "wifi";
233
+ const plausible = !r.internal && reachableKind && isPlausibleAutoSeed(r.address, r.family);
234
+ const plausibleReason = plausible ? "" : explainNonPlausible({
235
+ kind,
236
+ family: r.family,
237
+ address: r.address,
238
+ internal: r.internal
239
+ });
240
+ return {
241
+ name: r.name,
242
+ family: r.family,
243
+ address: r.address,
244
+ cidr: r.cidr,
245
+ netmask: r.netmask,
246
+ internal: r.internal,
247
+ mac: r.mac,
248
+ kind,
249
+ preferred: false,
250
+ plausible,
251
+ plausibleReason
252
+ };
253
+ });
254
+ const preferred = pickPreferred(classified);
255
+ return classified.map((iface) => ({
256
+ ...iface,
257
+ preferred: preferred !== null && iface.name === preferred.name && iface.address === preferred.address
258
+ }));
259
+ }
260
+ /**
261
+ * Filter the interface list by the operator's allowlist. Empty
262
+ * allowlist = no-op (every interface passes); otherwise only entries
263
+ * whose `address` matches an allowlist entry remain. Loopback always
264
+ * survives so the SDK keeps `127.0.0.1` as the last-resort fallback.
265
+ */
266
+ function applyAllowlist(interfaces, allowed) {
267
+ if (allowed.length === 0) return interfaces;
268
+ const set = new Set(allowed);
269
+ return interfaces.filter((i) => i.kind === "loopback" || set.has(i.address));
270
+ }
271
+ /**
272
+ * Rank interfaces and pick the auto-selected outbound one. See the
273
+ * cap's `getPreferred` doc for the heuristic.
274
+ */
275
+ function pickPreferred(interfaces) {
276
+ const candidates = interfaces.filter((i) => !i.internal && i.family === "IPv4" && !i.address.startsWith("169.254.") && i.kind !== "loopback");
277
+ if (candidates.length === 0) return null;
278
+ const kindRank = {
279
+ lan: 1,
280
+ wifi: 2,
281
+ vpn: 3,
282
+ docker: 4,
283
+ other: 5,
284
+ loopback: 99
285
+ };
286
+ return [...candidates].toSorted((a, b) => {
287
+ const ra = kindRank[a.kind];
288
+ const rb = kindRank[b.kind];
289
+ if (ra !== rb) return ra - rb;
290
+ return prefixLen(b.netmask) - prefixLen(a.netmask);
291
+ })[0] ?? null;
292
+ }
293
+ /**
294
+ * Build the ordered candidate URL list. Priority schema:
295
+ * 0 — preferred LAN IPv4
296
+ * 10+ — other LAN IPv4
297
+ * 100 — public tunnel hostname (always HTTPS)
298
+ * 150 — mesh endpoint (Tailscale MagicDNS / 100.x, always HTTPS)
299
+ * 200+ — LAN IPv6
300
+ * 1000 — loopback (last resort)
301
+ *
302
+ * The mesh endpoint ranks just below a true public funnel (a Funnel is
303
+ * reachable by ANY client; the mesh needs the peer on the same tailnet)
304
+ * but above the IPv6 / loopback fallbacks — giving remote, mesh-joined
305
+ * clients a working candidate when no public tunnel is up.
306
+ *
307
+ * `scheme` controls LAN + loopback URLs. Browsers running over HTTPS
308
+ * block `http://` candidates as mixed content, so callers loaded over
309
+ * HTTPS should pass `scheme: 'https'` even when probing a LAN IP — the
310
+ * hub's cert manager already issues a SAN-multi cert covering local
311
+ * interfaces. The public tunnel + mesh endpoint always emit `https://`
312
+ * (the tunnel edge / the hub itself terminates TLS).
313
+ */
314
+ function buildEndpoints(interfaces, port, includeLoopback, ipv4Only, publicHostname, scheme = "http", meshEndpoint = null) {
315
+ const out = [];
316
+ let priority = 0;
317
+ const preferred = pickPreferred(interfaces);
318
+ const emit = (iface, kind, label, baseUrl, pri) => {
319
+ out.push({
320
+ label,
321
+ baseUrl,
322
+ kind,
323
+ interfaceKind: iface.kind,
324
+ plausible: iface.plausible,
325
+ plausibleReason: iface.plausibleReason,
326
+ priority: pri
327
+ });
328
+ };
329
+ if (preferred) emit(preferred, "lan-ipv4", `${formatKind(preferred.kind)} — ${preferred.name}`, `${scheme}://${preferred.address}:${port}`, priority++);
330
+ for (const iface of interfaces) {
331
+ if (iface.internal || iface.family !== "IPv4") continue;
332
+ if (iface.kind === "loopback") continue;
333
+ if (preferred && iface.name === preferred.name && iface.address === preferred.address) continue;
334
+ if (iface.address.startsWith("169.254.")) continue;
335
+ emit(iface, "lan-ipv4", `${formatKind(iface.kind)} — ${iface.name}`, `${scheme}://${iface.address}:${port}`, 10 + priority++);
336
+ }
337
+ if (publicHostname) out.push({
338
+ label: "Public tunnel",
339
+ baseUrl: `https://${publicHostname}`,
340
+ kind: "public",
341
+ interfaceKind: "public",
342
+ plausible: true,
343
+ plausibleReason: "",
344
+ priority: 100
345
+ });
346
+ if (meshEndpoint && meshEndpoint.host) out.push({
347
+ label: "Mesh (Tailscale)",
348
+ baseUrl: `https://${meshEndpoint.host}:${meshEndpoint.port}`,
349
+ kind: "public",
350
+ interfaceKind: "vpn",
351
+ plausible: true,
352
+ plausibleReason: "",
353
+ priority: 150
354
+ });
355
+ if (!ipv4Only) {
356
+ let v6prio = 200;
357
+ for (const iface of interfaces) {
358
+ if (iface.internal || iface.family !== "IPv6") continue;
359
+ if (iface.kind === "loopback") continue;
360
+ if (iface.address.startsWith("fe80:")) continue;
361
+ emit(iface, "lan-ipv6", `${formatKind(iface.kind)} — ${iface.name} (IPv6)`, `${scheme}://[${iface.address}]:${port}`, v6prio++);
362
+ }
363
+ }
364
+ if (includeLoopback) out.push({
365
+ label: "Loopback",
366
+ baseUrl: `${scheme}://127.0.0.1:${port}`,
367
+ kind: "loopback",
368
+ interfaceKind: "loopback",
369
+ plausible: false,
370
+ plausibleReason: "Loopback — last-resort fallback when no other endpoint responds.",
371
+ priority: 1e3
372
+ });
373
+ return out.toSorted((a, b) => a.priority - b.priority);
374
+ }
375
+ /**
376
+ * First-boot heuristic: which addresses should the allowlist start
377
+ * with? Includes LAN + Wi-Fi IPv4 addresses + plausible IPv6:
378
+ *
379
+ * - **IPv4**: skip link-local (`169.254.*`), keep the rest.
380
+ * - **IPv6**: skip link-local (`fe80::*`), unspecified, and
381
+ * multicast. Keep ULAs (`fc00::/7` → `fc??:` / `fd??:`) and Global
382
+ * Unicast addresses (`2000::/3` → `2???`/`3???`). Privacy-extension
383
+ * temporary addresses get included by default; the operator can
384
+ * prune them from the Network Addresses tab if the rotating IPs
385
+ * become a nuisance.
386
+ *
387
+ * Skips docker/vpn/loopback/other entirely — those stay opt-in.
388
+ */
389
+ function autoSeedAllowlist(interfaces) {
390
+ return [...new Set(interfaces.filter((i) => !i.internal && (i.kind === "lan" || i.kind === "wifi") && isPlausibleAutoSeed(i.address, i.family)).map((i) => i.address))];
391
+ }
392
+ /**
393
+ * Per-interface tooltip text surfaced on the "Unlikely usable" badge.
394
+ * Server-side so the UI doesn't re-derive the rationale (single source
395
+ * of truth). Returns `''` for plausible entries; the addon overlays
396
+ * this on the `LocalInterface.plausibleReason` field.
397
+ */
398
+ function explainNonPlausible(input) {
399
+ if (input.internal) return "Internal interface (loopback) — not reachable from clients.";
400
+ if (input.kind === "docker") return "Docker bridge — only reachable from inside the container network.";
401
+ if (input.kind === "vpn") return "VPN tunnel — only reachable while the VPN is connected.";
402
+ if (input.kind === "other") return "Unrecognised interface kind — verify reachability before pinning.";
403
+ if (input.family === "IPv6") {
404
+ const a = input.address.toLowerCase();
405
+ if (a.startsWith("fe80:")) return "IPv6 link-local — only reachable on the same link, not routed.";
406
+ if (a.startsWith("ff")) return "IPv6 multicast — not a unicast address.";
407
+ if (a === "::" || a === "::1") return "IPv6 loopback / unspecified — not a public address.";
408
+ return "IPv6 address outside the ULA / GUA ranges — verify before pinning.";
409
+ }
410
+ if (input.address.startsWith("169.254.")) return "IPv4 link-local (RFC 3927) — only valid when DHCP fails.";
411
+ return "Address looks unusual for client traffic — verify before pinning.";
412
+ }
413
+ /**
414
+ * Per-address gate used by `autoSeedAllowlist`. Exposed for tests so
415
+ * we can pin every classification rule without standing up the addon.
416
+ */
417
+ function isPlausibleAutoSeed(address, family) {
418
+ if (family === "IPv4") {
419
+ if (address.startsWith("169.254.")) return false;
420
+ return true;
421
+ }
422
+ const a = address.toLowerCase();
423
+ if (a === "::" || a === "::1") return false;
424
+ if (a.startsWith("fe80:")) return false;
425
+ if (a.startsWith("ff")) return false;
426
+ if (/^f[cd][0-9a-f]{0,2}:/.test(a)) return true;
427
+ if (/^[23][0-9a-f]{0,3}:/.test(a)) return true;
428
+ return false;
429
+ }
430
+ function classifyKind(name, address, internal) {
431
+ if (internal || name === "lo" || name.startsWith("lo")) return "loopback";
432
+ const n = name.toLowerCase();
433
+ if (n.startsWith("docker") || n.startsWith("br-") || n.startsWith("veth")) return "docker";
434
+ if (n.startsWith("tun") || n.startsWith("utun") || n.startsWith("wg") || n.startsWith("tap")) return "vpn";
435
+ if (n.startsWith("wlan") || n.startsWith("wlp") || n.startsWith("wlx")) return "wifi";
436
+ if (n.startsWith("eth") || /^en\d+$/.test(n)) {
437
+ if (process.platform === "darwin" && /^en[1-9]\d*$/.test(n)) return "wifi";
438
+ return "lan";
439
+ }
440
+ if (address === "127.0.0.1" || address === "::1") return "loopback";
441
+ return "other";
442
+ }
443
+ /** Convert an IPv4/IPv6 netmask string to its prefix length (CIDR). */
444
+ function prefixLen(netmask) {
445
+ if (!netmask) return 0;
446
+ if (netmask.includes(":")) {
447
+ let bits = 0;
448
+ for (const group of netmask.split(":")) {
449
+ if (!group) continue;
450
+ const n = parseInt(group, 16);
451
+ if (!Number.isFinite(n)) break;
452
+ for (let mask = 32768; mask; mask >>= 1) if (n & mask) bits++;
453
+ else return bits;
454
+ }
455
+ return bits;
456
+ }
457
+ let bits = 0;
458
+ for (const part of netmask.split(".")) {
459
+ const n = parseInt(part, 10);
460
+ if (!Number.isFinite(n)) break;
461
+ for (let mask = 128; mask; mask >>= 1) if (n & mask) bits++;
462
+ else return bits;
463
+ }
464
+ return bits;
465
+ }
466
+ function snapshotKey(interfaces) {
467
+ return [...interfaces].map((i) => `${i.name}|${i.family}|${i.address}|${i.netmask}`).toSorted().join("\n");
468
+ }
469
+ function formatKind(kind) {
470
+ switch (kind) {
471
+ case "lan": return "LAN";
472
+ case "wifi": return "Wi-Fi";
473
+ case "vpn": return "VPN";
474
+ case "docker": return "Docker";
475
+ case "loopback": return "Loopback";
476
+ case "other": return "Other";
477
+ }
478
+ }
479
+ //#endregion
480
+ exports.LocalNetworkAddon = LocalNetworkAddon;
481
+ exports.applyAllowlist = applyAllowlist;
482
+ exports.autoSeedAllowlist = autoSeedAllowlist;
483
+ exports.buildEndpoints = buildEndpoints;
484
+ exports.classifyKind = classifyKind;
485
+ exports.enumerateOsInterfaces = enumerateOsInterfaces;
486
+ exports.explainNonPlausible = explainNonPlausible;
487
+ exports.isPlausibleAutoSeed = isPlausibleAutoSeed;
488
+ exports.pickPreferred = pickPreferred;
489
+ exports.prefixLen = prefixLen;