@camstack/system 1.2.116 → 1.2.118

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 (63) hide show
  1. package/dist/addon-utils.d.ts +1 -1
  2. package/dist/addon-utils.js +1 -1
  3. package/dist/addon-utils.mjs +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  5. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  7. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  8. package/dist/builtins/alerts/alerts.addon.js +1 -1
  9. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  12. package/dist/builtins/console-logging/index.js +1 -1
  13. package/dist/builtins/console-logging/index.mjs +1 -1
  14. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  15. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  16. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  17. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  18. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  19. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  20. package/dist/builtins/hub-forwarder/index.js +1 -1
  21. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  22. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  23. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  24. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  25. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  26. package/dist/builtins/local-network/ipv6-lan.d.ts +26 -0
  27. package/dist/builtins/local-network/local-network.addon.d.ts +50 -14
  28. package/dist/builtins/local-network/local-network.addon.js +254 -38
  29. package/dist/builtins/local-network/local-network.addon.mjs +248 -39
  30. package/dist/builtins/loki-logging/index.js +1 -1
  31. package/dist/builtins/loki-logging/index.mjs +1 -1
  32. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  33. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  34. package/dist/builtins/platform-probe/index.js +1 -1
  35. package/dist/builtins/platform-probe/index.mjs +1 -1
  36. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  37. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  38. package/dist/builtins/snapshot/index.js +1 -1
  39. package/dist/builtins/snapshot/index.mjs +1 -1
  40. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  41. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  42. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +2 -2
  43. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +2 -2
  44. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  45. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  46. package/dist/builtins/system-config/system-config.addon.js +1 -1
  47. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  48. package/dist/builtins/winston-logging/index.js +1 -1
  49. package/dist/builtins/winston-logging/index.mjs +1 -1
  50. package/dist/{dist-Cri60Jd0.js → dist-C2_1HCpW.js} +149 -23
  51. package/dist/{dist-BpzbLPel.mjs → dist-DCTpBXm4.mjs} +149 -23
  52. package/dist/download/model-downloader.d.ts +18 -1
  53. package/dist/{file-data-plane-CuE_hBli.mjs → file-data-plane-BhKdxJgf.mjs} +49 -13
  54. package/dist/{file-data-plane-DUHPHa-Y.js → file-data-plane-DO8KbxCe.js} +49 -13
  55. package/dist/http/lan-http-bind.d.ts +12 -1
  56. package/dist/index.d.ts +1 -1
  57. package/dist/index.js +4 -3
  58. package/dist/index.mjs +4 -4
  59. package/dist/{lan-http-bind-CZ4EBeD_.js → lan-http-bind-DmgpFP6_.js} +53 -11
  60. package/dist/{lan-http-bind-BDJm4d-K.mjs → lan-http-bind-jKrj6OjQ.mjs} +48 -12
  61. package/dist/{retired-settings-keys-SrxMH3OT.mjs → retired-settings-keys-Czd76yLZ.mjs} +1 -1
  62. package/dist/{retired-settings-keys-BVAxT5XL.js → retired-settings-keys-DHRXLMPn.js} +1 -1
  63. package/package.json +1 -1
@@ -50,21 +50,56 @@ function buildHeaders(url) {
50
50
  if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
51
51
  return headers;
52
52
  }
53
- /**
54
- * Download a single file from a URL to a destination path.
55
- * Uses native fetch() (Node 22+) which handles redirects natively.
56
- * Streams to disk with optional progress callback.
57
- * Returns the destination path. Skips download if file already exists.
58
- */
59
- async function downloadFile(url, destPath, onProgress) {
53
+ var DEFAULT_MAX_REDIRECTS = 5;
54
+ function normalizeDownloadOptions(third) {
55
+ if (typeof third === "function") return { onProgress: third };
56
+ return third ?? {};
57
+ }
58
+ function isRedirectStatus(status) {
59
+ return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
60
+ }
61
+ function resolveRedirectUrl(current, location) {
62
+ return new URL(location, current);
63
+ }
64
+ async function downloadFile(url, destPath, onProgressOrOptions) {
60
65
  if (fs.existsSync(destPath)) return destPath;
66
+ const opts = normalizeDownloadOptions(onProgressOrOptions);
67
+ const fetchImpl = opts.fetchImpl ?? fetch;
68
+ const maxRedirects = opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
61
69
  fs.mkdirSync(path$1.dirname(destPath), { recursive: true });
62
70
  const tmpPath = destPath + ".downloading";
63
71
  try {
64
- const response = await fetch(url, {
65
- redirect: "follow",
66
- headers: buildHeaders(url)
67
- });
72
+ let current = url;
73
+ const seen = /* @__PURE__ */ new Set();
74
+ let response;
75
+ const manual = opts.redirectPolicy !== void 0;
76
+ for (let hop = 0; hop <= maxRedirects; hop++) {
77
+ const parsed = new URL(current);
78
+ if (opts.redirectPolicy) opts.redirectPolicy(parsed, hop);
79
+ if (seen.has(parsed.href)) throw new Error(`Redirect loop detected at ${parsed.href}`);
80
+ seen.add(parsed.href);
81
+ const controller = opts.timeoutMs !== void 0 ? new AbortController() : void 0;
82
+ const timer = controller && opts.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
83
+ try {
84
+ response = await fetchImpl(current, {
85
+ redirect: manual ? "manual" : "follow",
86
+ headers: buildHeaders(current),
87
+ ...controller ? { signal: controller.signal } : {}
88
+ });
89
+ } finally {
90
+ if (timer) clearTimeout(timer);
91
+ }
92
+ if (manual && isRedirectStatus(response.status)) {
93
+ const location = response.headers.get("location");
94
+ if (!location) throw new Error(`Redirect ${response.status} missing Location header`);
95
+ if (hop >= maxRedirects) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
96
+ current = resolveRedirectUrl(current, location).href;
97
+ continue;
98
+ }
99
+ break;
100
+ }
101
+ if (!response) throw new Error(`No response downloading ${url}`);
102
+ if (manual && isRedirectStatus(response.status)) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
68
103
  if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
69
104
  if (!response.body) throw new Error(`No response body from ${url}`);
70
105
  const total = parseInt(response.headers.get("content-length") ?? "0", 10);
@@ -75,9 +110,10 @@ async function downloadFile(url, destPath, onProgress) {
75
110
  for (;;) {
76
111
  const { done, value } = await reader.read();
77
112
  if (done || !value) break;
78
- fileStream.write(value);
79
113
  downloaded += value.length;
80
- onProgress?.(downloaded, total);
114
+ if (opts.maxBytes !== void 0 && downloaded > opts.maxBytes) throw new Error(`Downloaded ${downloaded} bytes exceeds the ${opts.maxBytes}-byte limit`);
115
+ fileStream.write(value);
116
+ opts.onProgress?.(downloaded, total);
81
117
  }
82
118
  } finally {
83
119
  fileStream.end();
@@ -51,21 +51,56 @@ function buildHeaders(url) {
51
51
  if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
52
52
  return headers;
53
53
  }
54
- /**
55
- * Download a single file from a URL to a destination path.
56
- * Uses native fetch() (Node 22+) which handles redirects natively.
57
- * Streams to disk with optional progress callback.
58
- * Returns the destination path. Skips download if file already exists.
59
- */
60
- async function downloadFile(url, destPath, onProgress) {
54
+ var DEFAULT_MAX_REDIRECTS = 5;
55
+ function normalizeDownloadOptions(third) {
56
+ if (typeof third === "function") return { onProgress: third };
57
+ return third ?? {};
58
+ }
59
+ function isRedirectStatus(status) {
60
+ return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
61
+ }
62
+ function resolveRedirectUrl(current, location) {
63
+ return new URL(location, current);
64
+ }
65
+ async function downloadFile(url, destPath, onProgressOrOptions) {
61
66
  if (node_fs.existsSync(destPath)) return destPath;
67
+ const opts = normalizeDownloadOptions(onProgressOrOptions);
68
+ const fetchImpl = opts.fetchImpl ?? fetch;
69
+ const maxRedirects = opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
62
70
  node_fs.mkdirSync(node_path.dirname(destPath), { recursive: true });
63
71
  const tmpPath = destPath + ".downloading";
64
72
  try {
65
- const response = await fetch(url, {
66
- redirect: "follow",
67
- headers: buildHeaders(url)
68
- });
73
+ let current = url;
74
+ const seen = /* @__PURE__ */ new Set();
75
+ let response;
76
+ const manual = opts.redirectPolicy !== void 0;
77
+ for (let hop = 0; hop <= maxRedirects; hop++) {
78
+ const parsed = new URL(current);
79
+ if (opts.redirectPolicy) opts.redirectPolicy(parsed, hop);
80
+ if (seen.has(parsed.href)) throw new Error(`Redirect loop detected at ${parsed.href}`);
81
+ seen.add(parsed.href);
82
+ const controller = opts.timeoutMs !== void 0 ? new AbortController() : void 0;
83
+ const timer = controller && opts.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
84
+ try {
85
+ response = await fetchImpl(current, {
86
+ redirect: manual ? "manual" : "follow",
87
+ headers: buildHeaders(current),
88
+ ...controller ? { signal: controller.signal } : {}
89
+ });
90
+ } finally {
91
+ if (timer) clearTimeout(timer);
92
+ }
93
+ if (manual && isRedirectStatus(response.status)) {
94
+ const location = response.headers.get("location");
95
+ if (!location) throw new Error(`Redirect ${response.status} missing Location header`);
96
+ if (hop >= maxRedirects) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
97
+ current = resolveRedirectUrl(current, location).href;
98
+ continue;
99
+ }
100
+ break;
101
+ }
102
+ if (!response) throw new Error(`No response downloading ${url}`);
103
+ if (manual && isRedirectStatus(response.status)) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
69
104
  if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
70
105
  if (!response.body) throw new Error(`No response body from ${url}`);
71
106
  const total = parseInt(response.headers.get("content-length") ?? "0", 10);
@@ -76,9 +111,10 @@ async function downloadFile(url, destPath, onProgress) {
76
111
  for (;;) {
77
112
  const { done, value } = await reader.read();
78
113
  if (done || !value) break;
79
- fileStream.write(value);
80
114
  downloaded += value.length;
81
- onProgress?.(downloaded, total);
115
+ if (opts.maxBytes !== void 0 && downloaded > opts.maxBytes) throw new Error(`Downloaded ${downloaded} bytes exceeds the ${opts.maxBytes}-byte limit`);
116
+ fileStream.write(value);
117
+ opts.onProgress?.(downloaded, total);
82
118
  }
83
119
  } finally {
84
120
  fileStream.end();
@@ -1,4 +1,5 @@
1
1
  import { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { Duplex } from 'node:stream';
2
3
  export interface LanHttpBindOptions {
3
4
  readonly enabled: boolean;
4
5
  readonly port: number;
@@ -10,8 +11,18 @@ export interface LanHttpBindResult {
10
11
  readonly port: number;
11
12
  }
12
13
  export type LanHttpRequestHandler = (req: IncomingMessage, res: ServerResponse) => void;
14
+ export type LanHttpUpgradeHandler = (req: IncomingMessage, socket: Duplex, head: Buffer) => void;
15
+ export interface LanHttpHandlers {
16
+ readonly onRequest: LanHttpRequestHandler;
17
+ readonly onUpgrade: LanHttpUpgradeHandler;
18
+ }
13
19
  export declare const DEFAULT_LAN_HTTP_PORT = 4480;
14
- export declare function registerLanHttpHandler(next: LanHttpRequestHandler | null): void;
20
+ /** Map "all IPv4" to dual-stack IPv6 (`::`, ipv6Only false) so IPv4 still works. */
21
+ export declare function allFamiliesListenHost(host: string): {
22
+ host: string;
23
+ ipv6Only: boolean;
24
+ };
25
+ export declare function registerLanHttpHandler(next: LanHttpHandlers | null): void;
15
26
  export declare function readLanHttpState(): LanHttpBindResult;
16
27
  export declare function applyLanHttp(options: LanHttpBindOptions): Promise<LanHttpBindResult>;
17
28
  /** After the hub registers the Fastify request handler, bind whatever was pending. */
package/dist/index.d.ts CHANGED
@@ -80,7 +80,7 @@ export { StorageLocationManager } from './storage/storage-location-manager.js';
80
80
  export type { IFileStorage, IStorageLocation, IStorageProvider as ICoreStorageProvider, IStructuredStorage, QueryFilter, StorageRecord, } from './storage/storage-manager.js';
81
81
  export { StorageManager } from './storage/storage-manager.js';
82
82
  export * from './tls/index.js';
83
- export { applyLanHttp, bindPendingLanHttp, closeLanHttp, DEFAULT_LAN_HTTP_PORT, readLanHttpState, registerLanHttpHandler, } from './http/lan-http-bind.js';
83
+ export { applyLanHttp, allFamiliesListenHost, bindPendingLanHttp, closeLanHttp, DEFAULT_LAN_HTTP_PORT, readLanHttpState, registerLanHttpHandler, } from './http/lan-http-bind.js';
84
84
  export { IntegrationRegistry } from './builtins/sqlite-storage/integration-registry.js';
85
85
  export { type EnsureAddonNativePrebuildsOptions, ensureAddonNativePrebuilds, type NativeEnsureOutcome, type NativeEnsureResult, } from './kernel/deps/ensure-addon-natives.js';
86
86
  export { type EnsureNativePrebuildsOptions, ensureNativePrebuilds, hasDotNode, NATIVE_SCAN_DEPTH, type PrebuildFetchFn, type PrebuildTarget, TRADITIONAL_NATIVE_PACKAGES, } from './kernel/deps/ensure-native-prebuilds.js';
package/dist/index.js CHANGED
@@ -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-Cri60Jd0.js");
3
+ const require_dist = require("./dist-C2_1HCpW.js");
4
4
  const require_builtins_alerts_alerts_addon = require("./builtins/alerts/alerts.addon.js");
5
5
  require("./builtins/alerts/index.js");
6
6
  const require_formatter = require("./formatter-DqAKDlvN.js");
@@ -24,10 +24,10 @@ require("./builtins/storage-orchestrator/index.js");
24
24
  const require_builtins_system_config_system_config_addon = require("./builtins/system-config/system-config.addon.js");
25
25
  require("./builtins/system-config/index.js");
26
26
  const require_builtins_winston_logging_index = require("./builtins/winston-logging/index.js");
27
- const require_file_data_plane = require("./file-data-plane-DUHPHa-Y.js");
27
+ const require_file_data_plane = require("./file-data-plane-DO8KbxCe.js");
28
28
  const require_manifest_python_deps = require("./manifest-python-deps-CwBbX4Ut.js");
29
29
  const require_resource_monitor = require("./resource-monitor-CdnzxBLP.js");
30
- const require_lan_http_bind = require("./lan-http-bind-CZ4EBeD_.js");
30
+ const require_lan_http_bind = require("./lan-http-bind-DmgpFP6_.js");
31
31
  const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
32
32
  let zod = require("zod");
33
33
  let node_crypto = require("node:crypto");
@@ -94948,6 +94948,7 @@ exports.WinstonLoggingAddon = require_builtins_winston_logging_index.WinstonLogg
94948
94948
  exports.__resetCapUsageRegistryForTests = require_manifest_python_deps.__resetCapUsageRegistryForTests;
94949
94949
  exports.adaptBrokerToCluster = require_manifest_python_deps.adaptBrokerToCluster;
94950
94950
  exports.addonSettingsCapability = require_dist.addonSettingsCapability;
94951
+ exports.allFamiliesListenHost = require_lan_http_bind.allFamiliesListenHost;
94951
94952
  exports.applyLanHttp = require_lan_http_bind.applyLanHttp;
94952
94953
  exports.bindPendingLanHttp = require_lan_http_bind.bindPendingLanHttp;
94953
94954
  exports.bootstrapSchema = bootstrapSchema;
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
2
- import { At as asNumber, B as extractNestedAddonId, Bt as parseJsonUnknown$1, Dt as ReadinessTimeoutError, Et as ReadinessRegistry, Ft as expandCapMethods, Gt as EventCategory$1, H as isArrayOutputSchema, Ht as resolveCapMount, J as lifecycleJobSchema, K as isVoidInput, Mt as createEvent, Nt as emitDownForOwnedCaps, Q as looseSchema, St as DEVICE_STATUS_METHOD, U as isCollectionArrayMethod, Ut as scopeKey, Vt as readinessKey, W as isObjectInput, Z as logLevelAtMost, bt as DATAPLANE_SECRET_HEADER$1, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, it as procedureAuthKey, jt as asString$1, kt as asJsonObject$1, ot as scopesAllowAddon, q as kebabToCamel, st as scopesAllowDeviceCap, t as ALL_CAPABILITY_DEFINITIONS, tt as objectInputDeclaresAddonId, vt as errMsg$1, xt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, y as addonSettingsCapability, zt as parseJsonObject } from "./dist-BpzbLPel.mjs";
2
+ import { At as asNumber, B as extractNestedAddonId, Bt as parseJsonUnknown$1, Dt as ReadinessTimeoutError, Et as ReadinessRegistry, Ft as expandCapMethods, Gt as EventCategory$1, H as isArrayOutputSchema, Ht as resolveCapMount, J as lifecycleJobSchema, K as isVoidInput, Mt as createEvent, Nt as emitDownForOwnedCaps, Q as looseSchema, St as DEVICE_STATUS_METHOD, U as isCollectionArrayMethod, Ut as scopeKey, Vt as readinessKey, W as isObjectInput, Z as logLevelAtMost, bt as DATAPLANE_SECRET_HEADER$1, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, it as procedureAuthKey, jt as asString$1, kt as asJsonObject$1, ot as scopesAllowAddon, q as kebabToCamel, st as scopesAllowDeviceCap, t as ALL_CAPABILITY_DEFINITIONS, tt as objectInputDeclaresAddonId, vt as errMsg$1, xt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, y as addonSettingsCapability, zt as parseJsonObject } from "./dist-DCTpBXm4.mjs";
3
3
  import { AlertCenterAddon } from "./builtins/alerts/alerts.addon.mjs";
4
4
  import "./builtins/alerts/index.mjs";
5
5
  import { t as formatLogLine } from "./formatter-B7qW8bPJ.mjs";
@@ -23,10 +23,10 @@ import "./builtins/storage-orchestrator/index.mjs";
23
23
  import { SystemConfigAddon } from "./builtins/system-config/system-config.addon.mjs";
24
24
  import "./builtins/system-config/index.mjs";
25
25
  import { WinstonDestination, WinstonLoggingAddon } from "./builtins/winston-logging/index.mjs";
26
- import { a as parseTokenizedUrl, c as collectModelFiles, d as downloadModel, f as ensureModel, h as isModelDownloaded, i as parseRangeHeader, l as deleteModelFromDisk, m as getModelFilePath, n as contentTypeFor, o as resolveFilePath, p as fetchJson, r as createAuthenticatedFileServer, s as ModelDownloadService, t as createFileDataPlaneHandler, u as downloadFile } from "./file-data-plane-CuE_hBli.mjs";
26
+ import { a as parseTokenizedUrl, c as collectModelFiles, d as downloadModel, f as ensureModel, h as isModelDownloaded, i as parseRangeHeader, l as deleteModelFromDisk, m as getModelFilePath, n as contentTypeFor, o as resolveFilePath, p as fetchJson, r as createAuthenticatedFileServer, s as ModelDownloadService, t as createFileDataPlaneHandler, u as downloadFile } from "./file-data-plane-BhKdxJgf.mjs";
27
27
  import { $ as buildNativeCapProxy, A as createHubCapForwardService, At as buildHeapSample, B as AGENT_CAP_FWD_ACTION, C as brokerTransportLink, Ct as runNpm, D as localProviderLink, Dt as HEAP_WATCH_INTERVAL_MS, E as ipcParentLink, Et as HEAP_RECLAIM_TRIGGER_MB, F as createUdsLogger, Ft as strandedMb, G as callWithServiceDiscovery, H as CapRouteResolver, I as createUdsLoggerWithControl, J as UdsLocalTransportServer, K as createLocalTransport, L as LocalChildClient, M as createUdsEventBridge, Mt as shouldReclaim, N as createUdsEventBus, Nt as startHeapWatch, O as HUB_CAP_FWD_ACTION, Ot as HEAP_WATCH_WARN_RATIO, P as udsChildLogToWorkerEntry, Pt as startRunnerHeapWatch, Q as encodeFrame, R as LocalChildRegistry, S as brokerCallForCap, St as resolveNpmInvocation, T as ipcChildLink, Tt as HEAP_RECLAIM_MIN_INTERVAL_MS, U as CapRouteError, V as AGENT_CAP_FWD_SERVICE, W as classifyCapRoute, X as localEndpointPath, Y as SocketChannel, Z as FrameDecoder, _ as createKernelHwAccel, _t as CapabilityHandle, a as getWorkerDeviceRegistry, b as __resetCapUsageRegistryForTests, bt as installManifestNativeDeps, c as setHubConnected, ct as NATIVE_PROVIDER_SERVICE_INFIX, d as getBrokerEventBus, dt as capBareAction, et as buildUdsNativeCapProxy, f as getMoleculerEventStats, ft as capServiceName, g as AddonDepsManager, gt as DeviceRegistry, h as subscribePassthrough, ht as serializeTypedArrays, i as createUdsAddonContext, it as mountNativeCapService, j as createParentUnownedCallHandler, jt as createV8Reclaimer, k as HUB_CAP_FWD_SERVICE, kt as RUNNER_HEAP_WATCH_INTERVAL_MS, l as EVENT_TOPIC_PREFIX, lt as capActionName, m as setNodeEventInterest, mt as deserializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as createAddonService, p as registerEventBusService, pt as parseCapAction, q as UdsLocalTransportClient, r as createAddonContext, s as getOrInitReadinessRegistryForClient, st as validateProviderRegistrations, t as installManifestPythonDeps, tt as createBrokerDeviceManagerApi, u as clusterEventTopic, ut as capActionSuffix, v as resolveHwAccel, vt as CapabilityUnavailableError, w as buildLinkChain, wt as createAddonDataPlaneFacility, x as getCapUsageRegistry, xt as resolveAddonClass, y as CapUsageRegistry, yt as copyBundledNativeModules, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-SGdbr9D5.mjs";
28
28
  import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-BWmQ5i-o.mjs";
29
- import { S as evaluateExistingCert, _ as collectCertIdentity, a as readLanHttpState, b as MAX_LEAF_VALIDITY_DAYS, c as readTlsAccessStatus, d as writeTlsMode, f as validateUploadedTls, g as CA_COMMON_NAME, h as reissueTlsLeaf, i as closeLanHttp, l as readTlsMode, m as loadTlsCert, n as applyLanHttp, o as registerLanHttpHandler, p as ensureTlsCert, r as bindPendingLanHttp, s as readExtraSans, t as DEFAULT_LAN_HTTP_PORT, u as writeExtraSans, v as CA_VALIDITY_DAYS, x as SERVER_AUTH_OID, y as LEAF_RENEWAL_WINDOW_DAYS } from "./lan-http-bind-BDJm4d-K.mjs";
29
+ import { C as evaluateExistingCert, S as SERVER_AUTH_OID, _ as CA_COMMON_NAME, a as closeLanHttp, b as LEAF_RENEWAL_WINDOW_DAYS, c as readExtraSans, d as writeExtraSans, f as writeTlsMode, g as reissueTlsLeaf, h as loadTlsCert, i as bindPendingLanHttp, l as readTlsAccessStatus, m as ensureTlsCert, n as allFamiliesListenHost, o as readLanHttpState, p as validateUploadedTls, r as applyLanHttp, s as registerLanHttpHandler, t as DEFAULT_LAN_HTTP_PORT, u as readTlsMode, v as collectCertIdentity, x as MAX_LEAF_VALIDITY_DAYS, y as CA_VALIDITY_DAYS } from "./lan-http-bind-jKrj6OjQ.mjs";
30
30
  import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
31
31
  import { z } from "zod";
32
32
  import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
@@ -94816,4 +94816,4 @@ var LifecycleJobEngine = class {
94816
94816
  }
94817
94817
  };
94818
94818
  //#endregion
94819
- export { AGENT_CAP_FWD_ACTION, AGENT_CAP_FWD_SERVICE, AGENT_READINESS_SERVICE_NAME, ALL_CAPABILITY_DEFINITIONS, AddonApiFactory, AddonDepsManager, AddonEngineManager, AddonHealthMonitor, AddonInstaller, AddonLoader, AddonManifest, AddonRouteRegistry, AlertCenterAddon, ApiKeyManager, AuthManager, CA_COMMON_NAME, CA_VALIDITY_DAYS, CLUSTER_SECRET_MISMATCH_TYPE, CLUSTER_SECRET_REJECTED_EXIT_CODE, CORE_CAP_SERVICE_NAME, CapRouteError, CapRouteResolver, CapUsageRegistry, CapabilityHandle, CapabilityRegistry, CapabilityUnavailableError, ConfigManager, ConfigStore, ConsoleDestination, ConsoleLoggingAddon, CoreBlocksAddon, CustomActionRegistry, DEFAULT_DATA_PATH, DEFAULT_LAN_HTTP_PORT, DEVICE_SETTINGS_CONTRIBUTION_METHODS, DEVICE_STATUS_METHOD, DataPlaneRegistry, DeviceManagerAddon, DeviceRegistry, DeviceStore, EVENT_TOPIC_PREFIX, EngineManagerResolver, EventBus, FeatureManager, FilesystemStorageAddon, FilesystemStorageProvider, FrameDecoder, FsStorageBackend, HEALTH_MONITOR_GRACE_PERIOD_MS, HEALTH_MONITOR_RETRY_INTERVALS_MS, HEALTH_MONITOR_TICK_MS, HEAP_RECLAIM_MIN_INTERVAL_MS, HEAP_RECLAIM_TRIGGER_MB, HEAP_WATCH_INTERVAL_MS, HEAP_WATCH_WARN_RATIO, HUB_CAP_FWD_ACTION, HUB_CAP_FWD_SERVICE, HubForwarderAddon, HubForwarderDestination, HubLogForwarder, HubNodeRegistry, INFRA_CAPABILITIES, IntegrationRegistry, JobJournal, LEAF_RENEWAL_WINDOW_DAYS, LifecycleJobEngine, LifecycleStateMachine, LivenessMonitorAddon, LocalAuthAddon, LocalChildClient, LocalChildRegistry, LogManager, LogRingBuffer, LokiDestination, LokiLoggingAddon, MAX_LEAF_VALIDITY_DAYS, METHOD_ACCESS_MAP, ModelDownloadService, NATIVE_PROVIDER_SERVICE_INFIX, NATIVE_SCAN_DEPTH, NativeMetricsAddon, NativeMetricsProvider, NetworkQualityTracker, NotificationService, PYTHON_VERSION, PipelineRunner, PipelineValidator, PythonEnvManager, QUARANTINE_DIRNAME, RESTART_MARKER_FILE, RUNNER_HEAP_WATCH_INTERVAL_MS, RUNTIME_DEFAULTS, ReadinessRegistry, ReadinessTimeoutError, ReplEngine, RingBuffer, SERVER_AUTH_OID, ScopedLogger, ScopedTokenManager, SocketChannel, SqliteSettingsAddon, SqliteSettingsBackend, StagingArea, StorageLocationManager, StorageManager, StorageOrchestratorAddon, StorageOrchestratorService, SystemConfigAddon, SystemEventBus, TRADITIONAL_NATIVE_PACKAGES, ToastService, UDS_NO_ROUTE_PREFIX, UdsLocalTransportClient, UdsLocalTransportServer, UserManager, WinstonDestination, WinstonLoggingAddon, __resetCapUsageRegistryForTests, adaptBrokerToCluster, addonSettingsCapability, applyLanHttp, bindPendingLanHttp, bootstrapSchema, brokerCallForCap, brokerTransportLink, buildBinaryPath, buildCapRouters, buildHeapSample, buildLinkChain, buildNativeCapProxy, buildNodeManifest, buildStorageLocationRegistry, buildUdsNativeCapProxy, builderMountedCapNames, callRegisterNodeWithRetry, callWithServiceDiscovery, capActionName, capActionSuffix, capBareAction, capServiceName, classifyAddonDir, classifyCapRoute, clearPendingRestart, closeLanHttp, clusterEventTopic, clusterSecretMatches, collectCertIdentity, collectModelFiles, contentTypeFor, copyDirRecursive, copyExtraFileDirs, createAddonContext, createAddonDataPlaneFacility, createAddonService, createAuthenticatedFileServer, createBroker, createBrokerDeviceManagerApi, createCoreCapService, createFileDataPlaneHandler, createHubCapForwardService, createHubService, createKernelHwAccel, createLocalTransport, createParentUnownedCallHandler, createProcessService, createReadinessService, createReadinessServiceForRegistry, createScopedProcessManager, createStreamProbeBrokerService, createUdsAddonContext, createUdsEventBridge, createUdsEventBus, createUdsLogger, createUdsLoggerWithControl, createV8Reclaimer, deleteModelFromDisk, deriveAgentListenPort, describeProviderKindDrift, detectWorkspacePackagesDir, downloadBinary, downloadFile, downloadModel, emitDownForOwnedCaps, encodeFrame, ensureAddonNativePrebuilds, ensureBinary, ensureDir, ensureFfmpeg, ensureLibraryBuilt, ensureModel, ensureNativePrebuilds, ensurePython, ensureTlsCert, evaluateExistingCert, expandCapMethods, fetchJson, findInPath, formatLogLine, getBrokerEventBus, getCapUsageRegistry, getFfmpegDownloadUrl, getModelFilePath, getMoleculerEventStats, getOrInitReadinessRegistry, getOrInitReadinessRegistryForClient, getPidStats, getPlatformInfo, getPythonDownloadUrl, getRestartMarkerPath, getSinglePidStats, getWorkerDeviceRegistry, hasDotNode, hashClusterSecret, installManifestNativeDeps, installManifestPythonDeps, installPackageFromNpm, installPythonPackages, installPythonRequirements, ipcChildLink, ipcParentLink, isAddonDeploySource, isArrayOutputSchema, isClusterSecretMismatchError, isCollectionArrayMethod, isInfraCapability, isModelDownloaded, isSourceNewer, loadTlsCert, localEndpointPath, localProviderLink, mountNativeCapService, parseCapAction, parseRangeHeader, parseTokenizedUrl, proxyToUpstream, quarantineAddonResidue, readExtraSans, readLanHttpState, readPendingRestart, readTlsAccessStatus, readTlsMode, readinessKey, registerEventBusService, registerLanHttpHandler, reissueTlsLeaf, resolveFilePath, resolveHwAccel, resolveNpmInvocation, runNpm, scheduleSelfRestart, scopeKey, scopesAllowAddon, scopesAllowDeviceCap, selectAddonResidue, serializeTypedArrays, setHubConnected, setNodeEventInterest, shouldReclaim, startHeapWatch, startRunnerHeapWatch, strandedMb, stripCamstackDeps, subscribePassthrough, udsChildLogToWorkerEntry, validateProviderRegistrations, validateUploadedTls, writeExtraSans, writePendingRestart, writeTlsMode };
94819
+ export { AGENT_CAP_FWD_ACTION, AGENT_CAP_FWD_SERVICE, AGENT_READINESS_SERVICE_NAME, ALL_CAPABILITY_DEFINITIONS, AddonApiFactory, AddonDepsManager, AddonEngineManager, AddonHealthMonitor, AddonInstaller, AddonLoader, AddonManifest, AddonRouteRegistry, AlertCenterAddon, ApiKeyManager, AuthManager, CA_COMMON_NAME, CA_VALIDITY_DAYS, CLUSTER_SECRET_MISMATCH_TYPE, CLUSTER_SECRET_REJECTED_EXIT_CODE, CORE_CAP_SERVICE_NAME, CapRouteError, CapRouteResolver, CapUsageRegistry, CapabilityHandle, CapabilityRegistry, CapabilityUnavailableError, ConfigManager, ConfigStore, ConsoleDestination, ConsoleLoggingAddon, CoreBlocksAddon, CustomActionRegistry, DEFAULT_DATA_PATH, DEFAULT_LAN_HTTP_PORT, DEVICE_SETTINGS_CONTRIBUTION_METHODS, DEVICE_STATUS_METHOD, DataPlaneRegistry, DeviceManagerAddon, DeviceRegistry, DeviceStore, EVENT_TOPIC_PREFIX, EngineManagerResolver, EventBus, FeatureManager, FilesystemStorageAddon, FilesystemStorageProvider, FrameDecoder, FsStorageBackend, HEALTH_MONITOR_GRACE_PERIOD_MS, HEALTH_MONITOR_RETRY_INTERVALS_MS, HEALTH_MONITOR_TICK_MS, HEAP_RECLAIM_MIN_INTERVAL_MS, HEAP_RECLAIM_TRIGGER_MB, HEAP_WATCH_INTERVAL_MS, HEAP_WATCH_WARN_RATIO, HUB_CAP_FWD_ACTION, HUB_CAP_FWD_SERVICE, HubForwarderAddon, HubForwarderDestination, HubLogForwarder, HubNodeRegistry, INFRA_CAPABILITIES, IntegrationRegistry, JobJournal, LEAF_RENEWAL_WINDOW_DAYS, LifecycleJobEngine, LifecycleStateMachine, LivenessMonitorAddon, LocalAuthAddon, LocalChildClient, LocalChildRegistry, LogManager, LogRingBuffer, LokiDestination, LokiLoggingAddon, MAX_LEAF_VALIDITY_DAYS, METHOD_ACCESS_MAP, ModelDownloadService, NATIVE_PROVIDER_SERVICE_INFIX, NATIVE_SCAN_DEPTH, NativeMetricsAddon, NativeMetricsProvider, NetworkQualityTracker, NotificationService, PYTHON_VERSION, PipelineRunner, PipelineValidator, PythonEnvManager, QUARANTINE_DIRNAME, RESTART_MARKER_FILE, RUNNER_HEAP_WATCH_INTERVAL_MS, RUNTIME_DEFAULTS, ReadinessRegistry, ReadinessTimeoutError, ReplEngine, RingBuffer, SERVER_AUTH_OID, ScopedLogger, ScopedTokenManager, SocketChannel, SqliteSettingsAddon, SqliteSettingsBackend, StagingArea, StorageLocationManager, StorageManager, StorageOrchestratorAddon, StorageOrchestratorService, SystemConfigAddon, SystemEventBus, TRADITIONAL_NATIVE_PACKAGES, ToastService, UDS_NO_ROUTE_PREFIX, UdsLocalTransportClient, UdsLocalTransportServer, UserManager, WinstonDestination, WinstonLoggingAddon, __resetCapUsageRegistryForTests, adaptBrokerToCluster, addonSettingsCapability, allFamiliesListenHost, applyLanHttp, bindPendingLanHttp, bootstrapSchema, brokerCallForCap, brokerTransportLink, buildBinaryPath, buildCapRouters, buildHeapSample, buildLinkChain, buildNativeCapProxy, buildNodeManifest, buildStorageLocationRegistry, buildUdsNativeCapProxy, builderMountedCapNames, callRegisterNodeWithRetry, callWithServiceDiscovery, capActionName, capActionSuffix, capBareAction, capServiceName, classifyAddonDir, classifyCapRoute, clearPendingRestart, closeLanHttp, clusterEventTopic, clusterSecretMatches, collectCertIdentity, collectModelFiles, contentTypeFor, copyDirRecursive, copyExtraFileDirs, createAddonContext, createAddonDataPlaneFacility, createAddonService, createAuthenticatedFileServer, createBroker, createBrokerDeviceManagerApi, createCoreCapService, createFileDataPlaneHandler, createHubCapForwardService, createHubService, createKernelHwAccel, createLocalTransport, createParentUnownedCallHandler, createProcessService, createReadinessService, createReadinessServiceForRegistry, createScopedProcessManager, createStreamProbeBrokerService, createUdsAddonContext, createUdsEventBridge, createUdsEventBus, createUdsLogger, createUdsLoggerWithControl, createV8Reclaimer, deleteModelFromDisk, deriveAgentListenPort, describeProviderKindDrift, detectWorkspacePackagesDir, downloadBinary, downloadFile, downloadModel, emitDownForOwnedCaps, encodeFrame, ensureAddonNativePrebuilds, ensureBinary, ensureDir, ensureFfmpeg, ensureLibraryBuilt, ensureModel, ensureNativePrebuilds, ensurePython, ensureTlsCert, evaluateExistingCert, expandCapMethods, fetchJson, findInPath, formatLogLine, getBrokerEventBus, getCapUsageRegistry, getFfmpegDownloadUrl, getModelFilePath, getMoleculerEventStats, getOrInitReadinessRegistry, getOrInitReadinessRegistryForClient, getPidStats, getPlatformInfo, getPythonDownloadUrl, getRestartMarkerPath, getSinglePidStats, getWorkerDeviceRegistry, hasDotNode, hashClusterSecret, installManifestNativeDeps, installManifestPythonDeps, installPackageFromNpm, installPythonPackages, installPythonRequirements, ipcChildLink, ipcParentLink, isAddonDeploySource, isArrayOutputSchema, isClusterSecretMismatchError, isCollectionArrayMethod, isInfraCapability, isModelDownloaded, isSourceNewer, loadTlsCert, localEndpointPath, localProviderLink, mountNativeCapService, parseCapAction, parseRangeHeader, parseTokenizedUrl, proxyToUpstream, quarantineAddonResidue, readExtraSans, readLanHttpState, readPendingRestart, readTlsAccessStatus, readTlsMode, readinessKey, registerEventBusService, registerLanHttpHandler, reissueTlsLeaf, resolveFilePath, resolveHwAccel, resolveNpmInvocation, runNpm, scheduleSelfRestart, scopeKey, scopesAllowAddon, scopesAllowDeviceCap, selectAddonResidue, serializeTypedArrays, setHubConnected, setNodeEventInterest, shouldReclaim, startHeapWatch, startRunnerHeapWatch, strandedMb, stripCamstackDeps, subscribePassthrough, udsChildLogToWorkerEntry, validateProviderRegistrations, validateUploadedTls, writeExtraSans, writePendingRestart, writeTlsMode };
@@ -622,11 +622,15 @@ function readTlsAccessStatus(dataDir, restartRequired = false) {
622
622
  * Second HTTP listener that shares the hub's existing request handler.
623
623
  *
624
624
  * Fastify is one protocol per instance; HTTPS stays on :4443 and this
625
- * binds a plain `http.Server` that emits `request` onto the same
626
- * handler graph (tRPC, cookies, data-plane, static).
625
+ * binds a plain `http.Server` that emits `request` AND `upgrade` onto the
626
+ * same handler graph (tRPC HTTP, cookies, data-plane, static, tRPC WS).
627
+ *
628
+ * Forwarding only `request` is not enough: the viewer speaks tRPC exclusively
629
+ * over WebSocket (`wsLink`). `/health` wins the LAN race, then `ws://…/trpc`
630
+ * hangs because nobody handles the upgrade on this socket.
627
631
  */
628
632
  var DEFAULT_HTTP_PORT = 4480;
629
- var handler = null;
633
+ var handlers = null;
630
634
  var server = null;
631
635
  var pending = null;
632
636
  var state = {
@@ -634,9 +638,21 @@ var state = {
634
638
  error: null,
635
639
  port: DEFAULT_HTTP_PORT
636
640
  };
641
+ var boundRequestedHost = null;
637
642
  var DEFAULT_LAN_HTTP_PORT = DEFAULT_HTTP_PORT;
643
+ /** Map "all IPv4" to dual-stack IPv6 (`::`, ipv6Only false) so IPv4 still works. */
644
+ function allFamiliesListenHost(host) {
645
+ if (host === "0.0.0.0" || host === "*" || host === "") return {
646
+ host: "::",
647
+ ipv6Only: false
648
+ };
649
+ return {
650
+ host,
651
+ ipv6Only: false
652
+ };
653
+ }
638
654
  function registerLanHttpHandler(next) {
639
- handler = next;
655
+ handlers = next;
640
656
  }
641
657
  function readLanHttpState() {
642
658
  return state;
@@ -652,7 +668,7 @@ async function applyLanHttp(options) {
652
668
  };
653
669
  return state;
654
670
  }
655
- if (handler === null) {
671
+ if (handlers === null) {
656
672
  state = {
657
673
  listening: false,
658
674
  error: "HTTP listener is not registered yet",
@@ -660,14 +676,17 @@ async function applyLanHttp(options) {
660
676
  };
661
677
  return state;
662
678
  }
663
- if (server !== null && state.listening && state.port === options.port) return state;
679
+ if (server !== null && state.listening && (options.port === 0 || state.port === options.port) && boundRequestedHost === options.host) return state;
664
680
  await closeLanHttp();
665
681
  try {
666
- server = await listenHttp(options.port, options.host, handler);
682
+ const bound = await listenHttp(options.port, options.host, handlers);
683
+ server = bound;
684
+ boundRequestedHost = options.host;
685
+ const addr = bound.address();
667
686
  state = {
668
687
  listening: true,
669
688
  error: null,
670
- port: options.port
689
+ port: typeof addr === "object" && addr !== null ? addr.port : options.port
671
690
  };
672
691
  return state;
673
692
  } catch (err) {
@@ -692,16 +711,29 @@ async function bindPendingLanHttp() {
692
711
  async function closeLanHttp() {
693
712
  const current = server;
694
713
  server = null;
714
+ boundRequestedHost = null;
695
715
  if (current === null) return;
696
716
  await new Promise((resolve) => {
697
717
  current.close(() => resolve());
698
718
  });
699
719
  }
700
- function listenHttp(port, host, onRequest) {
720
+ function listenHttp(port, host, next) {
721
+ const resolved = allFamiliesListenHost(host);
722
+ return listenOn(port, resolved, next).catch((err) => {
723
+ if (resolved.host === "::" && host !== "::") return listenOn(port, {
724
+ host: "0.0.0.0",
725
+ ipv6Only: false
726
+ }, next);
727
+ throw err;
728
+ });
729
+ }
730
+ function listenOn(port, bind, next) {
701
731
  return new Promise((resolve, reject) => {
702
- const created = (0, node_http.createServer)(onRequest);
732
+ const created = (0, node_http.createServer)(next.onRequest);
733
+ created.on("upgrade", next.onUpgrade);
703
734
  const onError = (err) => {
704
735
  created.off("listening", onListening);
736
+ created.close();
705
737
  reject(err);
706
738
  };
707
739
  const onListening = () => {
@@ -710,7 +742,11 @@ function listenHttp(port, host, onRequest) {
710
742
  };
711
743
  created.once("error", onError);
712
744
  created.once("listening", onListening);
713
- created.listen(port, host);
745
+ created.listen({
746
+ port,
747
+ host: bind.host,
748
+ ipv6Only: bind.ipv6Only
749
+ });
714
750
  });
715
751
  }
716
752
  //#endregion
@@ -750,6 +786,12 @@ Object.defineProperty(exports, "SERVER_AUTH_OID", {
750
786
  return SERVER_AUTH_OID;
751
787
  }
752
788
  });
789
+ Object.defineProperty(exports, "allFamiliesListenHost", {
790
+ enumerable: true,
791
+ get: function() {
792
+ return allFamiliesListenHost;
793
+ }
794
+ });
753
795
  Object.defineProperty(exports, "applyLanHttp", {
754
796
  enumerable: true,
755
797
  get: function() {
@@ -621,11 +621,15 @@ function readTlsAccessStatus(dataDir, restartRequired = false) {
621
621
  * Second HTTP listener that shares the hub's existing request handler.
622
622
  *
623
623
  * Fastify is one protocol per instance; HTTPS stays on :4443 and this
624
- * binds a plain `http.Server` that emits `request` onto the same
625
- * handler graph (tRPC, cookies, data-plane, static).
624
+ * binds a plain `http.Server` that emits `request` AND `upgrade` onto the
625
+ * same handler graph (tRPC HTTP, cookies, data-plane, static, tRPC WS).
626
+ *
627
+ * Forwarding only `request` is not enough: the viewer speaks tRPC exclusively
628
+ * over WebSocket (`wsLink`). `/health` wins the LAN race, then `ws://…/trpc`
629
+ * hangs because nobody handles the upgrade on this socket.
626
630
  */
627
631
  var DEFAULT_HTTP_PORT = 4480;
628
- var handler = null;
632
+ var handlers = null;
629
633
  var server = null;
630
634
  var pending = null;
631
635
  var state = {
@@ -633,9 +637,21 @@ var state = {
633
637
  error: null,
634
638
  port: DEFAULT_HTTP_PORT
635
639
  };
640
+ var boundRequestedHost = null;
636
641
  var DEFAULT_LAN_HTTP_PORT = DEFAULT_HTTP_PORT;
642
+ /** Map "all IPv4" to dual-stack IPv6 (`::`, ipv6Only false) so IPv4 still works. */
643
+ function allFamiliesListenHost(host) {
644
+ if (host === "0.0.0.0" || host === "*" || host === "") return {
645
+ host: "::",
646
+ ipv6Only: false
647
+ };
648
+ return {
649
+ host,
650
+ ipv6Only: false
651
+ };
652
+ }
637
653
  function registerLanHttpHandler(next) {
638
- handler = next;
654
+ handlers = next;
639
655
  }
640
656
  function readLanHttpState() {
641
657
  return state;
@@ -651,7 +667,7 @@ async function applyLanHttp(options) {
651
667
  };
652
668
  return state;
653
669
  }
654
- if (handler === null) {
670
+ if (handlers === null) {
655
671
  state = {
656
672
  listening: false,
657
673
  error: "HTTP listener is not registered yet",
@@ -659,14 +675,17 @@ async function applyLanHttp(options) {
659
675
  };
660
676
  return state;
661
677
  }
662
- if (server !== null && state.listening && state.port === options.port) return state;
678
+ if (server !== null && state.listening && (options.port === 0 || state.port === options.port) && boundRequestedHost === options.host) return state;
663
679
  await closeLanHttp();
664
680
  try {
665
- server = await listenHttp(options.port, options.host, handler);
681
+ const bound = await listenHttp(options.port, options.host, handlers);
682
+ server = bound;
683
+ boundRequestedHost = options.host;
684
+ const addr = bound.address();
666
685
  state = {
667
686
  listening: true,
668
687
  error: null,
669
- port: options.port
688
+ port: typeof addr === "object" && addr !== null ? addr.port : options.port
670
689
  };
671
690
  return state;
672
691
  } catch (err) {
@@ -691,16 +710,29 @@ async function bindPendingLanHttp() {
691
710
  async function closeLanHttp() {
692
711
  const current = server;
693
712
  server = null;
713
+ boundRequestedHost = null;
694
714
  if (current === null) return;
695
715
  await new Promise((resolve) => {
696
716
  current.close(() => resolve());
697
717
  });
698
718
  }
699
- function listenHttp(port, host, onRequest) {
719
+ function listenHttp(port, host, next) {
720
+ const resolved = allFamiliesListenHost(host);
721
+ return listenOn(port, resolved, next).catch((err) => {
722
+ if (resolved.host === "::" && host !== "::") return listenOn(port, {
723
+ host: "0.0.0.0",
724
+ ipv6Only: false
725
+ }, next);
726
+ throw err;
727
+ });
728
+ }
729
+ function listenOn(port, bind, next) {
700
730
  return new Promise((resolve, reject) => {
701
- const created = createServer(onRequest);
731
+ const created = createServer(next.onRequest);
732
+ created.on("upgrade", next.onUpgrade);
702
733
  const onError = (err) => {
703
734
  created.off("listening", onListening);
735
+ created.close();
704
736
  reject(err);
705
737
  };
706
738
  const onListening = () => {
@@ -709,8 +741,12 @@ function listenHttp(port, host, onRequest) {
709
741
  };
710
742
  created.once("error", onError);
711
743
  created.once("listening", onListening);
712
- created.listen(port, host);
744
+ created.listen({
745
+ port,
746
+ host: bind.host,
747
+ ipv6Only: bind.ipv6Only
748
+ });
713
749
  });
714
750
  }
715
751
  //#endregion
716
- export { evaluateExistingCert as S, collectCertIdentity as _, readLanHttpState as a, MAX_LEAF_VALIDITY_DAYS as b, readTlsAccessStatus as c, writeTlsMode as d, validateUploadedTls as f, CA_COMMON_NAME as g, reissueTlsLeaf as h, closeLanHttp as i, readTlsMode as l, loadTlsCert as m, applyLanHttp as n, registerLanHttpHandler as o, ensureTlsCert as p, bindPendingLanHttp as r, readExtraSans as s, DEFAULT_LAN_HTTP_PORT as t, writeExtraSans as u, CA_VALIDITY_DAYS as v, SERVER_AUTH_OID as x, LEAF_RENEWAL_WINDOW_DAYS as y };
752
+ export { evaluateExistingCert as C, SERVER_AUTH_OID as S, CA_COMMON_NAME as _, closeLanHttp as a, LEAF_RENEWAL_WINDOW_DAYS as b, readExtraSans as c, writeExtraSans as d, writeTlsMode as f, reissueTlsLeaf as g, loadTlsCert as h, bindPendingLanHttp as i, readTlsAccessStatus as l, ensureTlsCert as m, allFamiliesListenHost as n, readLanHttpState as o, validateUploadedTls as p, applyLanHttp as r, registerLanHttpHandler as s, DEFAULT_LAN_HTTP_PORT as t, readTlsMode as u, collectCertIdentity as v, MAX_LEAF_VALIDITY_DAYS as x, CA_VALIDITY_DAYS as y };
@@ -1,4 +1,4 @@
1
- import { kt as asJsonObject } from "./dist-BpzbLPel.mjs";
1
+ import { kt as asJsonObject } from "./dist-DCTpBXm4.mjs";
2
2
  //#region src/builtins/sqlite-storage/retired-settings-keys.ts
3
3
  /**
4
4
  * Is THIS node the one whose settings store is the cluster's authority?
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-Cri60Jd0.js");
1
+ const require_dist = require("./dist-C2_1HCpW.js");
2
2
  //#region src/builtins/sqlite-storage/retired-settings-keys.ts
3
3
  /**
4
4
  * Is THIS node the one whose settings store is the cluster's authority?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.116",
3
+ "version": "1.2.118",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",