@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,4 +1,4 @@
1
- import { IncomingMessage, ServerResponse } from 'node:http';
1
+ import { IncomingMessage, ServerResponse, OutgoingHttpHeaders } from 'node:http';
2
2
  export interface ReverseProxyOptions {
3
3
  /** Addon listener base, e.g. `http://127.0.0.1:54123`. */
4
4
  readonly baseUrl: string;
@@ -14,6 +14,16 @@ export interface ReverseProxyOptions {
14
14
  */
15
15
  readonly replayBody?: Buffer;
16
16
  }
17
+ /**
18
+ * The upstream's response headers, minus the CORS policy, which belongs to the
19
+ * EDGE (D707). The hub stamps its allowlist verdict on `clientRes` with
20
+ * `setHeader` before hijacking, and Node merges those into `writeHead` — so an
21
+ * upstream `access-control-*` header would OVERRIDE the hub's answer: the
22
+ * authenticated file-server's `*` reached a refused origin this way. `Vary` is
23
+ * merged rather than replaced, so the edge's `Origin` survives an upstream
24
+ * `Accept-Encoding`.
25
+ */
26
+ export declare function edgeOwnedResponseHeaders(upRes: IncomingMessage, clientRes: ServerResponse): OutgoingHttpHeaders;
17
27
  /** Reverse-proxy one request to an addon data-plane listener. Fire-and-forget:
18
28
  * the caller must `reply.hijack()` (or otherwise stop the framework from also
19
29
  * responding) before calling this, since we drive `clientRes` directly. */
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-CXVXFdJX.js");
3
+ const require_dist = require("./dist-DePB7uwU.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_builtins_calendars_calendars_addon = require("./builtins/calendars/calendars.addon.js");
@@ -31,7 +31,7 @@ require("./builtins/system-config/index.js");
31
31
  const require_builtins_winston_logging_index = require("./builtins/winston-logging/index.js");
32
32
  const require_event_loop_stall_monitor = require("./event-loop-stall-monitor-ey4mbofz.js");
33
33
  const require_tls$1 = require("./tls-ue_Xefmv.js");
34
- const require_child_cap_dispatch = require("./child-cap-dispatch-CvYlCq60.js");
34
+ const require_child_cap_dispatch = require("./child-cap-dispatch-CRqYKHAb.js");
35
35
  const require_resource_monitor = require("./resource-monitor-BgWGRxN5.js");
36
36
  const require_custom_action_registry = require("./custom-action-registry-acBY3mHA.js");
37
37
  let zod = require("zod");
@@ -410,6 +410,38 @@ function canServeDataPlane(state) {
410
410
  * headers + body), so `Content-Range`, backpressure and client-disconnect are all
411
411
  * native. No bytes are buffered; nothing crosses the cap channel.
412
412
  */
413
+ /**
414
+ * The upstream's response headers, minus the CORS policy, which belongs to the
415
+ * EDGE (D707). The hub stamps its allowlist verdict on `clientRes` with
416
+ * `setHeader` before hijacking, and Node merges those into `writeHead` — so an
417
+ * upstream `access-control-*` header would OVERRIDE the hub's answer: the
418
+ * authenticated file-server's `*` reached a refused origin this way. `Vary` is
419
+ * merged rather than replaced, so the edge's `Origin` survives an upstream
420
+ * `Accept-Encoding`.
421
+ */
422
+ function edgeOwnedResponseHeaders(upRes, clientRes) {
423
+ const out = {};
424
+ for (const [name, value] of Object.entries(upRes.headers)) {
425
+ if (value === void 0) continue;
426
+ const lower = name.toLowerCase();
427
+ if (lower.startsWith("access-control-")) continue;
428
+ out[lower] = value;
429
+ }
430
+ const edgeVary = clientRes.getHeader("vary");
431
+ const upVary = out["vary"];
432
+ if (typeof edgeVary === "string" && edgeVary.length > 0 && upVary !== void 0) {
433
+ const tokens = /* @__PURE__ */ new Set();
434
+ const merged = [];
435
+ for (const part of [edgeVary, String(upVary)].join(",").split(",")) {
436
+ const token = part.trim();
437
+ if (token.length === 0 || tokens.has(token.toLowerCase())) continue;
438
+ tokens.add(token.toLowerCase());
439
+ merged.push(token);
440
+ }
441
+ out["vary"] = merged.join(", ");
442
+ }
443
+ return out;
444
+ }
413
445
  /** Reverse-proxy one request to an addon data-plane listener. Fire-and-forget:
414
446
  * the caller must `reply.hijack()` (or otherwise stop the framework from also
415
447
  * responding) before calling this, since we drive `clientRes` directly. */
@@ -430,17 +462,11 @@ function proxyToUpstream(opts) {
430
462
  path: upstreamPath,
431
463
  headers
432
464
  }, (upRes) => {
433
- clientRes.writeHead(upRes.statusCode ?? 502, {
434
- "access-control-allow-origin": "*",
435
- ...upRes.headers
436
- });
465
+ clientRes.writeHead(upRes.statusCode ?? 502, edgeOwnedResponseHeaders(upRes, clientRes));
437
466
  upRes.pipe(clientRes);
438
467
  });
439
468
  upstream.on("error", (err) => {
440
- if (!clientRes.headersSent) clientRes.writeHead(502, {
441
- "content-type": "application/json",
442
- "access-control-allow-origin": "*"
443
- });
469
+ if (!clientRes.headersSent) clientRes.writeHead(502, { "content-type": "application/json" });
444
470
  clientRes.end(JSON.stringify({
445
471
  error: "data-plane upstream error",
446
472
  detail: String(err)
@@ -7746,10 +7772,26 @@ function createDoorSettingsView(addonId, door, sections) {
7746
7772
  //#region src/kernel/config-schema.ts
7747
7773
  /** Default data directory — used when CAMSTACK_DATA env var is not set */
7748
7774
  var DEFAULT_DATA_PATH = "camstack-data";
7775
+ /**
7776
+ * A list of browser origins from config.yaml (a YAML list) or from the
7777
+ * `CAMSTACK_CORS_ORIGINS` env var (one comma-separated string — env carries
7778
+ * only strings). Validation of each entry is the CORS policy's job
7779
+ * (`server/backend/src/api/cors/cors-policy.ts`), which logs what it rejects;
7780
+ * the schema only fixes the SHAPE so a typo cannot stop the hub from booting.
7781
+ */
7782
+ var originListSchema = zod.z.preprocess((value) => typeof value === "string" ? value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0) : value, zod.z.array(zod.z.string()));
7749
7783
  var serverSchema = zod.z.object({
7750
7784
  port: zod.z.number().default(4443),
7751
7785
  host: zod.z.string().default("0.0.0.0"),
7752
- dataPath: zod.z.string().default(DEFAULT_DATA_PATH)
7786
+ dataPath: zod.z.string().default(DEFAULT_DATA_PATH),
7787
+ /**
7788
+ * EXTRA browser origins allowed to call this hub cross-origin (D707), on
7789
+ * top of the built-ins: the hub's own origin, the hosted viewer PWA and the
7790
+ * native app's opaque `null` origin. Bootstrap-owned on purpose — widening
7791
+ * who may read hub responses in a browser is a security decision, and the
7792
+ * policy is live from the first request, before the settings store exists.
7793
+ */
7794
+ corsOrigins: originListSchema.default([])
7753
7795
  });
7754
7796
  var authSchema = zod.z.object({
7755
7797
  jwtSecret: zod.z.string().nullable().default(null),
@@ -10214,7 +10256,8 @@ var ENV_VAR_MAP = {
10214
10256
  CAMSTACK_DATA: "server.dataPath",
10215
10257
  CAMSTACK_JWT_SECRET: "auth.jwtSecret",
10216
10258
  CAMSTACK_ADMIN_USER: "auth.adminUsername",
10217
- CAMSTACK_ADMIN_PASS: "auth.adminPassword"
10259
+ CAMSTACK_ADMIN_PASS: "auth.adminPassword",
10260
+ CAMSTACK_CORS_ORIGINS: "server.corsOrigins"
10218
10261
  };
10219
10262
  /** config.yaml, env overrides applied, parsed. */
10220
10263
  function loadBootstrapConfig(configPath) {
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 { $n as ReadinessRegistry, Bt as lifecycleJobSchema, D as METHOD_ACCESS_MAP, Dt as extractNestedAddonId, Ft as isObjectInput, Gt as looseSchema, It as isVoidInput, Jn as errMsg$1, Lt as kebabToCamel, M as RUNTIME_DEFAULTS, Mt as isArrayOutputSchema, Nt as isCollectionArrayMethod, Qn as DEVICE_STATUS_METHOD, U as addonSettingsCapability, Wt as logLevelAtMost, Xn as DATAPLANE_SECRET_HEADER$1, Zn as DEVICE_SETTINGS_CONTRIBUTION_METHODS, _r as scopeKey, an as procedureAuthKey, ar as createEvent, br as EventCategory$1, cr as expandCapMethods, en as objectInputDeclaresAddonId, er as ReadinessTimeoutError, gn as scopesAllowDeviceCap, gr as resolveCapMount, hn as scopesAllowAddon, hr as readinessKey, ir as asString$1, mr as parseJsonUnknown, nr as asJsonObject$1, or as emitDownForOwnedCaps, pn as resolveMethodAuth, pr as parseJsonObject, rr as asNumber, t as ALL_CAPABILITY_DEFINITIONS, tn as objectInputDeclaresRequiredDeviceId, w as LOG_LEVEL_RANK } from "./dist-Cm556q2j.mjs";
2
+ import { $n as DEVICE_SETTINGS_CONTRIBUTION_METHODS, Gt as logLevelAtMost, It as isObjectInput, Kt as looseSchema, Lt as isVoidInput, N as RUNTIME_DEFAULTS, Nt as isArrayOutputSchema, O as METHOD_ACCESS_MAP, Ot as extractNestedAddonId, Pt as isCollectionArrayMethod, Qn as DATAPLANE_SECRET_HEADER$1, Rt as kebabToCamel, Sr as EventCategory$1, T as LOG_LEVEL_RANK, Vt as lifecycleJobSchema, W as addonSettingsCapability, Xn as errMsg$1, _n as scopesAllowAddon, _r as readinessKey, ar as asNumber, cr as emitDownForOwnedCaps, er as DEVICE_STATUS_METHOD, gr as parseJsonUnknown, hn as resolveMethodAuth, hr as parseJsonObject, ir as asJsonObject$1, nn as objectInputDeclaresRequiredDeviceId, nr as ReadinessTimeoutError, or as asString$1, sn as procedureAuthKey, sr as createEvent, t as ALL_CAPABILITY_DEFINITIONS, tn as objectInputDeclaresAddonId, tr as ReadinessRegistry, ur as expandCapMethods, vn as scopesAllowDeviceCap, vr as resolveCapMount, yr as scopeKey } from "./dist-DVyXxn41.mjs";
3
3
  import { AlertCenterAddon } from "./builtins/alerts/alerts.addon.mjs";
4
4
  import "./builtins/alerts/index.mjs";
5
5
  import { CalendarsAddon } from "./builtins/calendars/calendars.addon.mjs";
@@ -30,7 +30,7 @@ import "./builtins/system-config/index.mjs";
30
30
  import { WinstonDestination, WinstonLoggingAddon } from "./builtins/winston-logging/index.mjs";
31
31
  import { _ as ensureModel, a as createFileDataPlaneHandler, c as parseRangeHeader, d as ModelDownloadService, g as downloadModel, h as downloadFile, i as startEventLoopStallMonitor, l as parseTokenizedUrl, m as deleteModelFromDisk, n as STALL_TICK_MS, o as contentTypeFor, p as collectModelFiles, r as attributeStall, s as createAuthenticatedFileServer, t as STALL_REPORT_MS, u as resolveFilePath, v as fetchJson, x as isModelDownloaded, y as getModelFilePath } from "./event-loop-stall-monitor-EXjzIxDz.mjs";
32
32
  import { C as registerLanHttpHandler, S as readLanHttpState, _ as DEFAULT_LAN_HTTP_PORT, a as writeTlsMode, b as bindPendingLanHttp, c as loadTlsCert, d as collectCertIdentity, f as CA_VALIDITY_DAYS, g as evaluateExistingCert, h as SERVER_AUTH_OID, i as writeExtraSans, l as reissueTlsLeaf, m as MAX_LEAF_VALIDITY_DAYS, n as readTlsAccessStatus, o as validateUploadedTls, p as LEAF_RENEWAL_WINDOW_DAYS, r as readTlsMode, s as ensureTlsCert, t as readExtraSans, u as CA_COMMON_NAME, v as allFamiliesListenHost, x as closeLanHttp, y as applyLanHttp } from "./tls-DTlVWwAI.mjs";
33
- import { $ as CapRouteError, $n as CAP_ACTION_UNLABELLED, $t as RUNNER_HEAP_WATCH_INTERVAL_MS, A as resolveHwAccel, An as OUTBOUND_QUEUE_COOLDOWN_MS, At as serializeTypedArrays, B as udsChildLogToWorkerEntry, Bn as SOCKET_QUEUE_TOP_N, Bt as createAddonPeerBytesFacility, C as getBrokerEventBus, Cn as DECISIVE_HEAP_SPACES, Ct as NATIVE_PROVIDER_SERVICE_INFIX, D as subscribePassthrough, Dn as heapSpaceField, Dt as capServiceName, E as setNodeEventInterest, En as formatHeapSpaces, Et as capBareAction, F as ipcParentLink, Fn as MESH_QUEUE_TOP_N, Ft as installManifestNativeDeps, G as UDS_NO_ROUTE_PREFIX, Gn as readSocketQueues, Gt as HEAP_RECLAIM_TRIGGER_MB, H as createUdsLoggerWithControl, Hn as createSocketPlaneReader, Ht as createAddonDataPlaneFacility, I as localProviderLink, In as createMeshQueueReader, It as resolveAddonClass, J as answerClaimedGetStatus, Jn as recordSocketFrame, Jt as HUB_MAIN_HEAP_WATCH_LABEL, K as afterWorkerOnlineAnnounce, Kn as EMPTY_SOCKET_DIRECTION, Kt as HEAP_WATCH_INTERVAL_MS, L as createParentUnownedCallHandler, Ln as formatMeshQueue, Lt as buildNpmChildEnv, M as brokerTransportLink, Mn as OUTBOUND_QUEUE_THRESHOLD_BYTES, Mt as CapabilityHandle, N as buildLinkChain, Nn as createOutboundQueueGate, Nt as CapabilityUnavailableError, O as AddonDepsManager, On as readHeapSpaces, Ot as parseCapAction, P as deviceCapResolverLink, Pn as formatOutboundQueueVerdict, Pt as copyBundledNativeModules, Q as CapRouteResolver, Qn as CAP_ACTION_OVERFLOW_LABEL, Qt as RSS_BUDGET_RELEASE_RATIO, R as createUdsEventBridge, Rn as EMPTY_SOCKET_PLANE_BASELINE, Rt as resolveNpmInvocation, S as clusterEventTopic, Sn as isArrayBufferCensusReport, St as validateProviderRegistrations, T as registerEventBusService, Tn as emitHeapDiagnosticReport, Tt as capActionSuffix, U as LocalChildClient, Un as diffSocketPlane, Ut as HEAP_RECLAIM_MIN_INTERVAL_MS, V as createUdsLogger, Vn as createSocketPlaneMeter, Vt as hostNodeIdOf, W as LocalChildRegistry, Wn as formatSocketPlane, Wt as HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS, X as AGENT_CAP_FWD_ACTION, Xn as socketDirectionBytes, Xt as HUB_RSS_BUDGET_ENV, Y as deviceOfGetStatus, Yn as sampleSocketDirection, Yt as HUB_MAIN_RSS_BUDGET_MB, Z as AGENT_CAP_FWD_SERVICE, Zn as socketDirectionMessages, Zt as RSS_BUDGET_REANNOUNCE_MIN_MS, _ as getWorkerDeviceRegistry, _n as ARRAY_BUFFER_CENSUS_THRESHOLD_MB, a as reapProcessGroup, an as createV8Reclaimer, ar as EVENT_PLANE_TOP_N, at as __resetCapUsageRegistryForTests, b as setHubConnected, bn as createInspectorArrayBufferCensus, c as runnerOwnsProcessGroup, cn as nextRssBudgetState, cr as diffEventPlane, ct as UdsLocalTransportClient, d as summarizeMembers, dn as shouldReclaim, dt as PeerAnsweredError, en as RUNNER_RSS_BUDGET_ENV, er as EMPTY_CAP_ACTION_READING, et as classifyCapRoute, f as installManifestSystemDeps, fn as startHeapWatch, ft as localEndpointPath, g as createUdsAddonContext, gn as ARRAY_BUFFER_CENSUS_SUSTAIN_MS, gt as createBrokerDeviceManagerApi, h as createAddonContext, hn as ARRAY_BUFFER_CENSUS_COOLDOWN_MS, ht as buildNativeCapProxy, in as createLoopDelayMeter, ir as diffCapActionCensus, it as PARENT_ROUTED_PROVIDER_ADDON_ID, j as brokerCallForCap, jn as OUTBOUND_QUEUE_SUSTAIN_MS, jt as DeviceRegistry, k as createKernelHwAccel, kn as selectReportedSpaces, kt as deserializeTypedArrays, l as signalAllRunnerGroups, ln as parseRssBudgetMb, lr as formatEventPlane, lt as UdsLocalTransportServer, m as adaptBrokerToCluster, mn as strandedMb, mt as encodeFrame, nn as buildHeapSample, nr as capActionLabel, nt as readMoleculerFanoutMode, o as registerRunnerGroup, on as describeRss, or as createEventPlaneMeter, ot as getCapUsageRegistry, p as installManifestPythonDeps, pn as startRunnerHeapWatch, pt as FrameDecoder, q as GET_STATUS_METHOD, qn as createSocketDirectionCounters, qt as HEAP_WATCH_WARN_RATIO, r as defaultProcessGroupOps, rn as createDeferredHeapWatchSink, rr as createCapActionCensus, rt as CapUsageRegistry, s as releaseRunnerGroup, sn as hubMainRssBudget, sr as createEventPlaneReader, st as createLocalTransport, t as CAP_METHOD_NOT_IMPLEMENTED, tn as ZERO_LOOP_DELAY, tr as MAX_CAP_ACTIONS_PER_PEER, tt as callWithServiceDiscovery, un as reclaimIntervalMs, ut as SocketChannel, v as getOrInitReadinessRegistry, vn as ARRAY_BUFFER_RELEASE_MIN_DROP_RATIO, w as getMoleculerEventStats, wn as HEAP_SPACE_REPORT_MIN_MB, wt as capActionName, x as EVENT_TOPIC_PREFIX, xn as formatArrayBufferCensus, xt as createAddonService, y as getOrInitReadinessRegistryForClient, yn as createArrayBufferCensusGate, yt as mountNativeCapService, z as createUdsEventBus, zn as SOCKET_PLANE_TOP_N, zt as runNpm } from "./child-cap-dispatch-C6IpRb4P.mjs";
33
+ import { $ as CapRouteError, $n as CAP_ACTION_UNLABELLED, $t as RUNNER_HEAP_WATCH_INTERVAL_MS, A as resolveHwAccel, An as OUTBOUND_QUEUE_COOLDOWN_MS, At as serializeTypedArrays, B as udsChildLogToWorkerEntry, Bn as SOCKET_QUEUE_TOP_N, Bt as createAddonPeerBytesFacility, C as getBrokerEventBus, Cn as DECISIVE_HEAP_SPACES, Ct as NATIVE_PROVIDER_SERVICE_INFIX, D as subscribePassthrough, Dn as heapSpaceField, Dt as capServiceName, E as setNodeEventInterest, En as formatHeapSpaces, Et as capBareAction, F as ipcParentLink, Fn as MESH_QUEUE_TOP_N, Ft as installManifestNativeDeps, G as UDS_NO_ROUTE_PREFIX, Gn as readSocketQueues, Gt as HEAP_RECLAIM_TRIGGER_MB, H as createUdsLoggerWithControl, Hn as createSocketPlaneReader, Ht as createAddonDataPlaneFacility, I as localProviderLink, In as createMeshQueueReader, It as resolveAddonClass, J as answerClaimedGetStatus, Jn as recordSocketFrame, Jt as HUB_MAIN_HEAP_WATCH_LABEL, K as afterWorkerOnlineAnnounce, Kn as EMPTY_SOCKET_DIRECTION, Kt as HEAP_WATCH_INTERVAL_MS, L as createParentUnownedCallHandler, Ln as formatMeshQueue, Lt as buildNpmChildEnv, M as brokerTransportLink, Mn as OUTBOUND_QUEUE_THRESHOLD_BYTES, Mt as CapabilityHandle, N as buildLinkChain, Nn as createOutboundQueueGate, Nt as CapabilityUnavailableError, O as AddonDepsManager, On as readHeapSpaces, Ot as parseCapAction, P as deviceCapResolverLink, Pn as formatOutboundQueueVerdict, Pt as copyBundledNativeModules, Q as CapRouteResolver, Qn as CAP_ACTION_OVERFLOW_LABEL, Qt as RSS_BUDGET_RELEASE_RATIO, R as createUdsEventBridge, Rn as EMPTY_SOCKET_PLANE_BASELINE, Rt as resolveNpmInvocation, S as clusterEventTopic, Sn as isArrayBufferCensusReport, St as validateProviderRegistrations, T as registerEventBusService, Tn as emitHeapDiagnosticReport, Tt as capActionSuffix, U as LocalChildClient, Un as diffSocketPlane, Ut as HEAP_RECLAIM_MIN_INTERVAL_MS, V as createUdsLogger, Vn as createSocketPlaneMeter, Vt as hostNodeIdOf, W as LocalChildRegistry, Wn as formatSocketPlane, Wt as HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS, X as AGENT_CAP_FWD_ACTION, Xn as socketDirectionBytes, Xt as HUB_RSS_BUDGET_ENV, Y as deviceOfGetStatus, Yn as sampleSocketDirection, Yt as HUB_MAIN_RSS_BUDGET_MB, Z as AGENT_CAP_FWD_SERVICE, Zn as socketDirectionMessages, Zt as RSS_BUDGET_REANNOUNCE_MIN_MS, _ as getWorkerDeviceRegistry, _n as ARRAY_BUFFER_CENSUS_THRESHOLD_MB, a as reapProcessGroup, an as createV8Reclaimer, ar as EVENT_PLANE_TOP_N, at as __resetCapUsageRegistryForTests, b as setHubConnected, bn as createInspectorArrayBufferCensus, c as runnerOwnsProcessGroup, cn as nextRssBudgetState, cr as diffEventPlane, ct as UdsLocalTransportClient, d as summarizeMembers, dn as shouldReclaim, dt as PeerAnsweredError, en as RUNNER_RSS_BUDGET_ENV, er as EMPTY_CAP_ACTION_READING, et as classifyCapRoute, f as installManifestSystemDeps, fn as startHeapWatch, ft as localEndpointPath, g as createUdsAddonContext, gn as ARRAY_BUFFER_CENSUS_SUSTAIN_MS, gt as createBrokerDeviceManagerApi, h as createAddonContext, hn as ARRAY_BUFFER_CENSUS_COOLDOWN_MS, ht as buildNativeCapProxy, in as createLoopDelayMeter, ir as diffCapActionCensus, it as PARENT_ROUTED_PROVIDER_ADDON_ID, j as brokerCallForCap, jn as OUTBOUND_QUEUE_SUSTAIN_MS, jt as DeviceRegistry, k as createKernelHwAccel, kn as selectReportedSpaces, kt as deserializeTypedArrays, l as signalAllRunnerGroups, ln as parseRssBudgetMb, lr as formatEventPlane, lt as UdsLocalTransportServer, m as adaptBrokerToCluster, mn as strandedMb, mt as encodeFrame, nn as buildHeapSample, nr as capActionLabel, nt as readMoleculerFanoutMode, o as registerRunnerGroup, on as describeRss, or as createEventPlaneMeter, ot as getCapUsageRegistry, p as installManifestPythonDeps, pn as startRunnerHeapWatch, pt as FrameDecoder, q as GET_STATUS_METHOD, qn as createSocketDirectionCounters, qt as HEAP_WATCH_WARN_RATIO, r as defaultProcessGroupOps, rn as createDeferredHeapWatchSink, rr as createCapActionCensus, rt as CapUsageRegistry, s as releaseRunnerGroup, sn as hubMainRssBudget, sr as createEventPlaneReader, st as createLocalTransport, t as CAP_METHOD_NOT_IMPLEMENTED, tn as ZERO_LOOP_DELAY, tr as MAX_CAP_ACTIONS_PER_PEER, tt as callWithServiceDiscovery, un as reclaimIntervalMs, ut as SocketChannel, v as getOrInitReadinessRegistry, vn as ARRAY_BUFFER_RELEASE_MIN_DROP_RATIO, w as getMoleculerEventStats, wn as HEAP_SPACE_REPORT_MIN_MB, wt as capActionName, x as EVENT_TOPIC_PREFIX, xn as formatArrayBufferCensus, xt as createAddonService, y as getOrInitReadinessRegistryForClient, yn as createArrayBufferCensusGate, yt as mountNativeCapService, z as createUdsEventBus, zn as SOCKET_PLANE_TOP_N, zt as runNpm } from "./child-cap-dispatch-C1x1kNJK.mjs";
34
34
  import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-B2WZ8_q9.mjs";
35
35
  import { t as CustomActionRegistry } from "./custom-action-registry-B4Cf4O_X.mjs";
36
36
  import { z } from "zod";
@@ -403,6 +403,38 @@ function canServeDataPlane(state) {
403
403
  * headers + body), so `Content-Range`, backpressure and client-disconnect are all
404
404
  * native. No bytes are buffered; nothing crosses the cap channel.
405
405
  */
406
+ /**
407
+ * The upstream's response headers, minus the CORS policy, which belongs to the
408
+ * EDGE (D707). The hub stamps its allowlist verdict on `clientRes` with
409
+ * `setHeader` before hijacking, and Node merges those into `writeHead` — so an
410
+ * upstream `access-control-*` header would OVERRIDE the hub's answer: the
411
+ * authenticated file-server's `*` reached a refused origin this way. `Vary` is
412
+ * merged rather than replaced, so the edge's `Origin` survives an upstream
413
+ * `Accept-Encoding`.
414
+ */
415
+ function edgeOwnedResponseHeaders(upRes, clientRes) {
416
+ const out = {};
417
+ for (const [name, value] of Object.entries(upRes.headers)) {
418
+ if (value === void 0) continue;
419
+ const lower = name.toLowerCase();
420
+ if (lower.startsWith("access-control-")) continue;
421
+ out[lower] = value;
422
+ }
423
+ const edgeVary = clientRes.getHeader("vary");
424
+ const upVary = out["vary"];
425
+ if (typeof edgeVary === "string" && edgeVary.length > 0 && upVary !== void 0) {
426
+ const tokens = /* @__PURE__ */ new Set();
427
+ const merged = [];
428
+ for (const part of [edgeVary, String(upVary)].join(",").split(",")) {
429
+ const token = part.trim();
430
+ if (token.length === 0 || tokens.has(token.toLowerCase())) continue;
431
+ tokens.add(token.toLowerCase());
432
+ merged.push(token);
433
+ }
434
+ out["vary"] = merged.join(", ");
435
+ }
436
+ return out;
437
+ }
406
438
  /** Reverse-proxy one request to an addon data-plane listener. Fire-and-forget:
407
439
  * the caller must `reply.hijack()` (or otherwise stop the framework from also
408
440
  * responding) before calling this, since we drive `clientRes` directly. */
@@ -423,17 +455,11 @@ function proxyToUpstream(opts) {
423
455
  path: upstreamPath,
424
456
  headers
425
457
  }, (upRes) => {
426
- clientRes.writeHead(upRes.statusCode ?? 502, {
427
- "access-control-allow-origin": "*",
428
- ...upRes.headers
429
- });
458
+ clientRes.writeHead(upRes.statusCode ?? 502, edgeOwnedResponseHeaders(upRes, clientRes));
430
459
  upRes.pipe(clientRes);
431
460
  });
432
461
  upstream.on("error", (err) => {
433
- if (!clientRes.headersSent) clientRes.writeHead(502, {
434
- "content-type": "application/json",
435
- "access-control-allow-origin": "*"
436
- });
462
+ if (!clientRes.headersSent) clientRes.writeHead(502, { "content-type": "application/json" });
437
463
  clientRes.end(JSON.stringify({
438
464
  error: "data-plane upstream error",
439
465
  detail: String(err)
@@ -7739,10 +7765,26 @@ function createDoorSettingsView(addonId, door, sections) {
7739
7765
  //#region src/kernel/config-schema.ts
7740
7766
  /** Default data directory — used when CAMSTACK_DATA env var is not set */
7741
7767
  var DEFAULT_DATA_PATH = "camstack-data";
7768
+ /**
7769
+ * A list of browser origins from config.yaml (a YAML list) or from the
7770
+ * `CAMSTACK_CORS_ORIGINS` env var (one comma-separated string — env carries
7771
+ * only strings). Validation of each entry is the CORS policy's job
7772
+ * (`server/backend/src/api/cors/cors-policy.ts`), which logs what it rejects;
7773
+ * the schema only fixes the SHAPE so a typo cannot stop the hub from booting.
7774
+ */
7775
+ var originListSchema = z.preprocess((value) => typeof value === "string" ? value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0) : value, z.array(z.string()));
7742
7776
  var serverSchema = z.object({
7743
7777
  port: z.number().default(4443),
7744
7778
  host: z.string().default("0.0.0.0"),
7745
- dataPath: z.string().default(DEFAULT_DATA_PATH)
7779
+ dataPath: z.string().default(DEFAULT_DATA_PATH),
7780
+ /**
7781
+ * EXTRA browser origins allowed to call this hub cross-origin (D707), on
7782
+ * top of the built-ins: the hub's own origin, the hosted viewer PWA and the
7783
+ * native app's opaque `null` origin. Bootstrap-owned on purpose — widening
7784
+ * who may read hub responses in a browser is a security decision, and the
7785
+ * policy is live from the first request, before the settings store exists.
7786
+ */
7787
+ corsOrigins: originListSchema.default([])
7746
7788
  });
7747
7789
  var authSchema = z.object({
7748
7790
  jwtSecret: z.string().nullable().default(null),
@@ -10207,7 +10249,8 @@ var ENV_VAR_MAP = {
10207
10249
  CAMSTACK_DATA: "server.dataPath",
10208
10250
  CAMSTACK_JWT_SECRET: "auth.jwtSecret",
10209
10251
  CAMSTACK_ADMIN_USER: "auth.adminUsername",
10210
- CAMSTACK_ADMIN_PASS: "auth.adminPassword"
10252
+ CAMSTACK_ADMIN_PASS: "auth.adminPassword",
10253
+ CAMSTACK_CORS_ORIGINS: "server.corsOrigins"
10211
10254
  };
10212
10255
  /** config.yaml, env overrides applied, parsed. */
10213
10256
  function loadBootstrapConfig(configPath) {
@@ -12,6 +12,7 @@ export declare const bootstrapSchema: z.ZodObject<{
12
12
  port: z.ZodDefault<z.ZodNumber>;
13
13
  host: z.ZodDefault<z.ZodString>;
14
14
  dataPath: z.ZodDefault<z.ZodString>;
15
+ corsOrigins: z.ZodDefault<z.ZodPreprocess<z.ZodArray<z.ZodString>>>;
15
16
  }, z.core.$strip>>;
16
17
  auth: z.ZodDefault<z.ZodObject<{
17
18
  jwtSecret: z.ZodDefault<z.ZodNullable<z.ZodString>>;
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-CXVXFdJX.js");
1
+ const require_dist = require("./dist-DePB7uwU.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?
@@ -1,4 +1,4 @@
1
- import { nr as asJsonObject } from "./dist-Cm556q2j.mjs";
1
+ import { ir as asJsonObject } from "./dist-DVyXxn41.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?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.353",
3
+ "version": "1.2.354",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",