@camstack/server 1.2.592 → 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 +219 -221
  103. package/dist/api/trpc/generated-cap-routers.js +4878 -4726
  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 +254 -197
  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,41 +1,3 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.isSafeDevUploadVersion = isSafeDevUploadVersion;
37
- exports.packDevUploadVersionDir = packDevUploadVersionDir;
38
- exports.unpackDevUploadVersionBundle = unpackDevUploadVersionBundle;
39
1
  /**
40
2
  * Pack / unpack a hub `server-root/dev-uploads/<version>/` directory for
41
3
  * agent fan-out (`POST /api/server-upload/propagate` → `$agent.stageDevUploads`).
@@ -43,15 +5,15 @@ exports.unpackDevUploadVersionBundle = unpackDevUploadVersionBundle;
43
5
  * One gzipped tar carries every tarball + `manifest.json`. Fail-closed on
44
6
  * path traversal and on a layout that would not satisfy RootUpdateService.
45
7
  */
46
- const fs = __importStar(require("node:fs"));
47
- const os = __importStar(require("node:os"));
48
- const path = __importStar(require("node:path"));
49
- const tar = __importStar(require("tar"));
50
- const index_js_1 = require("../server-root/index.js");
8
+ import * as fs from 'node:fs';
9
+ import * as os from 'node:os';
10
+ import * as path from 'node:path';
11
+ import * as tar from 'tar';
12
+ import { DEV_UPLOAD_MANIFEST_FILE, isDevChannelVersion, readDevUploadManifest, } from '../server-root/index.js';
51
13
  /** Version chars safe as a single path segment (matches server-upload). */
52
14
  const SAFE_VERSION_RE = /^[0-9A-Za-z][0-9A-Za-z.-]*$/;
53
- function isSafeDevUploadVersion(version) {
54
- return SAFE_VERSION_RE.test(version) && (0, index_js_1.isDevChannelVersion)(version);
15
+ export function isSafeDevUploadVersion(version) {
16
+ return SAFE_VERSION_RE.test(version) && isDevChannelVersion(version);
55
17
  }
56
18
  function hasPathTraversal(name) {
57
19
  return name.includes('/') || name.includes('\\') || name.includes('..');
@@ -60,8 +22,8 @@ function hasPathTraversal(name) {
60
22
  * Pack every file in `versionDir` (basename entries only) into a gzipped tar.
61
23
  * Refuses if the manifest is missing/invalid or lists a missing tarball.
62
24
  */
63
- async function packDevUploadVersionDir(versionDir) {
64
- const manifest = (0, index_js_1.readDevUploadManifest)(versionDir);
25
+ export async function packDevUploadVersionDir(versionDir) {
26
+ const manifest = readDevUploadManifest(versionDir);
65
27
  if (manifest === null) {
66
28
  throw new Error(`dev-uploads manifest missing or invalid in ${versionDir}`);
67
29
  }
@@ -74,7 +36,7 @@ async function packDevUploadVersionDir(versionDir) {
74
36
  throw new Error(`dev-uploads tarball listed in manifest is missing: ${filename}`);
75
37
  }
76
38
  }
77
- if (!fs.existsSync(path.join(versionDir, index_js_1.DEV_UPLOAD_MANIFEST_FILE))) {
39
+ if (!fs.existsSync(path.join(versionDir, DEV_UPLOAD_MANIFEST_FILE))) {
78
40
  throw new Error(`dev-uploads manifest file missing in ${versionDir}`);
79
41
  }
80
42
  const entries = fs.readdirSync(versionDir).filter((name) => {
@@ -100,7 +62,7 @@ async function packDevUploadVersionDir(versionDir) {
100
62
  * atomically (stage sibling + rename). Validates version shape, entry names,
101
63
  * and that the extracted layout matches the manifest.
102
64
  */
103
- async function unpackDevUploadVersionBundle(args) {
65
+ export async function unpackDevUploadVersionBundle(args) {
104
66
  const { serverRoot, version, bundle } = args;
105
67
  if (!isSafeDevUploadVersion(version)) {
106
68
  throw new Error(`Refused: version "${version}" is not a safe dev-channel version for staging`);
@@ -132,7 +94,7 @@ async function unpackDevUploadVersionBundle(args) {
132
94
  if (refusedEntry !== null) {
133
95
  throw new Error(`Refused: archive entry is not a basename: ${refusedEntry}`);
134
96
  }
135
- const manifest = (0, index_js_1.readDevUploadManifest)(stagingDir);
97
+ const manifest = readDevUploadManifest(stagingDir);
136
98
  if (manifest === null) {
137
99
  throw new Error('extracted archive has no valid manifest.json');
138
100
  }
@@ -1,7 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ADAPTIVE_PROBE_PER_IP_PER_MINUTE = exports.ADAPTIVE_PROBE_BYTES = void 0;
4
- exports.registerAdaptiveProbeRoute = registerAdaptiveProbeRoute;
5
1
  /**
6
2
  * Burst blob for adaptive-tier downlink measurement (D635).
7
3
  *
@@ -24,16 +20,16 @@ exports.registerAdaptiveProbeRoute = registerAdaptiveProbeRoute;
24
20
  * check the stream data plane applies — and is rate-limited per client IP.
25
21
  * Everything a refusal returns is a few bytes.
26
22
  */
27
- const node_crypto_1 = require("node:crypto");
28
- const health_routes_js_1 = require("./health.routes.js");
29
- const auth_rate_limit_js_1 = require("../../auth/auth-rate-limit.js");
30
- exports.ADAPTIVE_PROBE_BYTES = 1024 * 1024;
23
+ import { randomBytes } from 'node:crypto';
24
+ import { isAuthorizedHealthRequest } from './health.routes.js';
25
+ import { clientKeyFromRequest } from '../../auth/auth-rate-limit.js';
26
+ export const ADAPTIVE_PROBE_BYTES = 1024 * 1024;
31
27
  /**
32
28
  * Probes a client IP may draw per minute: 12. The client probes at most once
33
29
  * per 30 s per app (single-flight + cache), so 12 leaves room for several
34
30
  * apps/devices behind one NAT and caps an abuser at 12 MiB/min.
35
31
  */
36
- exports.ADAPTIVE_PROBE_PER_IP_PER_MINUTE = 12;
32
+ export const ADAPTIVE_PROBE_PER_IP_PER_MINUTE = 12;
37
33
  /**
38
34
  * Random, so it is INCOMPRESSIBLE. The previous body was one repeated byte and
39
35
  * `@fastify/compress` (global in `main.ts`; its default types include
@@ -41,11 +37,11 @@ exports.ADAPTIVE_PROBE_PER_IP_PER_MINUTE = 12;
41
37
  * trip and called it bandwidth. `compress: false` below stops our own
42
38
  * compressor; randomness also defeats one in a relay on the way.
43
39
  */
44
- const BODY = (0, node_crypto_1.randomBytes)(exports.ADAPTIVE_PROBE_BYTES);
45
- function registerAdaptiveProbeRoute(fastify, deps) {
40
+ const BODY = randomBytes(ADAPTIVE_PROBE_BYTES);
41
+ export function registerAdaptiveProbeRoute(fastify, deps) {
46
42
  fastify.get('/adaptive-probe', { compress: false }, async (req, reply) => {
47
43
  reply.header('cache-control', 'no-store');
48
- const authorized = (0, health_routes_js_1.isAuthorizedHealthRequest)({
44
+ const authorized = isAuthorizedHealthRequest({
49
45
  ...(typeof req.headers.authorization === 'string'
50
46
  ? { authorization: req.headers.authorization }
51
47
  : {}),
@@ -53,7 +49,7 @@ function registerAdaptiveProbeRoute(fastify, deps) {
53
49
  }, deps.verifyToken);
54
50
  if (!authorized)
55
51
  return reply.status(401).send({ ok: false, error: 'unauthorized' });
56
- const key = (0, auth_rate_limit_js_1.clientKeyFromRequest)(req, deps.network);
52
+ const key = clientKeyFromRequest(req, deps.network);
57
53
  if (key !== null) {
58
54
  const verdict = deps.limiter.check(`adaptive-probe:${key}`);
59
55
  if (!verdict.allowed) {
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Health endpoints — fast probe surface for monitoring (k8s, uptime,
4
3
  * external watchdogs).
@@ -19,17 +18,13 @@
19
18
  * monitors talking to the hub and monitors talking directly to an agent
20
19
  * (`http://<agent>:4444/health`) see identical payloads.
21
20
  */
22
- Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.buildHubHealth = buildHubHealth;
24
- exports.isAuthorizedHealthRequest = isAuthorizedHealthRequest;
25
- exports.registerHealthRoutes = registerHealthRoutes;
26
- const runner_boot_check_js_1 = require("../../core/runner-health/runner-boot-check.js");
27
- const session_cookie_js_1 = require("../../auth/session-cookie.js");
21
+ import { isRunnerBootCheckDegraded } from '../../core/runner-health/runner-boot-check.js';
22
+ import { isSessionGradeJwtPayload, readSessionCookieFromHeader } from '../../auth/session-cookie.js';
28
23
  const AGENT_HEALTH_TIMEOUT_MS = 3_000;
29
24
  function nowIso() {
30
25
  return new Date().toISOString();
31
26
  }
32
- async function buildHubHealth(deps, proc = process) {
27
+ export async function buildHubHealth(deps, proc = process) {
33
28
  // Fan-out-free: in-memory registry snapshot only, never a per-node RPC (#26).
34
29
  const nodes = deps.agentRegistry.listNodeLiveness();
35
30
  const remote = nodes.filter((n) => !n.isHub);
@@ -40,7 +35,7 @@ async function buildHubHealth(deps, proc = process) {
40
35
  const runners = check === undefined
41
36
  ? undefined
42
37
  : {
43
- degraded: (0, runner_boot_check_js_1.isRunnerBootCheckDegraded)(check),
38
+ degraded: isRunnerBootCheckDegraded(check),
44
39
  expected: check.expected,
45
40
  running: check.running,
46
41
  failed: check.failed.length,
@@ -90,16 +85,16 @@ async function fetchAgentHealth(deps, nodeId) {
90
85
  * (agent ids, versions, pids) — public probes get only `{ok}`.
91
86
  * Pure over (headers, verifier) so the spec exercises it directly.
92
87
  */
93
- function isAuthorizedHealthRequest(headers, verifyToken) {
88
+ export function isAuthorizedHealthRequest(headers, verifyToken) {
94
89
  const bearer = headers.authorization?.startsWith('Bearer ')
95
90
  ? headers.authorization.slice('Bearer '.length)
96
91
  : null;
97
- const cookieToken = (0, session_cookie_js_1.readSessionCookieFromHeader)(headers.cookie);
92
+ const cookieToken = readSessionCookieFromHeader(headers.cookie);
98
93
  for (const token of [bearer, cookieToken]) {
99
94
  if (!token)
100
95
  continue;
101
96
  try {
102
- if ((0, session_cookie_js_1.isSessionGradeJwtPayload)(verifyToken(token)))
97
+ if (isSessionGradeJwtPayload(verifyToken(token)))
103
98
  return true;
104
99
  }
105
100
  catch {
@@ -108,7 +103,7 @@ function isAuthorizedHealthRequest(headers, verifyToken) {
108
103
  }
109
104
  return false;
110
105
  }
111
- function registerHealthRoutes(fastify, deps) {
106
+ export function registerHealthRoutes(fastify, deps) {
112
107
  const authorized = (req) => isAuthorizedHealthRequest({
113
108
  ...(typeof req.headers.authorization === 'string'
114
109
  ? { authorization: req.headers.authorization }
@@ -1,10 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HubAddressUnavailableError = void 0;
4
- exports.resolveHubBaseUrl = resolveHubBaseUrl;
5
- exports.clusterBaseUrlResolver = clusterBaseUrlResolver;
6
1
  /** Thrown when the hub cannot name an address `audience` can reach. */
7
- class HubAddressUnavailableError extends Error {
2
+ export class HubAddressUnavailableError extends Error {
8
3
  audience;
9
4
  reason;
10
5
  constructor(audience, reason) {
@@ -17,13 +12,12 @@ class HubAddressUnavailableError extends Error {
17
12
  this.name = 'HubAddressUnavailableError';
18
13
  }
19
14
  }
20
- exports.HubAddressUnavailableError = HubAddressUnavailableError;
21
15
  /**
22
16
  * Resolve the hub's base URL for `audience` from the live provider. Called per
23
17
  * delivery — interfaces and the allowlist move, and a deploy is rare enough
24
18
  * that a cache would only add a way to be stale.
25
19
  */
26
- async function resolveHubBaseUrl(getSource, audience) {
20
+ export async function resolveHubBaseUrl(getSource, audience) {
27
21
  const source = getSource();
28
22
  if (source === null)
29
23
  throw new HubAddressUnavailableError(audience, 'local-network-unavailable');
@@ -32,6 +26,6 @@ async function resolveHubBaseUrl(getSource, audience) {
32
26
  throw new HubAddressUnavailableError(audience, 'no-reachable-endpoint');
33
27
  return baseUrl;
34
28
  }
35
- function clusterBaseUrlResolver(getSource) {
29
+ export function clusterBaseUrlResolver(getSource) {
36
30
  return () => resolveHubBaseUrl(getSource, 'internal');
37
31
  }
@@ -1,46 +1,8 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.tarModelFiles = tarModelFiles;
37
- exports.distributeModelWith = distributeModelWith;
38
- exports.buildModelDistributorProvider = buildModelDistributorProvider;
39
- const node_child_process_1 = require("node:child_process");
40
- const fs = __importStar(require("node:fs"));
41
- const path = __importStar(require("node:path"));
42
- const system_1 = require("@camstack/system");
43
- const addon_upload_js_1 = require("./addon-upload.js");
1
+ import { spawn } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import { collectModelFiles, isModelDownloaded } from '@camstack/system';
5
+ import { buildHubHttpSource } from './addon-upload.js';
44
6
  const AGENT_DISTRIBUTE_TIMEOUT_MS = 60_000;
45
7
  function hubModelsDir() {
46
8
  return path.join(process.env['CAMSTACK_DATA'] ?? 'camstack-data', 'models');
@@ -50,9 +12,9 @@ function hubModelsDir() {
50
12
  * Async (spawn, not execFileSync) so a large model doesn't block the event
51
13
  * loop. The agent untars this exact buffer into its own modelsDir.
52
14
  */
53
- function tarModelFiles(cwd, files) {
15
+ export function tarModelFiles(cwd, files) {
54
16
  return new Promise((resolve, reject) => {
55
- const child = (0, node_child_process_1.spawn)('tar', ['-czf', '-', '-C', cwd, ...files]);
17
+ const child = spawn('tar', ['-czf', '-', '-C', cwd, ...files]);
56
18
  const chunks = [];
57
19
  const errChunks = [];
58
20
  child.stdout.on('data', (c) => chunks.push(c));
@@ -71,7 +33,7 @@ function tarModelFiles(cwd, files) {
71
33
  * precondition-check → collect → tar → stage → trigger the agent pull.
72
34
  * `nodeId === 'hub'` is a no-op (the artifact is already resident).
73
35
  */
74
- async function distributeModelWith(seam, input) {
36
+ export async function distributeModelWith(seam, input) {
75
37
  const { targetNodeId, modelId, format, entry } = input;
76
38
  if (targetNodeId === 'hub') {
77
39
  return { ok: true, sha256: '', bytes: 0, path: seam.modelsDir };
@@ -79,7 +41,7 @@ async function distributeModelWith(seam, input) {
79
41
  if (!seam.isPresent(entry, format)) {
80
42
  throw new Error(`model ${modelId}/${format} not present on hub — download or convert it first`);
81
43
  }
82
- const files = (0, system_1.collectModelFiles)(entry, format).filter((f) => seam.fileExists(f));
44
+ const files = collectModelFiles(entry, format).filter((f) => seam.fileExists(f));
83
45
  if (files.length === 0) {
84
46
  throw new Error(`model ${modelId}/${format} resolved no files to distribute`);
85
47
  }
@@ -94,17 +56,17 @@ async function distributeModelWith(seam, input) {
94
56
  * Moleculer broker + the deploy-stage registry, which a forked addon can't
95
57
  * reach.
96
58
  */
97
- function buildModelDistributorProvider(moleculer, loggingService,
59
+ export function buildModelDistributorProvider(moleculer, loggingService,
98
60
  /** The `local-network` cap's cluster address (`hub-cluster-url.ts`). */
99
61
  resolveClusterBaseUrl) {
100
62
  const logger = loggingService.createLogger('model-distributor');
101
63
  const modelsDir = hubModelsDir();
102
64
  const seam = {
103
65
  modelsDir,
104
- isPresent: (entry, format) => (0, system_1.isModelDownloaded)(modelsDir, entry, format),
66
+ isPresent: (entry, format) => isModelDownloaded(modelsDir, entry, format),
105
67
  fileExists: (rel) => fs.existsSync(path.join(modelsDir, rel)),
106
68
  tar: (files) => tarModelFiles(modelsDir, files),
107
- stage: async (buffer) => (0, addon_upload_js_1.buildHubHttpSource)(buffer, await resolveClusterBaseUrl()),
69
+ stage: async (buffer) => buildHubHttpSource(buffer, await resolveClusterBaseUrl()),
108
70
  callAgent: async (nodeId, payload) => {
109
71
  const broker = moleculer?.broker;
110
72
  if (!broker)
@@ -1,28 +1,25 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.renderConsentPage = renderConsentPage;
4
- const app_page_shell_js_1 = require("../../auth/app-page-shell.js");
5
- const app_page_strings_js_1 = require("../../auth/app-page-strings.js");
1
+ import { appHiddenField, appHint, appSubmitButton, escapeHtml, renderAppPage, } from '../../auth/app-page-shell.js';
2
+ import { appStrings } from '../../auth/app-page-strings.js';
6
3
  /** Allow/Deny consent screen on the hub's shared page shell (the look of the
7
4
  * app sign-in pages). Submitting POSTs to the same path with the hidden query
8
5
  * fields + `consent=allow|deny`. */
9
- function renderConsentPage(input) {
6
+ export function renderConsentPage(input) {
10
7
  const hidden = Object.entries(input.hidden)
11
- .map(([name, value]) => (0, app_page_shell_js_1.appHiddenField)(name, value))
8
+ .map(([name, value]) => appHiddenField(name, value))
12
9
  .join('');
13
- const t = (0, app_page_strings_js_1.appStrings)(input.lang).consent;
10
+ const t = appStrings(input.lang).consent;
14
11
  const destination = input.redirectUri
15
- ? `<p class="hint">${(0, app_page_shell_js_1.escapeHtml)(t.sendingTo)}<code>${(0, app_page_shell_js_1.escapeHtml)(input.redirectUri)}</code></p>`
12
+ ? `<p class="hint">${escapeHtml(t.sendingTo)}<code>${escapeHtml(input.redirectUri)}</code></p>`
16
13
  : '';
17
- return (0, app_page_shell_js_1.renderAppPage)({
14
+ return renderAppPage({
18
15
  lang: input.lang,
19
16
  title: `${t.titlePrefix}${input.displayName}`,
20
17
  heading: `${t.headingPrefix}${input.displayName}`,
21
18
  body: [
22
- `<p>${(0, app_page_shell_js_1.escapeHtml)(t.signedInAs)}<strong>${(0, app_page_shell_js_1.escapeHtml)(input.username)}</strong></p>`,
23
- (0, app_page_shell_js_1.appHint)(`${t.grantPrefix}${input.scopeSummary}`),
19
+ `<p>${escapeHtml(t.signedInAs)}<strong>${escapeHtml(input.username)}</strong></p>`,
20
+ appHint(`${t.grantPrefix}${input.scopeSummary}`),
24
21
  destination,
25
- `<form method="POST">${hidden}<div class="actions">${(0, app_page_shell_js_1.appSubmitButton)(t.allow, 'consent', 'allow')}${(0, app_page_shell_js_1.appSubmitButton)(t.deny, 'consent', 'deny', true)}</div></form>`,
22
+ `<form method="POST">${hidden}<div class="actions">${appSubmitButton(t.allow, 'consent', 'allow')}${appSubmitButton(t.deny, 'consent', 'deny', true)}</div></form>`,
26
23
  ].join(''),
27
24
  });
28
25
  }
@@ -1,15 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.redactAuthorizeQuery = redactAuthorizeQuery;
4
- exports.describeAuthorizeCall = describeAuthorizeCall;
5
- exports.validateAuthorizeQuery = validateAuthorizeQuery;
6
- exports.isRedirectUriAllowed = isRedirectUriAllowed;
7
- exports.summariseScopes = summariseScopes;
8
- exports.registerOauth2Routes = registerOauth2Routes;
9
- const session_cookie_js_1 = require("../../auth/session-cookie.js");
10
- const app_page_strings_js_1 = require("../../auth/app-page-strings.js");
11
- const consent_page_js_1 = require("./consent-page.js");
12
- const private_host_js_1 = require("./private-host.js");
1
+ import { loginRedirectUrl, SESSION_COOKIE, shouldRedirectToLogin, } from '../../auth/session-cookie.js';
2
+ import { resolveAppPageLang } from '../../auth/app-page-strings.js';
3
+ import { renderConsentPage } from './consent-page.js';
4
+ import { isPrivateHost } from './private-host.js';
13
5
  /**
14
6
  * Query keys whose VALUE may be logged.
15
7
  *
@@ -34,7 +26,7 @@ function truncate(value, max) {
34
26
  return value.length > max ? `${value.slice(0, max)}…` : value;
35
27
  }
36
28
  /** Rebuild a query string with every non-allow-listed value replaced. */
37
- function redactAuthorizeQuery(rawQuery) {
29
+ export function redactAuthorizeQuery(rawQuery) {
38
30
  if (rawQuery === '')
39
31
  return '';
40
32
  const parts = [];
@@ -57,7 +49,7 @@ function describeReferer(raw) {
57
49
  }
58
50
  }
59
51
  /** Everything the log is allowed to know about an inbound authorize call. */
60
- function describeAuthorizeCall(url, headers, hasSessionCookie) {
52
+ export function describeAuthorizeCall(url, headers, hasSessionCookie) {
61
53
  const q = url.indexOf('?');
62
54
  const ua = headers['user-agent'];
63
55
  return {
@@ -118,7 +110,7 @@ function resolveIntegrationParam(raw) {
118
110
  * NOT checked — that pair is verified only at the Lambda boundary, and a
119
111
  * PUBLIC client (`requiresPkce`) has no secret to check it against at all;
120
112
  * the S256 challenge is what binds the code to its requester instead. */
121
- function validateAuthorizeQuery(q, knownIntegrations, pendingAddons = []) {
113
+ export function validateAuthorizeQuery(q, knownIntegrations, pendingAddons = []) {
122
114
  if (q.response_type !== 'code')
123
115
  return { ok: false, status: 400, error: 'unsupported_response_type' };
124
116
  // Four distinct faults used to collapse into one opaque string.
@@ -198,7 +190,7 @@ function validateAuthorizeQuery(q, knownIntegrations, pendingAddons = []) {
198
190
  * `startsWith` on a string the browser will parse differently is exactly how an
199
191
  * allow-list gets walked around.
200
192
  */
201
- function isRedirectUriAllowed(redirectUri, allowedPrefixes, allowedPrivateHostPaths = []) {
193
+ export function isRedirectUriAllowed(redirectUri, allowedPrefixes, allowedPrivateHostPaths = []) {
202
194
  if (allowedPrefixes.some((p) => redirectUri.startsWith(p)))
203
195
  return true;
204
196
  if (allowedPrivateHostPaths.length === 0)
@@ -212,12 +204,12 @@ function isRedirectUriAllowed(redirectUri, allowedPrefixes, allowedPrivateHostPa
212
204
  }
213
205
  if (url.protocol !== 'http:' && url.protocol !== 'https:')
214
206
  return false;
215
- if (!(0, private_host_js_1.isPrivateHost)(url.hostname))
207
+ if (!isPrivateHost(url.hostname))
216
208
  return false;
217
209
  return allowedPrivateHostPaths.includes(url.pathname);
218
210
  }
219
211
  /** One-line human summary of a scope list for the consent screen. */
220
- function summariseScopes(scopes) {
212
+ export function summariseScopes(scopes) {
221
213
  if (scopes.some((s) => s.type === 'category' && s.target === 'device')) {
222
214
  return 'view and control all your cameras and devices';
223
215
  }
@@ -257,10 +249,10 @@ function refuseAuthorize(reply, logger, method, call, refusal) {
257
249
  * it" is invisible and every refusal reads as a first arrival.
258
250
  */
259
251
  function refuseUnauthenticated(request, reply, logger, call, reason) {
260
- const redirected = (0, session_cookie_js_1.shouldRedirectToLogin)(request.method, request.headers.accept);
252
+ const redirected = shouldRedirectToLogin(request.method, request.headers.accept);
261
253
  logger.info(redirected ? 'oauth2 authorize bounced to login' : 'oauth2 authorize refused: unauthenticated', { meta: { method: request.method, reason, redirected, ...call } });
262
254
  if (redirected)
263
- return reply.redirect((0, session_cookie_js_1.loginRedirectUrl)(request.url));
255
+ return reply.redirect(loginRedirectUrl(request.url));
264
256
  return reply.status(401).send({ error: 'unauthorized' });
265
257
  }
266
258
  /** Read integrationId → descriptor from every registered `oauth-integration`
@@ -286,7 +278,7 @@ function parseFormBody(raw) {
286
278
  }
287
279
  return result;
288
280
  }
289
- function registerOauth2Routes(fastify, deps) {
281
+ export function registerOauth2Routes(fastify, deps) {
290
282
  // Register a content-type parser for application/x-www-form-urlencoded so that
291
283
  // consent POST and token POST can read form bodies. @fastify/formbody is not in
292
284
  // the project's dependencies; we use URLSearchParams (Node built-in) instead.
@@ -303,7 +295,7 @@ function registerOauth2Routes(fastify, deps) {
303
295
  // the PWA service-worker navigate fallback, and the Vite dev proxy — no
304
296
  // per-path special-casing anywhere.
305
297
  fastify.get('/api/oauth2/authorize', async (request, reply) => {
306
- const cookie = request.cookies[session_cookie_js_1.SESSION_COOKIE];
298
+ const cookie = request.cookies[SESSION_COOKIE];
307
299
  const call = describeAuthorizeCall(request.url, request.headers, Boolean(cookie));
308
300
  if (!cookie) {
309
301
  return refuseUnauthenticated(request, reply, deps.logger, call, 'no-session-cookie');
@@ -341,8 +333,8 @@ function registerOauth2Routes(fastify, deps) {
341
333
  .status(400)
342
334
  .send({ error: 'invalid_request — redirect_uri not allowed for this integration' });
343
335
  }
344
- const html = (0, consent_page_js_1.renderConsentPage)({
345
- lang: (0, app_page_strings_js_1.resolveAppPageLang)({
336
+ const html = renderConsentPage({
337
+ lang: resolveAppPageLang({
346
338
  lang: request.query['lang'],
347
339
  acceptLanguage: request.headers['accept-language'],
348
340
  }),
@@ -401,7 +393,7 @@ function registerOauth2Routes(fastify, deps) {
401
393
  });
402
394
  // ─── POST /api/oauth2/authorize ───────────────────────────────────────────
403
395
  fastify.post('/api/oauth2/authorize', async (request, reply) => {
404
- const cookie = request.cookies[session_cookie_js_1.SESSION_COOKIE];
396
+ const cookie = request.cookies[SESSION_COOKIE];
405
397
  // `query` is empty here by nature, not by loss: the consent POST carries its
406
398
  // parameters as form fields. `method: POST` in the same line says so.
407
399
  const call = describeAuthorizeCall(request.url, request.headers, Boolean(cookie));
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Is this hostname unreachable from the public internet?
4
3
  *
@@ -15,8 +14,6 @@
15
14
  * not the one the browser will use). Names are admitted only by suffix, from a
16
15
  * closed list of suffixes that cannot be registered on the public internet.
17
16
  */
18
- Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.isPrivateHost = isPrivateHost;
20
17
  /** Suffixes that are, by definition, not publicly routable names. */
21
18
  const PRIVATE_NAME_SUFFIXES = ['.local', '.internal', '.home.arpa', '.ts.net'];
22
19
  /** Names that are exactly the loopback host. */
@@ -67,7 +64,7 @@ function isPrivateIpv6(host) {
67
64
  * True iff `host` (a `URL.hostname`, already lowercased by the URL parser) is
68
65
  * private by literal inspection. Never resolves.
69
66
  */
70
- function isPrivateHost(host) {
67
+ export function isPrivateHost(host) {
71
68
  if (host === '')
72
69
  return false;
73
70
  if (LOOPBACK_NAMES.includes(host))