@camstack/server 1.2.593 → 1.2.594

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 (256) hide show
  1. package/dist/addon-root-inventory.js +11 -50
  2. package/dist/agent/addon-scan.js +6 -44
  3. package/dist/agent/agent-addon-runtime.js +3 -8
  4. package/dist/agent/agent-addon-updates.js +12 -52
  5. package/dist/agent/agent-cap-dispatch-service.js +3 -5
  6. package/dist/agent/agent-config.js +7 -42
  7. package/dist/agent/agent-deploy-swap.js +5 -41
  8. package/dist/agent/agent-group-runner.js +8 -47
  9. package/dist/agent/agent-http-auth.js +10 -22
  10. package/dist/agent/agent-http.js +69 -115
  11. package/dist/agent/agent-hub-addon-update.js +10 -16
  12. package/dist/agent/agent-hub-registration.js +4 -7
  13. package/dist/agent/agent-infra-capabilities.js +5 -9
  14. package/dist/agent/agent-json-file.js +5 -42
  15. package/dist/agent/agent-mesh-gate.js +5 -8
  16. package/dist/agent/agent-node-certificates.js +25 -28
  17. package/dist/agent/agent-pairing-local.js +10 -47
  18. package/dist/agent/agent-pairing-routes.js +16 -20
  19. package/dist/agent/agent-pairing-store.js +18 -58
  20. package/dist/agent/agent-reconnect.js +1 -4
  21. package/dist/agent/agent-service.js +42 -78
  22. package/dist/agent/agent-sniffing-listener.js +11 -48
  23. package/dist/agent/agent-undeploy.js +5 -41
  24. package/dist/agent/agent-update-routes.js +14 -19
  25. package/dist/agent/agent-update-service.js +38 -80
  26. package/dist/agent/apply-model-distribution.js +1 -4
  27. package/dist/agent/apply-stage-dev-uploads.js +6 -9
  28. package/dist/agent/derive-hub-url.js +3 -8
  29. package/dist/agent/fetch-bundle-from-hub.js +6 -9
  30. package/dist/agent/hubs-found.js +6 -43
  31. package/dist/agent/infra-boot-guard.js +1 -4
  32. package/dist/agent/infra-boot-plan.js +2 -6
  33. package/dist/agent/main.js +158 -186
  34. package/dist/agent/register-agent-cap-dispatch.js +3 -6
  35. package/dist/agent/serial-queue.js +2 -7
  36. package/dist/agent-status-page.js +1 -4
  37. package/dist/api/addon-upload.js +22 -61
  38. package/dist/api/agent-addon-delivery.js +6 -11
  39. package/dist/api/auth-whoami.js +1 -4
  40. package/dist/api/backup-download-pump.js +5 -9
  41. package/dist/api/backup-download.js +7 -10
  42. package/dist/api/core/addon-settings.router.js +16 -19
  43. package/dist/api/core/agent-pairing.router.js +76 -79
  44. package/dist/api/core/agents.router.js +21 -24
  45. package/dist/api/core/auth-admin-tokens.procedures.js +48 -52
  46. package/dist/api/core/auth-device-cert.procedures.js +62 -67
  47. package/dist/api/core/auth-limits.js +16 -25
  48. package/dist/api/core/auth-reauth.procedures.js +32 -37
  49. package/dist/api/core/auth-revoke-credentials.procedures.js +22 -26
  50. package/dist/api/core/auth-sessions.procedures.js +52 -56
  51. package/dist/api/core/auth.router.js +300 -304
  52. package/dist/api/core/cap-providers.js +74 -121
  53. package/dist/api/core/capabilities.router.js +34 -37
  54. package/dist/api/core/capability-preference-writes.js +10 -17
  55. package/dist/api/core/certificates.router.js +106 -109
  56. package/dist/api/core/cluster-nodes.router.js +15 -18
  57. package/dist/api/core/collection-preference.js +2 -6
  58. package/dist/api/core/event-bus-proxy.router.js +34 -37
  59. package/dist/api/core/failure-contributions.js +4 -8
  60. package/dist/api/core/hwaccel.router.js +17 -20
  61. package/dist/api/core/integration-secrets.js +8 -12
  62. package/dist/api/core/lifecycle-job-runner.js +13 -49
  63. package/dist/api/core/live-events.router.js +29 -32
  64. package/dist/api/core/load-contributions.js +4 -8
  65. package/dist/api/core/logging-settings.js +30 -43
  66. package/dist/api/core/logs.router.js +40 -43
  67. package/dist/api/core/notifications.router.js +15 -18
  68. package/dist/api/core/public-event-filter.js +4 -8
  69. package/dist/api/core/repl.router.js +18 -21
  70. package/dist/api/core/request-census-settings.js +11 -16
  71. package/dist/api/core/server-management.provider.js +1 -4
  72. package/dist/api/core/server-name.js +9 -17
  73. package/dist/api/core/site-location.js +16 -24
  74. package/dist/api/core/stream-probe.router.js +21 -24
  75. package/dist/api/core/system-events.router.js +23 -26
  76. package/dist/api/cors/cors-policy.js +20 -29
  77. package/dist/api/cors/register-cors-policy.js +9 -14
  78. package/dist/api/deploy-stage-registry.js +6 -10
  79. package/dist/api/dev-uploads-bundle.js +12 -50
  80. package/dist/api/health/adaptive-probe.routes.js +9 -13
  81. package/dist/api/health/health.routes.js +8 -13
  82. package/dist/api/hub-cluster-url.js +3 -9
  83. package/dist/api/model-distributor.js +12 -50
  84. package/dist/api/oauth2/consent-page.js +10 -13
  85. package/dist/api/oauth2/oauth2-routes.js +17 -25
  86. package/dist/api/oauth2/private-host.js +1 -4
  87. package/dist/api/server-upload-propagate.js +15 -51
  88. package/dist/api/server-upload.js +13 -50
  89. package/dist/api/sse-no-compression.js +1 -4
  90. package/dist/api/static/frame-policy.js +4 -9
  91. package/dist/api/static/precompressed-asset.js +15 -57
  92. package/dist/api/static/spa-mount.js +8 -47
  93. package/dist/api/static/spa-static.js +5 -12
  94. package/dist/api/tarball-manifest.js +7 -44
  95. package/dist/api/trpc/cap-mount-helpers.js +7 -12
  96. package/dist/api/trpc/cap-route-error-formatter.js +10 -13
  97. package/dist/api/trpc/cap-router-runtime.js +40 -51
  98. package/dist/api/trpc/client-ip.js +9 -20
  99. package/dist/api/trpc/core-cap-bridge.js +32 -42
  100. package/dist/api/trpc/device-collection-dispatch.js +23 -27
  101. package/dist/api/trpc/device-config-secret-redaction.js +24 -40
  102. package/dist/api/trpc/generated-cap-mounts.js +218 -222
  103. package/dist/api/trpc/generated-cap-routers.js +4688 -4850
  104. package/dist/api/trpc/http-request-census-hook.js +8 -11
  105. package/dist/api/trpc/http-request-census.js +34 -41
  106. package/dist/api/trpc/http-request-census.singleton.js +4 -8
  107. package/dist/api/trpc/localized-schema-paths.js +1 -4
  108. package/dist/api/trpc/principal-visibility.js +14 -22
  109. package/dist/api/trpc/remote-addon-update-grant.js +1 -4
  110. package/dist/api/trpc/scope-access.js +10 -15
  111. package/dist/api/trpc/server-provided-caps.js +3 -7
  112. package/dist/api/trpc/share-view-access.js +6 -14
  113. package/dist/api/trpc/trpc-error-device-tags.js +3 -6
  114. package/dist/api/trpc/trpc-error-principal.js +2 -6
  115. package/dist/api/trpc/trpc.context.js +20 -25
  116. package/dist/api/trpc/trpc.middleware.js +38 -46
  117. package/dist/api/trpc/trpc.router.js +58 -99
  118. package/dist/api/trpc/user-error.js +5 -8
  119. package/dist/api/trpc/ws-request-census.js +17 -24
  120. package/dist/api/trpc/ws-slow-consumer-guard.js +11 -16
  121. package/dist/api/upload-auth.js +5 -9
  122. package/dist/auth/addon-route-jwt-gate.js +4 -7
  123. package/dist/auth/addon-route-share-gate.js +7 -12
  124. package/dist/auth/app-confirm-page.js +17 -22
  125. package/dist/auth/app-confirm-routes.js +26 -31
  126. package/dist/auth/app-confirmations.js +7 -44
  127. package/dist/auth/app-page-shell.js +17 -30
  128. package/dist/auth/app-page-strings.js +11 -17
  129. package/dist/auth/app-passkey-page.js +16 -21
  130. package/dist/auth/app-passkey-routes.js +37 -41
  131. package/dist/auth/app-refused-route.js +13 -18
  132. package/dist/auth/auth-network-policy.js +11 -15
  133. package/dist/auth/auth-provider-gate.js +4 -9
  134. package/dist/auth/auth-rate-limit.js +3 -7
  135. package/dist/auth/client-address.js +6 -9
  136. package/dist/auth/device-enroll-proofs.js +6 -43
  137. package/dist/auth/external-link-intents.js +3 -7
  138. package/dist/auth/hub-sessions.js +6 -12
  139. package/dist/auth/native-link-completions.js +7 -11
  140. package/dist/auth/native-return.js +9 -13
  141. package/dist/auth/passkey-provider.js +26 -32
  142. package/dist/auth/second-factors.js +6 -10
  143. package/dist/auth/session-connections.js +6 -12
  144. package/dist/auth/session-cookie.js +12 -23
  145. package/dist/auth/session-lifetimes.js +8 -12
  146. package/dist/auth/session-mint.js +4 -11
  147. package/dist/auth/sso-finish-app.js +13 -16
  148. package/dist/auth/sso-finish-deps.js +21 -27
  149. package/dist/auth/sso-finish.js +28 -38
  150. package/dist/auth/sso-routes.js +22 -25
  151. package/dist/auth/used-bridge-ids.js +1 -5
  152. package/dist/boot/boot-config.js +16 -55
  153. package/dist/boot/init-sequence.js +1 -4
  154. package/dist/boot/integration-id-backfill.js +3 -8
  155. package/dist/boot/platform-keychain-key.js +5 -42
  156. package/dist/boot/post-boot.service.js +14 -18
  157. package/dist/boot/reconcile-lifecycle-jobs.js +3 -6
  158. package/dist/boot/retired-public-url-env.js +4 -8
  159. package/dist/bootstrap-packages.js +1 -4
  160. package/dist/closure-node-modules.js +2 -38
  161. package/dist/closure-patches/patch-reach.json +6 -2
  162. package/dist/core/addon/addon-call-gateway.js +1 -5
  163. package/dist/core/addon/addon-package.service.js +83 -123
  164. package/dist/core/addon/addon-process-view.js +2 -6
  165. package/dist/core/addon/addon-realign-plan.js +1 -4
  166. package/dist/core/addon/addon-registry.service.js +199 -185
  167. package/dist/core/addon/addon-row-manifest.js +1 -4
  168. package/dist/core/addon/addon-search.service.js +3 -7
  169. package/dist/core/addon/addon-settings-provider.js +1 -3
  170. package/dist/core/addon/addon-uninstall.js +4 -11
  171. package/dist/core/addon/addon.tokens.js +2 -5
  172. package/dist/core/addon/device-meta-mirror.js +8 -13
  173. package/dist/core/addon/forked-custom-actions.js +6 -11
  174. package/dist/core/addon/integration-visibility.js +3 -6
  175. package/dist/core/addon/materialize-route-path.js +1 -4
  176. package/dist/core/addon/package-dir-utils.js +8 -45
  177. package/dist/core/addon/prune-misplaced-addons.js +5 -43
  178. package/dist/core/addon/runner-convergence.js +1 -4
  179. package/dist/core/addon/runner-serialization.js +1 -4
  180. package/dist/core/addon/runner-spawn-fanout.js +3 -8
  181. package/dist/core/addon/settings-door-wiring.js +5 -8
  182. package/dist/core/addon/single-flight-refresh.js +1 -4
  183. package/dist/core/addon-bridge/addon-bridge.service.js +7 -44
  184. package/dist/core/addon-pages/addon-pages.service.js +3 -40
  185. package/dist/core/addon-widgets/addon-widgets.service.js +4 -42
  186. package/dist/core/agent/agent-addon-backfill.js +9 -17
  187. package/dist/core/agent/agent-delivery-ledger.js +3 -7
  188. package/dist/core/agent/agent-liveness-event.js +2 -6
  189. package/dist/core/agent/agent-pairing-http.js +41 -45
  190. package/dist/core/agent/agent-registry.service.js +53 -92
  191. package/dist/core/agent/cluster-node-history-mirror.js +3 -7
  192. package/dist/core/agent/cluster-node-history-store.js +113 -58
  193. package/dist/core/agent/hub-agent-pairing.js +1 -5
  194. package/dist/core/agent/node-certificates-client.js +3 -6
  195. package/dist/core/agent/node-directory.js +1 -4
  196. package/dist/core/app-links/well-known-app-links.js +2 -6
  197. package/dist/core/auth/auth.service.js +3 -8
  198. package/dist/core/auth/handoff-code.service.js +11 -49
  199. package/dist/core/auth/record-kinds.js +35 -0
  200. package/dist/core/auth/share-token.service.js +174 -122
  201. package/dist/core/capability/capability.service.js +1 -5
  202. package/dist/core/config/config.schema.js +1 -6
  203. package/dist/core/config/config.service.js +2 -6
  204. package/dist/core/events/event-bus.service.js +3 -7
  205. package/dist/core/feature/feature.service.js +2 -6
  206. package/dist/core/lifecycle/lifecycle-runner.singleton.js +5 -10
  207. package/dist/core/lifecycle/lifecycle-state-machine.js +1 -5
  208. package/dist/core/logging/log-ring-buffer.js +1 -5
  209. package/dist/core/logging/logging.service.js +5 -9
  210. package/dist/core/logging/scoped-logger.js +1 -5
  211. package/dist/core/moleculer/agent-readiness-pull.js +1 -4
  212. package/dist/core/moleculer/agent-registration-request.js +3 -7
  213. package/dist/core/moleculer/cap-call-fn.js +39 -5
  214. package/dist/core/moleculer/cap-route-authority.js +3 -8
  215. package/dist/core/moleculer/hub-mesh-guard.js +5 -9
  216. package/dist/core/moleculer/moleculer.service.js +108 -119
  217. package/dist/core/network/network-quality.service.js +2 -6
  218. package/dist/core/notification/notification-wrapper.service.js +3 -7
  219. package/dist/core/notification/toast-wrapper.service.js +3 -7
  220. package/dist/core/provider/provider.tokens.js +1 -4
  221. package/dist/core/repl/repl-engine.service.js +4 -8
  222. package/dist/core/runner-health/runner-boot-check.js +7 -15
  223. package/dist/core/runner-health/update-preflight.js +9 -14
  224. package/dist/core/server-update/server-update.service.js +12 -49
  225. package/dist/core/server-update/system-apply-closure-patches.js +6 -42
  226. package/dist/core/server-update/system-ensure-prebuilds.js +3 -6
  227. package/dist/core/server-update/system-exec-npm.js +2 -5
  228. package/dist/core/storage/fs-storage-backend.js +1 -5
  229. package/dist/core/storage/storage-location-manager.js +1 -5
  230. package/dist/core/storage/storage.service.js +2 -6
  231. package/dist/core/streaming/ffmpeg-stream-info.js +3 -8
  232. package/dist/core/streaming/stream-probe.service.js +12 -16
  233. package/dist/core/streaming/ttl-cache.js +1 -5
  234. package/dist/core/topology/topology-emitter.service.js +19 -23
  235. package/dist/core/update-availability-emitter.js +3 -7
  236. package/dist/core/update-availability-store.js +8 -45
  237. package/dist/core/updates/agent-installed-packages.js +5 -9
  238. package/dist/core/updates/restart-marker.js +3 -8
  239. package/dist/core/updates/update-check-scheduler.js +13 -18
  240. package/dist/core/updates/wrapper-update-checker.js +3 -7
  241. package/dist/first-boot-addon-plan.js +2 -6
  242. package/dist/framework-nodepath.js +2 -38
  243. package/dist/i18n/request-lang.js +7 -11
  244. package/dist/launcher.js +30 -65
  245. package/dist/lifecycle-journal-path.js +2 -38
  246. package/dist/main.js +287 -324
  247. package/dist/manual-boot.js +120 -157
  248. package/dist/node-role.js +1 -4
  249. package/dist/package-inventory.js +7 -48
  250. package/dist/pending-restore.js +7 -43
  251. package/dist/single-copy-cleanup-runner.js +9 -45
  252. package/dist/single-copy-cleanup.js +7 -15
  253. package/dist/sqlite-restore.js +9 -48
  254. package/dist/starter.js +4 -39
  255. package/dist/ui-serving/lazy-ui-serving.js +3 -39
  256. package/package.json +13 -13
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Reads the hub's human name (D861) from the one row that holds it,
4
3
  * `system-settings` / `server.name`, and falls back to the machine hostname.
@@ -12,44 +11,37 @@
12
11
  * hub that looks unnamed because its store is down is not mistaken for one that
13
12
  * was never named.
14
13
  */
15
- var __importDefault = (this && this.__importDefault) || function (mod) {
16
- return (mod && mod.__esModule) ? mod : { "default": mod };
17
- };
18
- Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.ServerNameReader = void 0;
20
- exports.serverNameReaderFor = serverNameReaderFor;
21
- const node_os_1 = __importDefault(require("node:os"));
22
- const types_1 = require("@camstack/types");
14
+ import os from 'node:os';
15
+ import { errMsg, resolveServerName, SERVER_NAME_SETTING_KEY } from '@camstack/types';
23
16
  const SYSTEM_SETTINGS_COLLECTION = 'system-settings';
24
- class ServerNameReader {
17
+ export class ServerNameReader {
25
18
  deps;
26
19
  constructor(deps) {
27
20
  this.deps = deps;
28
21
  }
29
22
  async read() {
30
- const hostname = (this.deps.hostname ?? node_os_1.default.hostname)();
23
+ const hostname = (this.deps.hostname ?? os.hostname)();
31
24
  try {
32
25
  const stored = await this.deps.store.get({
33
26
  collection: SYSTEM_SETTINGS_COLLECTION,
34
- key: types_1.SERVER_NAME_SETTING_KEY,
27
+ key: SERVER_NAME_SETTING_KEY,
35
28
  });
36
- return (0, types_1.resolveServerName)(stored, hostname);
29
+ return resolveServerName(stored, hostname);
37
30
  }
38
31
  catch (err) {
39
32
  this.deps.logger?.warn('server name read failed - answering the hostname default', {
40
- meta: { error: (0, types_1.errMsg)(err) },
33
+ meta: { error: errMsg(err) },
41
34
  });
42
- return (0, types_1.resolveServerName)(undefined, hostname);
35
+ return resolveServerName(undefined, hostname);
43
36
  }
44
37
  }
45
38
  }
46
- exports.ServerNameReader = ServerNameReader;
47
39
  /**
48
40
  * A reader that resolves the `settings-store` cap lazily from the registry (it
49
41
  * boots after the routers are built). Without a registry, or before the cap is
50
42
  * up, the read throws and {@link ServerNameReader} answers the hostname default.
51
43
  */
52
- function serverNameReaderFor(registry, logger) {
44
+ export function serverNameReaderFor(registry, logger) {
53
45
  return new ServerNameReader({
54
46
  store: {
55
47
  get: async (input) => {
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Site location — the installation's coordinates, as a fact of the SITE.
4
3
  *
@@ -45,15 +44,9 @@
45
44
  * and a derivation must never overwrite a typed value, which is why
46
45
  * `SiteLocationService.detect` refuses when `source === 'operator-set'`.
47
46
  */
48
- Object.defineProperty(exports, "__esModule", { value: true });
49
- exports.SiteLocationService = exports.GEO_IP_ENDPOINTS = exports.GEO_IP_TIMEOUT_MS = exports.SITE_LOCATION_KEY = void 0;
50
- exports.isUsableCoordinate = isUsableCoordinate;
51
- exports.toStatus = toStatus;
52
- exports.parseGeoIpPayload = parseGeoIpPayload;
53
- exports.geolocatePublicIp = geolocatePublicIp;
54
- const types_1 = require("@camstack/types");
47
+ import { errMsg } from '@camstack/types';
55
48
  /** The `system-settings` row this module owns. */
56
- exports.SITE_LOCATION_KEY = 'site-location';
49
+ export const SITE_LOCATION_KEY = 'site-location';
57
50
  const SYSTEM_SETTINGS_COLLECTION = 'system-settings';
58
51
  /**
59
52
  * The addon store the coordinates used to live in. Read ONCE, lazily, to
@@ -70,7 +63,7 @@ const LEGACY_LNG_KEY = 'siteLongitude';
70
63
  * is long enough for a cold TLS handshake to a CDN and short enough that a
71
64
  * captive-portal black hole does not look like a hang.
72
65
  */
73
- exports.GEO_IP_TIMEOUT_MS = 4_000;
66
+ export const GEO_IP_TIMEOUT_MS = 4_000;
74
67
  /**
75
68
  * No-key, HTTPS geo-IP endpoints, tried in order until one parses.
76
69
  *
@@ -79,7 +72,7 @@ exports.GEO_IP_TIMEOUT_MS = 4_000;
79
72
  * and the request carries nothing but the hub's IP — which the endpoint would
80
73
  * see regardless, since seeing it is the entire mechanism.
81
74
  */
82
- exports.GEO_IP_ENDPOINTS = [
75
+ export const GEO_IP_ENDPOINTS = [
83
76
  'https://ipinfo.io/json',
84
77
  'https://ipapi.co/json/',
85
78
  ];
@@ -89,7 +82,7 @@ exports.GEO_IP_ENDPOINTS = [
89
82
  * is treated as absent rather than clamped: a wrong-but-plausible coordinate
90
83
  * produces a wrong sunrise silently, which is worse than the declared fallback.
91
84
  */
92
- function isUsableCoordinate(lat, lng) {
85
+ export function isUsableCoordinate(lat, lng) {
93
86
  if (typeof lat !== 'number' || typeof lng !== 'number')
94
87
  return false;
95
88
  if (!Number.isFinite(lat) || !Number.isFinite(lng))
@@ -99,7 +92,7 @@ function isUsableCoordinate(lat, lng) {
99
92
  return lat !== 0 || lng !== 0;
100
93
  }
101
94
  /** Project a stored row onto the wire shape. */
102
- function toStatus(record) {
95
+ export function toStatus(record) {
103
96
  if (record === null) {
104
97
  return { location: null, derivationAttemptedAt: null, derivationError: null };
105
98
  }
@@ -152,7 +145,7 @@ function asRecord(raw) {
152
145
  * three field names, and an adapter per vendor is how a 30-line fetch becomes a
153
146
  * folder.
154
147
  */
155
- function parseGeoIpPayload(payload) {
148
+ export function parseGeoIpPayload(payload) {
156
149
  if (payload === null || typeof payload !== 'object')
157
150
  return null;
158
151
  const obj = payload;
@@ -183,12 +176,12 @@ function parseGeoIpPayload(payload) {
183
176
  * Every failure mode collapses to `null` plus a log line: this is a *default*,
184
177
  * and a default that throws would take down whatever asked for it.
185
178
  */
186
- async function geolocatePublicIp(fetchImpl, logger, endpoints = exports.GEO_IP_ENDPOINTS) {
179
+ export async function geolocatePublicIp(fetchImpl, logger, endpoints = GEO_IP_ENDPOINTS) {
187
180
  for (const url of endpoints) {
188
181
  try {
189
182
  const response = await fetchImpl(url, {
190
183
  headers: { Accept: 'application/json' },
191
- signal: AbortSignal.timeout(exports.GEO_IP_TIMEOUT_MS),
184
+ signal: AbortSignal.timeout(GEO_IP_TIMEOUT_MS),
192
185
  });
193
186
  if (!response.ok) {
194
187
  logger?.debug('geo-IP endpoint refused', { meta: { url, status: response.status } });
@@ -200,7 +193,7 @@ async function geolocatePublicIp(fetchImpl, logger, endpoints = exports.GEO_IP_E
200
193
  logger?.debug('geo-IP endpoint answered without usable coordinates', { meta: { url } });
201
194
  }
202
195
  catch (err) {
203
- logger?.debug('geo-IP endpoint failed', { meta: { url, error: (0, types_1.errMsg)(err) } });
196
+ logger?.debug('geo-IP endpoint failed', { meta: { url, error: errMsg(err) } });
204
197
  }
205
198
  }
206
199
  return null;
@@ -213,7 +206,7 @@ async function geolocatePublicIp(fetchImpl, logger, endpoints = exports.GEO_IP_E
213
206
  * `derivationAttemptedAt` bounds them across requests and across restarts. The
214
207
  * durable marker is the real guarantee; the in-process one only stops a burst.
215
208
  */
216
- class SiteLocationService {
209
+ export class SiteLocationService {
217
210
  deps;
218
211
  static inFlight = null;
219
212
  constructor(deps) {
@@ -230,7 +223,7 @@ class SiteLocationService {
230
223
  try {
231
224
  return asRecord(await this.deps.store.get({
232
225
  collection: SYSTEM_SETTINGS_COLLECTION,
233
- key: exports.SITE_LOCATION_KEY,
226
+ key: SITE_LOCATION_KEY,
234
227
  }));
235
228
  }
236
229
  catch (err) {
@@ -238,14 +231,14 @@ class SiteLocationService {
238
231
  // the derivation off to overwrite a value that exists. Rethrow-as-null is
239
232
  // exactly the D49 shape this repo has been bitten by, so the caller is
240
233
  // told instead.
241
- this.deps.logger?.warn('site location read failed', { meta: { error: (0, types_1.errMsg)(err) } });
234
+ this.deps.logger?.warn('site location read failed', { meta: { error: errMsg(err) } });
242
235
  throw err;
243
236
  }
244
237
  }
245
238
  async write(record) {
246
239
  await this.deps.store.set({
247
240
  collection: SYSTEM_SETTINGS_COLLECTION,
248
- key: exports.SITE_LOCATION_KEY,
241
+ key: SITE_LOCATION_KEY,
249
242
  value: record,
250
243
  });
251
244
  }
@@ -275,7 +268,7 @@ class SiteLocationService {
275
268
  }
276
269
  catch (err) {
277
270
  this.deps.logger?.debug('legacy site coordinates read failed', {
278
- meta: { error: (0, types_1.errMsg)(err) },
271
+ meta: { error: errMsg(err) },
279
272
  });
280
273
  return null;
281
274
  }
@@ -340,7 +333,7 @@ class SiteLocationService {
340
333
  // The marker is what makes it one-shot. Losing it costs a retry on the
341
334
  // next read, never a wrong value.
342
335
  this.deps.logger?.warn('site location failure marker could not be persisted', {
343
- meta: { error: (0, types_1.errMsg)(err) },
336
+ meta: { error: errMsg(err) },
344
337
  });
345
338
  }
346
339
  return toStatus(failure);
@@ -386,4 +379,3 @@ class SiteLocationService {
386
379
  return this.derive();
387
380
  }
388
381
  }
389
- exports.SiteLocationService = SiteLocationService;
@@ -1,6 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createStreamProbeRouter = createStreamProbeRouter;
4
1
  /**
5
2
  * Stream probe router — fixed core API (not a capability).
6
3
  *
@@ -11,32 +8,32 @@ exports.createStreamProbeRouter = createStreamProbeRouter;
11
8
  * Previously these endpoints lived under `streaming.probeStream` — moved
12
9
  * here as part of eliminating the `streaming` aggregator capability.
13
10
  */
14
- const zod_1 = require("zod");
15
- const types_1 = require("@camstack/types");
16
- const trpc_middleware_js_1 = require("../trpc/trpc.middleware.js");
17
- const ProbedStreamSchema = zod_1.z.object({
18
- width: zod_1.z.number().optional(),
19
- height: zod_1.z.number().optional(),
20
- codec: zod_1.z.string().optional(),
21
- fps: zod_1.z.number().optional(),
22
- bitrateKbps: zod_1.z.number().optional(),
23
- quality: zod_1.z.enum(['high', 'mid', 'low']),
11
+ import { z } from 'zod';
12
+ import { classifyStream } from '@camstack/types';
13
+ import { trpcRouter, adminProcedure } from '../trpc/trpc.middleware.js';
14
+ const ProbedStreamSchema = z.object({
15
+ width: z.number().optional(),
16
+ height: z.number().optional(),
17
+ codec: z.string().optional(),
18
+ fps: z.number().optional(),
19
+ bitrateKbps: z.number().optional(),
20
+ quality: z.enum(['high', 'mid', 'low']),
24
21
  });
25
- const FieldProbeResultSchema = zod_1.z.object({
26
- status: zod_1.z.enum(['ok', 'error']),
27
- labels: zod_1.z.array(zod_1.z.string()).optional(),
28
- error: zod_1.z.string().optional(),
22
+ const FieldProbeResultSchema = z.object({
23
+ status: z.enum(['ok', 'error']),
24
+ labels: z.array(z.string()).optional(),
25
+ error: z.string().optional(),
29
26
  });
30
- function createStreamProbeRouter(sp) {
31
- return (0, trpc_middleware_js_1.trpcRouter)({
32
- probe: trpc_middleware_js_1.adminProcedure
33
- .input(zod_1.z.object({ url: zod_1.z.string(), force: zod_1.z.boolean().optional() }))
27
+ export function createStreamProbeRouter(sp) {
28
+ return trpcRouter({
29
+ probe: adminProcedure
30
+ .input(z.object({ url: z.string(), force: z.boolean().optional() }))
34
31
  .output(ProbedStreamSchema)
35
32
  .mutation(async ({ input }) => {
36
33
  if (!sp)
37
34
  throw new Error('StreamProbeService not available');
38
35
  const metadata = await sp.probe(input.url, { force: input.force });
39
- return { ...metadata, quality: (0, types_1.classifyStream)(metadata) };
36
+ return { ...metadata, quality: classifyStream(metadata) };
40
37
  }),
41
38
  /**
42
39
  * Generic field probe — decides stream vs HTTP reachability based on
@@ -46,8 +43,8 @@ function createStreamProbeRouter(sp) {
46
43
  * that need the kernel's probe without re-implementing ffprobe /
47
44
  * HTTP fetch in every addon.
48
45
  */
49
- probeField: trpc_middleware_js_1.adminProcedure
50
- .input(zod_1.z.object({ key: zod_1.z.string(), value: zod_1.z.unknown() }))
46
+ probeField: adminProcedure
47
+ .input(z.object({ key: z.string(), value: z.unknown() }))
51
48
  .output(FieldProbeResultSchema)
52
49
  .mutation(async ({ input }) => {
53
50
  if (!sp)
@@ -1,6 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createSystemEventsRouter = createSystemEventsRouter;
4
1
  /**
5
2
  * System events router — fixed core API (not a capability).
6
3
  *
@@ -9,10 +6,10 @@ exports.createSystemEventsRouter = createSystemEventsRouter;
9
6
  * All filters are applied server-side by the SystemEventBus — the client
10
7
  * only receives matching events.
11
8
  */
12
- const zod_1 = require("zod");
13
- const trpc_middleware_js_1 = require("../trpc/trpc.middleware.js");
14
- const principal_visibility_js_1 = require("../trpc/principal-visibility.js");
15
- const public_event_filter_js_1 = require("./public-event-filter.js");
9
+ import { z } from 'zod';
10
+ import { trpcRouter, protectedProcedure, iterableSubscription } from '../trpc/trpc.middleware.js';
11
+ import { scopedEventVisibility } from '../trpc/principal-visibility.js';
12
+ import { isPublicEvent, publicRecent } from './public-event-filter.js';
16
13
  function serialize(e) {
17
14
  return {
18
15
  id: e.id,
@@ -33,20 +30,20 @@ function serialize(e) {
33
30
  * Category handling is split (asymmetric): see the per-method schemas
34
31
  * below.
35
32
  */
36
- const ScopeFieldsSchema = zod_1.z.object({
33
+ const ScopeFieldsSchema = z.object({
37
34
  /** Legacy source filter (exact type+id match). */
38
- source: zod_1.z
35
+ source: z
39
36
  .object({
40
- type: zod_1.z.string(),
41
- id: zod_1.z.union([zod_1.z.string(), zod_1.z.number()]),
37
+ type: z.string(),
38
+ id: z.union([z.string(), z.number()]),
42
39
  })
43
40
  .optional(),
44
41
  /** Agent/node filter (prefix match: 'hub' matches 'hub/pipeline'). */
45
- agentId: zod_1.z.string().optional(),
42
+ agentId: z.string().optional(),
46
43
  /** Addon filter. Matches source.addonId or source.id when type='addon'. */
47
- addonId: zod_1.z.string().optional(),
44
+ addonId: z.string().optional(),
48
45
  /** Device filter. Matches source.deviceId or source.id when type='device'. */
49
- deviceId: zod_1.z.number().optional(),
46
+ deviceId: z.number().optional(),
50
47
  });
51
48
  /**
52
49
  * `getRecent` accepts a category array so the UI can drive a
@@ -61,8 +58,8 @@ const ScopeFieldsSchema = zod_1.z.object({
61
58
  * `category` field as `string | string[]`.
62
59
  */
63
60
  const GetRecentInputSchema = ScopeFieldsSchema.extend({
64
- category: zod_1.z.union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())]).optional(),
65
- limit: zod_1.z.number().int().min(1).max(500).optional(),
61
+ category: z.union([z.string(), z.array(z.string())]).optional(),
62
+ limit: z.number().int().min(1).max(500).optional(),
66
63
  });
67
64
  /**
68
65
  * `subscribe` keeps category as a single string — a WIRE choice now, not a bus
@@ -78,17 +75,17 @@ const GetRecentInputSchema = ScopeFieldsSchema.extend({
78
75
  * wildcard and narrow client-side.
79
76
  */
80
77
  const SubscribeInputSchema = ScopeFieldsSchema.extend({
81
- category: zod_1.z.string().optional(),
78
+ category: z.string().optional(),
82
79
  });
83
- function createSystemEventsRouter(eb) {
84
- return (0, trpc_middleware_js_1.trpcRouter)({
85
- getRecent: trpc_middleware_js_1.protectedProcedure.input(GetRecentInputSchema).query(({ input, ctx }) => {
80
+ export function createSystemEventsRouter(eb) {
81
+ return trpcRouter({
82
+ getRecent: protectedProcedure.input(GetRecentInputSchema).query(({ input, ctx }) => {
86
83
  // SECURITY (F0.5): filter the history to what a device-restricted scoped
87
84
  // token may view. null ⇒ admin / broad category-view operator ⇒ unfiltered.
88
85
  // An owner-only category (D224) is not history anyone may read. Both
89
86
  // projections run BEFORE the limit, so N asked is N public rows answered.
90
- const keep = (0, principal_visibility_js_1.scopedEventVisibility)(ctx.user, ctx.deviceScopeLookup);
91
- return (0, public_event_filter_js_1.publicRecent)(eb, {
87
+ const keep = scopedEventVisibility(ctx.user, ctx.deviceScopeLookup);
88
+ return publicRecent(eb, {
92
89
  ...(input.source ? { source: input.source } : {}),
93
90
  ...(input.agentId ? { agentId: input.agentId } : {}),
94
91
  ...(input.addonId ? { addonId: input.addonId } : {}),
@@ -96,11 +93,11 @@ function createSystemEventsRouter(eb) {
96
93
  ...(input.category ? { category: input.category } : {}),
97
94
  }, input.limit, keep).map(serialize);
98
95
  }),
99
- subscribe: trpc_middleware_js_1.protectedProcedure.input(SubscribeInputSchema).subscription(({ input, ctx }) => {
96
+ subscribe: protectedProcedure.input(SubscribeInputSchema).subscription(({ input, ctx }) => {
100
97
  // SECURITY (F0.5): a device-restricted scoped token must not receive every
101
98
  // camera's live events. Same projection as `getRecent`.
102
- const keep = (0, principal_visibility_js_1.scopedEventVisibility)(ctx.user, ctx.deviceScopeLookup);
103
- return (0, trpc_middleware_js_1.iterableSubscription)((push) => {
99
+ const keep = scopedEventVisibility(ctx.user, ctx.deviceScopeLookup);
100
+ return iterableSubscription((push) => {
104
101
  return eb.subscribe({
105
102
  ...(input.source ? { source: input.source } : {}),
106
103
  ...(input.agentId ? { agentId: input.agentId } : {}),
@@ -108,7 +105,7 @@ function createSystemEventsRouter(eb) {
108
105
  ...(input.deviceId !== undefined ? { deviceId: input.deviceId } : {}),
109
106
  ...(input.category ? { category: input.category } : {}),
110
107
  }, (event) => {
111
- if (!(0, public_event_filter_js_1.isPublicEvent)(event))
108
+ if (!isPublicEvent(event))
112
109
  return;
113
110
  if (!keep || keep(event))
114
111
  push(serialize(event));
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * cors-policy — which browser origins may READ this hub's responses (D707).
4
3
  *
@@ -32,23 +31,15 @@
32
31
  *
33
32
  * Pure: no Fastify, no I/O — `register-cors-policy.ts` is the glue.
34
33
  */
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.CORS_PREFLIGHT_MAX_AGE_SEC = exports.CORS_EXPOSED_HEADERS = exports.CORS_ALLOWED_HEADERS = exports.CORS_ALLOWED_METHODS = exports.OPAQUE_ORIGIN = exports.VIEWER_PWA_ORIGIN = void 0;
37
- exports.normalizeOrigin = normalizeOrigin;
38
- exports.parseConfiguredOrigins = parseConfiguredOrigins;
39
- exports.builtInOrigins = builtInOrigins;
40
- exports.judgeCorsOrigin = judgeCorsOrigin;
41
- exports.corsResponseHeaders = corsResponseHeaders;
42
- exports.appendVary = appendVary;
43
34
  /** The hosted viewer PWA (operator decision 2026-10-06). */
44
- exports.VIEWER_PWA_ORIGIN = 'https://camstack.zentik.app';
35
+ export const VIEWER_PWA_ORIGIN = 'https://camstack.zentik.app';
45
36
  /**
46
37
  * The serialisation of an opaque origin. The native app's OTA embed
47
38
  * (`assets/embed/camstack-embed.html`, loaded from `file://`) sends it.
48
39
  */
49
- exports.OPAQUE_ORIGIN = 'null';
40
+ export const OPAQUE_ORIGIN = 'null';
50
41
  /** Every method a hub route answers. */
51
- exports.CORS_ALLOWED_METHODS = 'GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS';
42
+ export const CORS_ALLOWED_METHODS = 'GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS';
52
43
  /**
53
44
  * Request headers a cross-origin caller may send. `authorization` is the
54
45
  * whole point; `range` is recorded-media seeking; the `trpc-*` / `x-trpc-*`
@@ -56,25 +47,25 @@ exports.CORS_ALLOWED_METHODS = 'GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS';
56
47
  * the cookie→bearer exchange is a same-origin mechanism and a cross-origin
57
48
  * page has no business asking for it.
58
49
  */
59
- exports.CORS_ALLOWED_HEADERS = 'authorization, content-type, range, if-range, if-none-match, cache-control, trpc-accept, x-trpc-source, x-trpc-batch-mode';
50
+ export const CORS_ALLOWED_HEADERS = 'authorization, content-type, range, if-range, if-none-match, cache-control, trpc-accept, x-trpc-source, x-trpc-batch-mode';
60
51
  /**
61
52
  * Response headers a cross-origin script may read. The byte-range trio is
62
53
  * recorded playback (a seek reads `content-range`); `content-disposition` is
63
54
  * export downloads; `retry-after` is the rate limiter; the `x-camstack-*`
64
55
  * trio is the clip-still contract (a 204 that says WHY there is no image).
65
56
  */
66
- exports.CORS_EXPOSED_HEADERS = 'content-range, accept-ranges, content-length, content-disposition, etag, retry-after, x-camstack-reason, x-camstack-reason-code, x-camstack-disposition';
57
+ export const CORS_EXPOSED_HEADERS = 'content-range, accept-ranges, content-length, content-disposition, etag, retry-after, x-camstack-reason, x-camstack-reason-code, x-camstack-disposition';
67
58
  /** Preflight cache. Chromium caps at 7200 s; Firefox honours up to 86400. */
68
- exports.CORS_PREFLIGHT_MAX_AGE_SEC = 7200;
59
+ export const CORS_PREFLIGHT_MAX_AGE_SEC = 7200;
69
60
  /**
70
61
  * The canonical serialisation of an origin (`scheme://host[:port]`, lower
71
62
  * case, default port dropped), or `null` when `raw` is not an http(s) origin.
72
63
  * `null` (the opaque origin) is accepted verbatim.
73
64
  */
74
- function normalizeOrigin(raw) {
65
+ export function normalizeOrigin(raw) {
75
66
  const trimmed = raw.trim();
76
- if (trimmed === exports.OPAQUE_ORIGIN)
77
- return exports.OPAQUE_ORIGIN;
67
+ if (trimmed === OPAQUE_ORIGIN)
68
+ return OPAQUE_ORIGIN;
78
69
  let url;
79
70
  try {
80
71
  url = new URL(trimmed);
@@ -94,7 +85,7 @@ function normalizeOrigin(raw) {
94
85
  return url.origin;
95
86
  }
96
87
  /** Read the configured value (array from YAML, already split from env). */
97
- function parseConfiguredOrigins(value) {
88
+ export function parseConfiguredOrigins(value) {
98
89
  if (!Array.isArray(value))
99
90
  return { origins: [], rejected: [] };
100
91
  const origins = [];
@@ -113,8 +104,8 @@ function parseConfiguredOrigins(value) {
113
104
  return { origins, rejected };
114
105
  }
115
106
  /** The built-in entries. */
116
- function builtInOrigins() {
117
- return [exports.VIEWER_PWA_ORIGIN, exports.OPAQUE_ORIGIN];
107
+ export function builtInOrigins() {
108
+ return [VIEWER_PWA_ORIGIN, OPAQUE_ORIGIN];
118
109
  }
119
110
  /** The first value of a possibly comma-joined forwarding header, lower case. */
120
111
  function firstHost(value) {
@@ -125,7 +116,7 @@ function firstHost(value) {
125
116
  }
126
117
  /** `host[:port]` of an http(s) origin, or null. */
127
118
  function hostOfOrigin(origin) {
128
- if (origin === exports.OPAQUE_ORIGIN)
119
+ if (origin === OPAQUE_ORIGIN)
129
120
  return null;
130
121
  try {
131
122
  return new URL(origin).host.toLowerCase();
@@ -138,7 +129,7 @@ function hostOfOrigin(origin) {
138
129
  * Judge one request's `Origin`. `listed` is the full allowlist (built-ins and
139
130
  * the operator's extras), already normalised.
140
131
  */
141
- function judgeCorsOrigin(facts, listed) {
132
+ export function judgeCorsOrigin(facts, listed) {
142
133
  const raw = facts.origin;
143
134
  if (raw === undefined || raw.length === 0)
144
135
  return { kind: 'no-origin' };
@@ -162,25 +153,25 @@ function judgeCorsOrigin(facts, listed) {
162
153
  * page, and `Vary: Origin` (set by the glue on every response) keeps a cache
163
154
  * from serving one origin's answer to another.
164
155
  */
165
- function corsResponseHeaders(origin, preflight) {
156
+ export function corsResponseHeaders(origin, preflight) {
166
157
  const base = {
167
158
  'access-control-allow-origin': origin,
168
- 'access-control-expose-headers': exports.CORS_EXPOSED_HEADERS,
159
+ 'access-control-expose-headers': CORS_EXPOSED_HEADERS,
169
160
  };
170
161
  if (preflight === null)
171
162
  return base;
172
163
  return {
173
164
  ...base,
174
- 'access-control-allow-methods': exports.CORS_ALLOWED_METHODS,
175
- 'access-control-allow-headers': exports.CORS_ALLOWED_HEADERS,
176
- 'access-control-max-age': String(exports.CORS_PREFLIGHT_MAX_AGE_SEC),
165
+ 'access-control-allow-methods': CORS_ALLOWED_METHODS,
166
+ 'access-control-allow-headers': CORS_ALLOWED_HEADERS,
167
+ 'access-control-max-age': String(CORS_PREFLIGHT_MAX_AGE_SEC),
177
168
  // A public origin (the PWA) calling a LAN hub is a "private network"
178
169
  // request to Chromium; its preflight must be answered explicitly.
179
170
  ...(preflight.requestPrivateNetwork ? { 'access-control-allow-private-network': 'true' } : {}),
180
171
  };
181
172
  }
182
173
  /** Append `token` to a `Vary` value unless it is already there. */
183
- function appendVary(existing, token) {
174
+ export function appendVary(existing, token) {
184
175
  if (existing === undefined || existing.trim().length === 0)
185
176
  return token;
186
177
  const parts = existing.split(',').map((p) => p.trim().toLowerCase());
@@ -1,9 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createCorsPolicy = createCorsPolicy;
4
- exports.registerCorsPolicy = registerCorsPolicy;
5
- exports.refuseForeignWsUpgrade = refuseForeignWsUpgrade;
6
- const cors_policy_js_1 = require("./cors-policy.js");
1
+ import { appendVary, builtInOrigins, corsResponseHeaders, judgeCorsOrigin, parseConfiguredOrigins, } from './cors-policy.js';
7
2
  /** Distinct refused origins remembered for log de-duplication. */
8
3
  const MAX_LOGGED_DENIALS = 256;
9
4
  function headerValue(value) {
@@ -18,8 +13,8 @@ function varyText(value) {
18
13
  return value.filter((v) => typeof v === 'string').join(', ');
19
14
  return undefined;
20
15
  }
21
- function createCorsPolicy(deps) {
22
- const builtIns = (0, cors_policy_js_1.builtInOrigins)();
16
+ export function createCorsPolicy(deps) {
17
+ const builtIns = builtInOrigins();
23
18
  let lastConfigured = Symbol('unset');
24
19
  let listed = new Set(builtIns);
25
20
  const loggedDenials = new Set();
@@ -28,7 +23,7 @@ function createCorsPolicy(deps) {
28
23
  if (configured === lastConfigured)
29
24
  return listed;
30
25
  lastConfigured = configured;
31
- const parsed = (0, cors_policy_js_1.parseConfiguredOrigins)(configured);
26
+ const parsed = parseConfiguredOrigins(configured);
32
27
  if (parsed.rejected.length > 0) {
33
28
  deps.logger.warn('cors: ignored configured origins that are not http(s) origins', {
34
29
  meta: { rejected: parsed.rejected, setting: 'server.corsOrigins' },
@@ -39,7 +34,7 @@ function createCorsPolicy(deps) {
39
34
  };
40
35
  return {
41
36
  judge(headers) {
42
- const verdict = (0, cors_policy_js_1.judgeCorsOrigin)({
37
+ const verdict = judgeCorsOrigin({
43
38
  origin: headerValue(headers.origin),
44
39
  host: headerValue(headers.host),
45
40
  forwardedHost: headerValue(headers['x-forwarded-host']),
@@ -64,17 +59,17 @@ function createCorsPolicy(deps) {
64
59
  * answered here with 204 (as before D707) — with grants only for an allowed
65
60
  * origin, so a refused preflight fails in the browser.
66
61
  */
67
- function registerCorsPolicy(fastify, policy) {
62
+ export function registerCorsPolicy(fastify, policy) {
68
63
  fastify.addHook('onRequest', async (request, reply) => {
69
64
  // The answer depends on Origin for every route, so every response says so
70
65
  // — a cached same-origin answer must never be replayed to another origin.
71
- const vary = (0, cors_policy_js_1.appendVary)(varyText(reply.getHeader('vary')), 'Origin');
66
+ const vary = appendVary(varyText(reply.getHeader('vary')), 'Origin');
72
67
  reply.header('vary', vary);
73
68
  reply.raw.setHeader('vary', vary);
74
69
  const verdict = policy.judge(request.headers);
75
70
  const isPreflight = request.method === 'OPTIONS' && request.headers['access-control-request-method'] !== undefined;
76
71
  if (verdict.kind === 'allowed') {
77
- const headers = (0, cors_policy_js_1.corsResponseHeaders)(verdict.origin, isPreflight
72
+ const headers = corsResponseHeaders(verdict.origin, isPreflight
78
73
  ? {
79
74
  requestPrivateNetwork: headerValue(request.headers['access-control-request-private-network']) === 'true',
80
75
  }
@@ -99,7 +94,7 @@ function registerCorsPolicy(fastify, policy) {
99
94
  * Node client, an agent) passes — Origin is the browser's signal, and auth is
100
95
  * the bearer in `connectionParams` either way.
101
96
  */
102
- function refuseForeignWsUpgrade(policy, headers, socket) {
97
+ export function refuseForeignWsUpgrade(policy, headers, socket) {
103
98
  const verdict = policy.judge(headers);
104
99
  if (verdict.kind !== 'denied')
105
100
  return false;
@@ -1,13 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DeployStageRegistry = void 0;
4
- const node_crypto_1 = require("node:crypto");
1
+ import { createHash, randomUUID, timingSafeEqual } from 'node:crypto';
5
2
  /**
6
3
  * In-memory, single-use, TTL-bounded store of staged addon tarballs the hub
7
4
  * serves to agents over HTTP. One entry per deploy target; the token is
8
5
  * consumed on the first successful read so a bundle URL is never reusable.
9
6
  */
10
- class DeployStageRegistry {
7
+ export class DeployStageRegistry {
11
8
  entries = new Map();
12
9
  ttlMs;
13
10
  now;
@@ -18,9 +15,9 @@ class DeployStageRegistry {
18
15
  stage(buffer) {
19
16
  // Reclaim abandoned (never-consumed) entries before inserting a new one.
20
17
  this.sweepExpired();
21
- const id = (0, node_crypto_1.randomUUID)();
22
- const token = (0, node_crypto_1.randomUUID)();
23
- const sha256 = (0, node_crypto_1.createHash)('sha256').update(buffer).digest('hex');
18
+ const id = randomUUID();
19
+ const token = randomUUID();
20
+ const sha256 = createHash('sha256').update(buffer).digest('hex');
24
21
  this.entries.set(id, { token, buffer, sha256, expiresAt: this.now() + this.ttlMs });
25
22
  return { id, token, sha256, bytes: buffer.length };
26
23
  }
@@ -35,7 +32,7 @@ class DeployStageRegistry {
35
32
  // Constant-time comparison: different byte lengths → not equal (no timing oracle).
36
33
  const entryBuf = Buffer.from(entry.token);
37
34
  const tokenBuf = Buffer.from(token);
38
- if (entryBuf.length !== tokenBuf.length || !(0, node_crypto_1.timingSafeEqual)(entryBuf, tokenBuf))
35
+ if (entryBuf.length !== tokenBuf.length || !timingSafeEqual(entryBuf, tokenBuf))
39
36
  return null;
40
37
  this.entries.delete(id); // single-use
41
38
  return entry.buffer;
@@ -57,4 +54,3 @@ class DeployStageRegistry {
57
54
  this.entries.delete(id);
58
55
  }
59
56
  }
60
- exports.DeployStageRegistry = DeployStageRegistry;