@camstack/server 1.2.594 → 1.2.596

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 (255) hide show
  1. package/dist/addon-root-inventory.js +50 -11
  2. package/dist/agent/addon-scan.js +44 -6
  3. package/dist/agent/agent-addon-runtime.js +8 -3
  4. package/dist/agent/agent-addon-updates.js +52 -12
  5. package/dist/agent/agent-cap-dispatch-service.js +5 -3
  6. package/dist/agent/agent-config.js +42 -7
  7. package/dist/agent/agent-deploy-swap.js +41 -5
  8. package/dist/agent/agent-group-runner.js +47 -8
  9. package/dist/agent/agent-http-auth.js +22 -10
  10. package/dist/agent/agent-http.js +113 -64
  11. package/dist/agent/agent-hub-addon-update.js +16 -10
  12. package/dist/agent/agent-hub-registration.js +7 -4
  13. package/dist/agent/agent-infra-capabilities.js +9 -5
  14. package/dist/agent/agent-json-file.js +42 -5
  15. package/dist/agent/agent-mesh-gate.js +8 -5
  16. package/dist/agent/agent-node-certificates.js +28 -25
  17. package/dist/agent/agent-pairing-local.js +47 -10
  18. package/dist/agent/agent-pairing-routes.js +20 -16
  19. package/dist/agent/agent-pairing-store.js +58 -18
  20. package/dist/agent/agent-reconnect.js +4 -1
  21. package/dist/agent/agent-service.js +71 -35
  22. package/dist/agent/agent-sniffing-listener.js +48 -11
  23. package/dist/agent/agent-undeploy.js +41 -5
  24. package/dist/agent/agent-update-routes.js +19 -14
  25. package/dist/agent/agent-update-service.js +80 -38
  26. package/dist/agent/apply-model-distribution.js +4 -1
  27. package/dist/agent/apply-stage-dev-uploads.js +9 -6
  28. package/dist/agent/derive-hub-url.js +8 -3
  29. package/dist/agent/fetch-bundle-from-hub.js +9 -6
  30. package/dist/agent/hubs-found.js +43 -6
  31. package/dist/agent/infra-boot-guard.js +4 -1
  32. package/dist/agent/infra-boot-plan.js +6 -2
  33. package/dist/agent/main.js +183 -148
  34. package/dist/agent/register-agent-cap-dispatch.js +6 -3
  35. package/dist/agent/serial-queue.js +7 -2
  36. package/dist/agent-status-page.js +4 -1
  37. package/dist/api/addon-upload.js +61 -22
  38. package/dist/api/agent-addon-delivery.js +11 -6
  39. package/dist/api/auth-whoami.js +4 -1
  40. package/dist/api/backup-download-pump.js +9 -5
  41. package/dist/api/backup-download.js +10 -7
  42. package/dist/api/core/addon-settings.router.js +19 -16
  43. package/dist/api/core/agent-pairing.router.js +79 -76
  44. package/dist/api/core/agents.router.js +24 -21
  45. package/dist/api/core/auth-admin-tokens.procedures.js +52 -48
  46. package/dist/api/core/auth-device-cert.procedures.js +67 -62
  47. package/dist/api/core/auth-limits.js +25 -16
  48. package/dist/api/core/auth-reauth.procedures.js +37 -32
  49. package/dist/api/core/auth-revoke-credentials.procedures.js +26 -22
  50. package/dist/api/core/auth-sessions.procedures.js +56 -52
  51. package/dist/api/core/auth.router.js +304 -300
  52. package/dist/api/core/cap-providers.js +121 -74
  53. package/dist/api/core/capabilities.router.js +37 -34
  54. package/dist/api/core/capability-preference-writes.js +17 -10
  55. package/dist/api/core/certificates.router.js +109 -106
  56. package/dist/api/core/cluster-nodes.router.js +18 -15
  57. package/dist/api/core/collection-preference.js +6 -2
  58. package/dist/api/core/event-bus-proxy.router.js +37 -34
  59. package/dist/api/core/failure-contributions.js +8 -4
  60. package/dist/api/core/hwaccel.router.js +20 -17
  61. package/dist/api/core/integration-secrets.js +12 -8
  62. package/dist/api/core/lifecycle-job-runner.js +49 -13
  63. package/dist/api/core/live-events.router.js +32 -29
  64. package/dist/api/core/load-contributions.js +8 -4
  65. package/dist/api/core/logging-settings.js +43 -30
  66. package/dist/api/core/logs.router.js +43 -40
  67. package/dist/api/core/notifications.router.js +18 -15
  68. package/dist/api/core/public-event-filter.js +8 -4
  69. package/dist/api/core/repl.router.js +21 -18
  70. package/dist/api/core/request-census-settings.js +16 -11
  71. package/dist/api/core/server-management.provider.js +4 -1
  72. package/dist/api/core/server-name.js +17 -9
  73. package/dist/api/core/site-location.js +24 -16
  74. package/dist/api/core/stream-probe.router.js +24 -21
  75. package/dist/api/core/system-events.router.js +26 -23
  76. package/dist/api/cors/cors-policy.js +29 -20
  77. package/dist/api/cors/register-cors-policy.js +14 -9
  78. package/dist/api/deploy-stage-registry.js +10 -6
  79. package/dist/api/dev-uploads-bundle.js +50 -12
  80. package/dist/api/health/adaptive-probe.routes.js +13 -9
  81. package/dist/api/health/health.routes.js +13 -8
  82. package/dist/api/hub-cluster-url.js +9 -3
  83. package/dist/api/model-distributor.js +50 -12
  84. package/dist/api/oauth2/consent-page.js +13 -10
  85. package/dist/api/oauth2/oauth2-routes.js +25 -17
  86. package/dist/api/oauth2/private-host.js +4 -1
  87. package/dist/api/server-upload-propagate.js +51 -15
  88. package/dist/api/server-upload.js +50 -13
  89. package/dist/api/sse-no-compression.js +4 -1
  90. package/dist/api/static/frame-policy.js +9 -4
  91. package/dist/api/static/precompressed-asset.js +57 -15
  92. package/dist/api/static/spa-mount.js +47 -8
  93. package/dist/api/static/spa-static.js +12 -5
  94. package/dist/api/tarball-manifest.js +44 -7
  95. package/dist/api/trpc/cap-mount-helpers.js +12 -7
  96. package/dist/api/trpc/cap-route-error-formatter.js +13 -10
  97. package/dist/api/trpc/cap-router-runtime.js +51 -40
  98. package/dist/api/trpc/client-ip.js +20 -9
  99. package/dist/api/trpc/core-cap-bridge.js +42 -32
  100. package/dist/api/trpc/device-collection-dispatch.js +27 -23
  101. package/dist/api/trpc/device-config-secret-redaction.js +40 -24
  102. package/dist/api/trpc/generated-cap-mounts.js +225 -219
  103. package/dist/api/trpc/generated-cap-routers.js +5167 -4852
  104. package/dist/api/trpc/http-request-census-hook.js +11 -8
  105. package/dist/api/trpc/http-request-census.js +41 -34
  106. package/dist/api/trpc/http-request-census.singleton.js +8 -4
  107. package/dist/api/trpc/localized-schema-paths.js +4 -1
  108. package/dist/api/trpc/principal-visibility.js +22 -14
  109. package/dist/api/trpc/remote-addon-update-grant.js +4 -1
  110. package/dist/api/trpc/scope-access.js +15 -10
  111. package/dist/api/trpc/server-provided-caps.js +7 -3
  112. package/dist/api/trpc/share-view-access.js +14 -6
  113. package/dist/api/trpc/trpc-error-device-tags.js +6 -3
  114. package/dist/api/trpc/trpc-error-principal.js +6 -2
  115. package/dist/api/trpc/trpc.context.js +25 -20
  116. package/dist/api/trpc/trpc.middleware.js +46 -38
  117. package/dist/api/trpc/trpc.router.js +99 -58
  118. package/dist/api/trpc/user-error.js +8 -5
  119. package/dist/api/trpc/ws-request-census.js +24 -17
  120. package/dist/api/trpc/ws-slow-consumer-guard.js +16 -11
  121. package/dist/api/upload-auth.js +9 -5
  122. package/dist/auth/addon-route-jwt-gate.js +7 -4
  123. package/dist/auth/addon-route-share-gate.js +12 -7
  124. package/dist/auth/app-confirm-page.js +22 -17
  125. package/dist/auth/app-confirm-routes.js +31 -26
  126. package/dist/auth/app-confirmations.js +44 -7
  127. package/dist/auth/app-page-shell.js +30 -17
  128. package/dist/auth/app-page-strings.js +17 -11
  129. package/dist/auth/app-passkey-page.js +21 -16
  130. package/dist/auth/app-passkey-routes.js +41 -37
  131. package/dist/auth/app-refused-route.js +18 -13
  132. package/dist/auth/auth-network-policy.js +15 -11
  133. package/dist/auth/auth-provider-gate.js +9 -4
  134. package/dist/auth/auth-rate-limit.js +7 -3
  135. package/dist/auth/client-address.js +9 -6
  136. package/dist/auth/device-enroll-proofs.js +43 -6
  137. package/dist/auth/external-link-intents.js +7 -3
  138. package/dist/auth/hub-sessions.js +12 -6
  139. package/dist/auth/native-link-completions.js +11 -7
  140. package/dist/auth/native-return.js +13 -9
  141. package/dist/auth/passkey-provider.js +32 -26
  142. package/dist/auth/second-factors.js +10 -6
  143. package/dist/auth/session-connections.js +12 -6
  144. package/dist/auth/session-cookie.js +23 -12
  145. package/dist/auth/session-lifetimes.js +12 -8
  146. package/dist/auth/session-mint.js +11 -4
  147. package/dist/auth/sso-finish-app.js +16 -13
  148. package/dist/auth/sso-finish-deps.js +27 -21
  149. package/dist/auth/sso-finish.js +38 -28
  150. package/dist/auth/sso-routes.js +25 -22
  151. package/dist/auth/used-bridge-ids.js +5 -1
  152. package/dist/boot/boot-config.js +55 -16
  153. package/dist/boot/init-sequence.js +4 -1
  154. package/dist/boot/integration-id-backfill.js +8 -3
  155. package/dist/boot/platform-keychain-key.js +42 -5
  156. package/dist/boot/post-boot.service.js +18 -14
  157. package/dist/boot/reconcile-lifecycle-jobs.js +6 -3
  158. package/dist/boot/retired-public-url-env.js +8 -4
  159. package/dist/bootstrap-packages.js +4 -1
  160. package/dist/closure-node-modules.js +38 -2
  161. package/dist/core/addon/addon-call-gateway.js +5 -1
  162. package/dist/core/addon/addon-package.service.js +123 -83
  163. package/dist/core/addon/addon-process-view.js +6 -2
  164. package/dist/core/addon/addon-realign-plan.js +4 -1
  165. package/dist/core/addon/addon-registry.service.js +187 -146
  166. package/dist/core/addon/addon-row-manifest.js +4 -1
  167. package/dist/core/addon/addon-search.service.js +7 -3
  168. package/dist/core/addon/addon-settings-provider.js +3 -1
  169. package/dist/core/addon/addon-uninstall.js +11 -4
  170. package/dist/core/addon/addon.tokens.js +5 -2
  171. package/dist/core/addon/device-meta-mirror.js +13 -8
  172. package/dist/core/addon/forked-custom-actions.js +11 -6
  173. package/dist/core/addon/integration-visibility.js +6 -3
  174. package/dist/core/addon/materialize-route-path.js +4 -1
  175. package/dist/core/addon/package-dir-utils.js +45 -8
  176. package/dist/core/addon/prune-misplaced-addons.js +43 -5
  177. package/dist/core/addon/runner-convergence.js +4 -1
  178. package/dist/core/addon/runner-serialization.js +4 -1
  179. package/dist/core/addon/runner-spawn-fanout.js +8 -3
  180. package/dist/core/addon/settings-door-wiring.js +8 -5
  181. package/dist/core/addon/single-flight-refresh.js +4 -1
  182. package/dist/core/addon-bridge/addon-bridge.service.js +44 -7
  183. package/dist/core/addon-pages/addon-pages.service.js +40 -3
  184. package/dist/core/addon-widgets/addon-widgets.service.js +42 -4
  185. package/dist/core/agent/agent-addon-backfill.js +17 -9
  186. package/dist/core/agent/agent-delivery-ledger.js +7 -3
  187. package/dist/core/agent/agent-liveness-event.js +6 -2
  188. package/dist/core/agent/agent-pairing-http.js +45 -41
  189. package/dist/core/agent/agent-registry.service.js +89 -50
  190. package/dist/core/agent/cluster-node-history-mirror.js +7 -3
  191. package/dist/core/agent/cluster-node-history-store.js +35 -31
  192. package/dist/core/agent/hub-agent-pairing.js +5 -1
  193. package/dist/core/agent/node-certificates-client.js +6 -3
  194. package/dist/core/agent/node-directory.js +4 -1
  195. package/dist/core/app-links/well-known-app-links.js +6 -2
  196. package/dist/core/auth/auth.service.js +8 -3
  197. package/dist/core/auth/handoff-code.service.js +49 -11
  198. package/dist/core/auth/record-kinds.js +19 -16
  199. package/dist/core/auth/share-token.service.js +79 -42
  200. package/dist/core/capability/capability.service.js +5 -1
  201. package/dist/core/config/config.schema.js +6 -1
  202. package/dist/core/config/config.service.js +6 -2
  203. package/dist/core/events/event-bus.service.js +7 -3
  204. package/dist/core/feature/feature.service.js +6 -2
  205. package/dist/core/lifecycle/lifecycle-runner.singleton.js +10 -5
  206. package/dist/core/lifecycle/lifecycle-state-machine.js +5 -1
  207. package/dist/core/logging/log-ring-buffer.js +5 -1
  208. package/dist/core/logging/logging.service.js +9 -5
  209. package/dist/core/logging/scoped-logger.js +5 -1
  210. package/dist/core/moleculer/agent-readiness-pull.js +4 -1
  211. package/dist/core/moleculer/agent-registration-request.js +7 -3
  212. package/dist/core/moleculer/cap-call-fn.js +7 -4
  213. package/dist/core/moleculer/cap-route-authority.js +8 -3
  214. package/dist/core/moleculer/hub-mesh-guard.js +9 -5
  215. package/dist/core/moleculer/moleculer.service.js +86 -79
  216. package/dist/core/network/network-quality.service.js +6 -2
  217. package/dist/core/notification/notification-wrapper.service.js +7 -3
  218. package/dist/core/notification/toast-wrapper.service.js +7 -3
  219. package/dist/core/provider/provider.tokens.js +4 -1
  220. package/dist/core/repl/repl-engine.service.js +8 -4
  221. package/dist/core/runner-health/runner-boot-check.js +15 -7
  222. package/dist/core/runner-health/update-preflight.js +14 -9
  223. package/dist/core/server-update/server-update.service.js +49 -12
  224. package/dist/core/server-update/system-apply-closure-patches.js +42 -6
  225. package/dist/core/server-update/system-ensure-prebuilds.js +6 -3
  226. package/dist/core/server-update/system-exec-npm.js +5 -2
  227. package/dist/core/storage/fs-storage-backend.js +5 -1
  228. package/dist/core/storage/storage-location-manager.js +5 -1
  229. package/dist/core/storage/storage.service.js +6 -2
  230. package/dist/core/streaming/ffmpeg-stream-info.js +8 -3
  231. package/dist/core/streaming/stream-probe.service.js +16 -12
  232. package/dist/core/streaming/ttl-cache.js +5 -1
  233. package/dist/core/topology/topology-emitter.service.js +23 -19
  234. package/dist/core/update-availability-emitter.js +7 -3
  235. package/dist/core/update-availability-store.js +45 -8
  236. package/dist/core/updates/agent-installed-packages.js +9 -5
  237. package/dist/core/updates/restart-marker.js +8 -3
  238. package/dist/core/updates/update-check-scheduler.js +18 -13
  239. package/dist/core/updates/wrapper-update-checker.js +7 -3
  240. package/dist/first-boot-addon-plan.js +6 -2
  241. package/dist/framework-nodepath.js +38 -2
  242. package/dist/i18n/request-lang.js +11 -7
  243. package/dist/launcher.js +65 -30
  244. package/dist/lifecycle-journal-path.js +38 -2
  245. package/dist/main.js +324 -286
  246. package/dist/manual-boot.js +156 -117
  247. package/dist/node-role.js +4 -1
  248. package/dist/package-inventory.js +48 -7
  249. package/dist/pending-restore.js +43 -7
  250. package/dist/single-copy-cleanup-runner.js +45 -9
  251. package/dist/single-copy-cleanup.js +15 -7
  252. package/dist/sqlite-restore.js +48 -9
  253. package/dist/starter.js +39 -4
  254. package/dist/ui-serving/lazy-ui-serving.js +39 -3
  255. package/package.json +7 -7
@@ -1,3 +1,41 @@
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;
1
39
  /**
2
40
  * Pack / unpack a hub `server-root/dev-uploads/<version>/` directory for
3
41
  * agent fan-out (`POST /api/server-upload/propagate` → `$agent.stageDevUploads`).
@@ -5,15 +43,15 @@
5
43
  * One gzipped tar carries every tarball + `manifest.json`. Fail-closed on
6
44
  * path traversal and on a layout that would not satisfy RootUpdateService.
7
45
  */
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';
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");
13
51
  /** Version chars safe as a single path segment (matches server-upload). */
14
52
  const SAFE_VERSION_RE = /^[0-9A-Za-z][0-9A-Za-z.-]*$/;
15
- export function isSafeDevUploadVersion(version) {
16
- return SAFE_VERSION_RE.test(version) && isDevChannelVersion(version);
53
+ function isSafeDevUploadVersion(version) {
54
+ return SAFE_VERSION_RE.test(version) && (0, index_js_1.isDevChannelVersion)(version);
17
55
  }
18
56
  function hasPathTraversal(name) {
19
57
  return name.includes('/') || name.includes('\\') || name.includes('..');
@@ -22,8 +60,8 @@ function hasPathTraversal(name) {
22
60
  * Pack every file in `versionDir` (basename entries only) into a gzipped tar.
23
61
  * Refuses if the manifest is missing/invalid or lists a missing tarball.
24
62
  */
25
- export async function packDevUploadVersionDir(versionDir) {
26
- const manifest = readDevUploadManifest(versionDir);
63
+ async function packDevUploadVersionDir(versionDir) {
64
+ const manifest = (0, index_js_1.readDevUploadManifest)(versionDir);
27
65
  if (manifest === null) {
28
66
  throw new Error(`dev-uploads manifest missing or invalid in ${versionDir}`);
29
67
  }
@@ -36,7 +74,7 @@ export async function packDevUploadVersionDir(versionDir) {
36
74
  throw new Error(`dev-uploads tarball listed in manifest is missing: ${filename}`);
37
75
  }
38
76
  }
39
- if (!fs.existsSync(path.join(versionDir, DEV_UPLOAD_MANIFEST_FILE))) {
77
+ if (!fs.existsSync(path.join(versionDir, index_js_1.DEV_UPLOAD_MANIFEST_FILE))) {
40
78
  throw new Error(`dev-uploads manifest file missing in ${versionDir}`);
41
79
  }
42
80
  const entries = fs.readdirSync(versionDir).filter((name) => {
@@ -62,7 +100,7 @@ export async function packDevUploadVersionDir(versionDir) {
62
100
  * atomically (stage sibling + rename). Validates version shape, entry names,
63
101
  * and that the extracted layout matches the manifest.
64
102
  */
65
- export async function unpackDevUploadVersionBundle(args) {
103
+ async function unpackDevUploadVersionBundle(args) {
66
104
  const { serverRoot, version, bundle } = args;
67
105
  if (!isSafeDevUploadVersion(version)) {
68
106
  throw new Error(`Refused: version "${version}" is not a safe dev-channel version for staging`);
@@ -94,7 +132,7 @@ export async function unpackDevUploadVersionBundle(args) {
94
132
  if (refusedEntry !== null) {
95
133
  throw new Error(`Refused: archive entry is not a basename: ${refusedEntry}`);
96
134
  }
97
- const manifest = readDevUploadManifest(stagingDir);
135
+ const manifest = (0, index_js_1.readDevUploadManifest)(stagingDir);
98
136
  if (manifest === null) {
99
137
  throw new Error('extracted archive has no valid manifest.json');
100
138
  }
@@ -1,3 +1,7 @@
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;
1
5
  /**
2
6
  * Burst blob for adaptive-tier downlink measurement (D635).
3
7
  *
@@ -20,16 +24,16 @@
20
24
  * check the stream data plane applies — and is rate-limited per client IP.
21
25
  * Everything a refusal returns is a few bytes.
22
26
  */
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;
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;
27
31
  /**
28
32
  * Probes a client IP may draw per minute: 12. The client probes at most once
29
33
  * per 30 s per app (single-flight + cache), so 12 leaves room for several
30
34
  * apps/devices behind one NAT and caps an abuser at 12 MiB/min.
31
35
  */
32
- export const ADAPTIVE_PROBE_PER_IP_PER_MINUTE = 12;
36
+ exports.ADAPTIVE_PROBE_PER_IP_PER_MINUTE = 12;
33
37
  /**
34
38
  * Random, so it is INCOMPRESSIBLE. The previous body was one repeated byte and
35
39
  * `@fastify/compress` (global in `main.ts`; its default types include
@@ -37,11 +41,11 @@ export const ADAPTIVE_PROBE_PER_IP_PER_MINUTE = 12;
37
41
  * trip and called it bandwidth. `compress: false` below stops our own
38
42
  * compressor; randomness also defeats one in a relay on the way.
39
43
  */
40
- const BODY = randomBytes(ADAPTIVE_PROBE_BYTES);
41
- export function registerAdaptiveProbeRoute(fastify, deps) {
44
+ const BODY = (0, node_crypto_1.randomBytes)(exports.ADAPTIVE_PROBE_BYTES);
45
+ function registerAdaptiveProbeRoute(fastify, deps) {
42
46
  fastify.get('/adaptive-probe', { compress: false }, async (req, reply) => {
43
47
  reply.header('cache-control', 'no-store');
44
- const authorized = isAuthorizedHealthRequest({
48
+ const authorized = (0, health_routes_js_1.isAuthorizedHealthRequest)({
45
49
  ...(typeof req.headers.authorization === 'string'
46
50
  ? { authorization: req.headers.authorization }
47
51
  : {}),
@@ -49,7 +53,7 @@ export function registerAdaptiveProbeRoute(fastify, deps) {
49
53
  }, deps.verifyToken);
50
54
  if (!authorized)
51
55
  return reply.status(401).send({ ok: false, error: 'unauthorized' });
52
- const key = clientKeyFromRequest(req, deps.network);
56
+ const key = (0, auth_rate_limit_js_1.clientKeyFromRequest)(req, deps.network);
53
57
  if (key !== null) {
54
58
  const verdict = deps.limiter.check(`adaptive-probe:${key}`);
55
59
  if (!verdict.allowed) {
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Health endpoints — fast probe surface for monitoring (k8s, uptime,
3
4
  * external watchdogs).
@@ -18,13 +19,17 @@
18
19
  * monitors talking to the hub and monitors talking directly to an agent
19
20
  * (`http://<agent>:4444/health`) see identical payloads.
20
21
  */
21
- import { isRunnerBootCheckDegraded } from '../../core/runner-health/runner-boot-check.js';
22
- import { isSessionGradeJwtPayload, readSessionCookieFromHeader } from '../../auth/session-cookie.js';
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");
23
28
  const AGENT_HEALTH_TIMEOUT_MS = 3_000;
24
29
  function nowIso() {
25
30
  return new Date().toISOString();
26
31
  }
27
- export async function buildHubHealth(deps, proc = process) {
32
+ async function buildHubHealth(deps, proc = process) {
28
33
  // Fan-out-free: in-memory registry snapshot only, never a per-node RPC (#26).
29
34
  const nodes = deps.agentRegistry.listNodeLiveness();
30
35
  const remote = nodes.filter((n) => !n.isHub);
@@ -35,7 +40,7 @@ export async function buildHubHealth(deps, proc = process) {
35
40
  const runners = check === undefined
36
41
  ? undefined
37
42
  : {
38
- degraded: isRunnerBootCheckDegraded(check),
43
+ degraded: (0, runner_boot_check_js_1.isRunnerBootCheckDegraded)(check),
39
44
  expected: check.expected,
40
45
  running: check.running,
41
46
  failed: check.failed.length,
@@ -85,16 +90,16 @@ async function fetchAgentHealth(deps, nodeId) {
85
90
  * (agent ids, versions, pids) — public probes get only `{ok}`.
86
91
  * Pure over (headers, verifier) so the spec exercises it directly.
87
92
  */
88
- export function isAuthorizedHealthRequest(headers, verifyToken) {
93
+ function isAuthorizedHealthRequest(headers, verifyToken) {
89
94
  const bearer = headers.authorization?.startsWith('Bearer ')
90
95
  ? headers.authorization.slice('Bearer '.length)
91
96
  : null;
92
- const cookieToken = readSessionCookieFromHeader(headers.cookie);
97
+ const cookieToken = (0, session_cookie_js_1.readSessionCookieFromHeader)(headers.cookie);
93
98
  for (const token of [bearer, cookieToken]) {
94
99
  if (!token)
95
100
  continue;
96
101
  try {
97
- if (isSessionGradeJwtPayload(verifyToken(token)))
102
+ if ((0, session_cookie_js_1.isSessionGradeJwtPayload)(verifyToken(token)))
98
103
  return true;
99
104
  }
100
105
  catch {
@@ -103,7 +108,7 @@ export function isAuthorizedHealthRequest(headers, verifyToken) {
103
108
  }
104
109
  return false;
105
110
  }
106
- export function registerHealthRoutes(fastify, deps) {
111
+ function registerHealthRoutes(fastify, deps) {
107
112
  const authorized = (req) => isAuthorizedHealthRequest({
108
113
  ...(typeof req.headers.authorization === 'string'
109
114
  ? { authorization: req.headers.authorization }
@@ -1,5 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HubAddressUnavailableError = void 0;
4
+ exports.resolveHubBaseUrl = resolveHubBaseUrl;
5
+ exports.clusterBaseUrlResolver = clusterBaseUrlResolver;
1
6
  /** Thrown when the hub cannot name an address `audience` can reach. */
2
- export class HubAddressUnavailableError extends Error {
7
+ class HubAddressUnavailableError extends Error {
3
8
  audience;
4
9
  reason;
5
10
  constructor(audience, reason) {
@@ -12,12 +17,13 @@ export class HubAddressUnavailableError extends Error {
12
17
  this.name = 'HubAddressUnavailableError';
13
18
  }
14
19
  }
20
+ exports.HubAddressUnavailableError = HubAddressUnavailableError;
15
21
  /**
16
22
  * Resolve the hub's base URL for `audience` from the live provider. Called per
17
23
  * delivery — interfaces and the allowlist move, and a deploy is rare enough
18
24
  * that a cache would only add a way to be stale.
19
25
  */
20
- export async function resolveHubBaseUrl(getSource, audience) {
26
+ async function resolveHubBaseUrl(getSource, audience) {
21
27
  const source = getSource();
22
28
  if (source === null)
23
29
  throw new HubAddressUnavailableError(audience, 'local-network-unavailable');
@@ -26,6 +32,6 @@ export async function resolveHubBaseUrl(getSource, audience) {
26
32
  throw new HubAddressUnavailableError(audience, 'no-reachable-endpoint');
27
33
  return baseUrl;
28
34
  }
29
- export function clusterBaseUrlResolver(getSource) {
35
+ function clusterBaseUrlResolver(getSource) {
30
36
  return () => resolveHubBaseUrl(getSource, 'internal');
31
37
  }
@@ -1,8 +1,46 @@
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';
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");
6
44
  const AGENT_DISTRIBUTE_TIMEOUT_MS = 60_000;
7
45
  function hubModelsDir() {
8
46
  return path.join(process.env['CAMSTACK_DATA'] ?? 'camstack-data', 'models');
@@ -12,9 +50,9 @@ function hubModelsDir() {
12
50
  * Async (spawn, not execFileSync) so a large model doesn't block the event
13
51
  * loop. The agent untars this exact buffer into its own modelsDir.
14
52
  */
15
- export function tarModelFiles(cwd, files) {
53
+ function tarModelFiles(cwd, files) {
16
54
  return new Promise((resolve, reject) => {
17
- const child = spawn('tar', ['-czf', '-', '-C', cwd, ...files]);
55
+ const child = (0, node_child_process_1.spawn)('tar', ['-czf', '-', '-C', cwd, ...files]);
18
56
  const chunks = [];
19
57
  const errChunks = [];
20
58
  child.stdout.on('data', (c) => chunks.push(c));
@@ -33,7 +71,7 @@ export function tarModelFiles(cwd, files) {
33
71
  * precondition-check → collect → tar → stage → trigger the agent pull.
34
72
  * `nodeId === 'hub'` is a no-op (the artifact is already resident).
35
73
  */
36
- export async function distributeModelWith(seam, input) {
74
+ async function distributeModelWith(seam, input) {
37
75
  const { targetNodeId, modelId, format, entry } = input;
38
76
  if (targetNodeId === 'hub') {
39
77
  return { ok: true, sha256: '', bytes: 0, path: seam.modelsDir };
@@ -41,7 +79,7 @@ export async function distributeModelWith(seam, input) {
41
79
  if (!seam.isPresent(entry, format)) {
42
80
  throw new Error(`model ${modelId}/${format} not present on hub — download or convert it first`);
43
81
  }
44
- const files = collectModelFiles(entry, format).filter((f) => seam.fileExists(f));
82
+ const files = (0, system_1.collectModelFiles)(entry, format).filter((f) => seam.fileExists(f));
45
83
  if (files.length === 0) {
46
84
  throw new Error(`model ${modelId}/${format} resolved no files to distribute`);
47
85
  }
@@ -56,17 +94,17 @@ export async function distributeModelWith(seam, input) {
56
94
  * Moleculer broker + the deploy-stage registry, which a forked addon can't
57
95
  * reach.
58
96
  */
59
- export function buildModelDistributorProvider(moleculer, loggingService,
97
+ function buildModelDistributorProvider(moleculer, loggingService,
60
98
  /** The `local-network` cap's cluster address (`hub-cluster-url.ts`). */
61
99
  resolveClusterBaseUrl) {
62
100
  const logger = loggingService.createLogger('model-distributor');
63
101
  const modelsDir = hubModelsDir();
64
102
  const seam = {
65
103
  modelsDir,
66
- isPresent: (entry, format) => isModelDownloaded(modelsDir, entry, format),
104
+ isPresent: (entry, format) => (0, system_1.isModelDownloaded)(modelsDir, entry, format),
67
105
  fileExists: (rel) => fs.existsSync(path.join(modelsDir, rel)),
68
106
  tar: (files) => tarModelFiles(modelsDir, files),
69
- stage: async (buffer) => buildHubHttpSource(buffer, await resolveClusterBaseUrl()),
107
+ stage: async (buffer) => (0, addon_upload_js_1.buildHubHttpSource)(buffer, await resolveClusterBaseUrl()),
70
108
  callAgent: async (nodeId, payload) => {
71
109
  const broker = moleculer?.broker;
72
110
  if (!broker)
@@ -1,25 +1,28 @@
1
- import { appHiddenField, appHint, appSubmitButton, escapeHtml, renderAppPage, } from '../../auth/app-page-shell.js';
2
- import { appStrings } from '../../auth/app-page-strings.js';
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");
3
6
  /** Allow/Deny consent screen on the hub's shared page shell (the look of the
4
7
  * app sign-in pages). Submitting POSTs to the same path with the hidden query
5
8
  * fields + `consent=allow|deny`. */
6
- export function renderConsentPage(input) {
9
+ function renderConsentPage(input) {
7
10
  const hidden = Object.entries(input.hidden)
8
- .map(([name, value]) => appHiddenField(name, value))
11
+ .map(([name, value]) => (0, app_page_shell_js_1.appHiddenField)(name, value))
9
12
  .join('');
10
- const t = appStrings(input.lang).consent;
13
+ const t = (0, app_page_strings_js_1.appStrings)(input.lang).consent;
11
14
  const destination = input.redirectUri
12
- ? `<p class="hint">${escapeHtml(t.sendingTo)}<code>${escapeHtml(input.redirectUri)}</code></p>`
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>`
13
16
  : '';
14
- return renderAppPage({
17
+ return (0, app_page_shell_js_1.renderAppPage)({
15
18
  lang: input.lang,
16
19
  title: `${t.titlePrefix}${input.displayName}`,
17
20
  heading: `${t.headingPrefix}${input.displayName}`,
18
21
  body: [
19
- `<p>${escapeHtml(t.signedInAs)}<strong>${escapeHtml(input.username)}</strong></p>`,
20
- appHint(`${t.grantPrefix}${input.scopeSummary}`),
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}`),
21
24
  destination,
22
- `<form method="POST">${hidden}<div class="actions">${appSubmitButton(t.allow, 'consent', 'allow')}${appSubmitButton(t.deny, 'consent', 'deny', true)}</div></form>`,
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>`,
23
26
  ].join(''),
24
27
  });
25
28
  }
@@ -1,7 +1,15 @@
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';
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");
5
13
  /**
6
14
  * Query keys whose VALUE may be logged.
7
15
  *
@@ -26,7 +34,7 @@ function truncate(value, max) {
26
34
  return value.length > max ? `${value.slice(0, max)}…` : value;
27
35
  }
28
36
  /** Rebuild a query string with every non-allow-listed value replaced. */
29
- export function redactAuthorizeQuery(rawQuery) {
37
+ function redactAuthorizeQuery(rawQuery) {
30
38
  if (rawQuery === '')
31
39
  return '';
32
40
  const parts = [];
@@ -49,7 +57,7 @@ function describeReferer(raw) {
49
57
  }
50
58
  }
51
59
  /** Everything the log is allowed to know about an inbound authorize call. */
52
- export function describeAuthorizeCall(url, headers, hasSessionCookie) {
60
+ function describeAuthorizeCall(url, headers, hasSessionCookie) {
53
61
  const q = url.indexOf('?');
54
62
  const ua = headers['user-agent'];
55
63
  return {
@@ -110,7 +118,7 @@ function resolveIntegrationParam(raw) {
110
118
  * NOT checked — that pair is verified only at the Lambda boundary, and a
111
119
  * PUBLIC client (`requiresPkce`) has no secret to check it against at all;
112
120
  * the S256 challenge is what binds the code to its requester instead. */
113
- export function validateAuthorizeQuery(q, knownIntegrations, pendingAddons = []) {
121
+ function validateAuthorizeQuery(q, knownIntegrations, pendingAddons = []) {
114
122
  if (q.response_type !== 'code')
115
123
  return { ok: false, status: 400, error: 'unsupported_response_type' };
116
124
  // Four distinct faults used to collapse into one opaque string.
@@ -190,7 +198,7 @@ export function validateAuthorizeQuery(q, knownIntegrations, pendingAddons = [])
190
198
  * `startsWith` on a string the browser will parse differently is exactly how an
191
199
  * allow-list gets walked around.
192
200
  */
193
- export function isRedirectUriAllowed(redirectUri, allowedPrefixes, allowedPrivateHostPaths = []) {
201
+ function isRedirectUriAllowed(redirectUri, allowedPrefixes, allowedPrivateHostPaths = []) {
194
202
  if (allowedPrefixes.some((p) => redirectUri.startsWith(p)))
195
203
  return true;
196
204
  if (allowedPrivateHostPaths.length === 0)
@@ -204,12 +212,12 @@ export function isRedirectUriAllowed(redirectUri, allowedPrefixes, allowedPrivat
204
212
  }
205
213
  if (url.protocol !== 'http:' && url.protocol !== 'https:')
206
214
  return false;
207
- if (!isPrivateHost(url.hostname))
215
+ if (!(0, private_host_js_1.isPrivateHost)(url.hostname))
208
216
  return false;
209
217
  return allowedPrivateHostPaths.includes(url.pathname);
210
218
  }
211
219
  /** One-line human summary of a scope list for the consent screen. */
212
- export function summariseScopes(scopes) {
220
+ function summariseScopes(scopes) {
213
221
  if (scopes.some((s) => s.type === 'category' && s.target === 'device')) {
214
222
  return 'view and control all your cameras and devices';
215
223
  }
@@ -249,10 +257,10 @@ function refuseAuthorize(reply, logger, method, call, refusal) {
249
257
  * it" is invisible and every refusal reads as a first arrival.
250
258
  */
251
259
  function refuseUnauthenticated(request, reply, logger, call, reason) {
252
- const redirected = shouldRedirectToLogin(request.method, request.headers.accept);
260
+ const redirected = (0, session_cookie_js_1.shouldRedirectToLogin)(request.method, request.headers.accept);
253
261
  logger.info(redirected ? 'oauth2 authorize bounced to login' : 'oauth2 authorize refused: unauthenticated', { meta: { method: request.method, reason, redirected, ...call } });
254
262
  if (redirected)
255
- return reply.redirect(loginRedirectUrl(request.url));
263
+ return reply.redirect((0, session_cookie_js_1.loginRedirectUrl)(request.url));
256
264
  return reply.status(401).send({ error: 'unauthorized' });
257
265
  }
258
266
  /** Read integrationId → descriptor from every registered `oauth-integration`
@@ -278,7 +286,7 @@ function parseFormBody(raw) {
278
286
  }
279
287
  return result;
280
288
  }
281
- export function registerOauth2Routes(fastify, deps) {
289
+ function registerOauth2Routes(fastify, deps) {
282
290
  // Register a content-type parser for application/x-www-form-urlencoded so that
283
291
  // consent POST and token POST can read form bodies. @fastify/formbody is not in
284
292
  // the project's dependencies; we use URLSearchParams (Node built-in) instead.
@@ -295,7 +303,7 @@ export function registerOauth2Routes(fastify, deps) {
295
303
  // the PWA service-worker navigate fallback, and the Vite dev proxy — no
296
304
  // per-path special-casing anywhere.
297
305
  fastify.get('/api/oauth2/authorize', async (request, reply) => {
298
- const cookie = request.cookies[SESSION_COOKIE];
306
+ const cookie = request.cookies[session_cookie_js_1.SESSION_COOKIE];
299
307
  const call = describeAuthorizeCall(request.url, request.headers, Boolean(cookie));
300
308
  if (!cookie) {
301
309
  return refuseUnauthenticated(request, reply, deps.logger, call, 'no-session-cookie');
@@ -333,8 +341,8 @@ export function registerOauth2Routes(fastify, deps) {
333
341
  .status(400)
334
342
  .send({ error: 'invalid_request — redirect_uri not allowed for this integration' });
335
343
  }
336
- const html = renderConsentPage({
337
- lang: resolveAppPageLang({
344
+ const html = (0, consent_page_js_1.renderConsentPage)({
345
+ lang: (0, app_page_strings_js_1.resolveAppPageLang)({
338
346
  lang: request.query['lang'],
339
347
  acceptLanguage: request.headers['accept-language'],
340
348
  }),
@@ -393,7 +401,7 @@ export function registerOauth2Routes(fastify, deps) {
393
401
  });
394
402
  // ─── POST /api/oauth2/authorize ───────────────────────────────────────────
395
403
  fastify.post('/api/oauth2/authorize', async (request, reply) => {
396
- const cookie = request.cookies[SESSION_COOKIE];
404
+ const cookie = request.cookies[session_cookie_js_1.SESSION_COOKIE];
397
405
  // `query` is empty here by nature, not by loss: the consent POST carries its
398
406
  // parameters as form fields. `method: POST` in the same line says so.
399
407
  const call = describeAuthorizeCall(request.url, request.headers, Boolean(cookie));
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Is this hostname unreachable from the public internet?
3
4
  *
@@ -14,6 +15,8 @@
14
15
  * not the one the browser will use). Names are admitted only by suffix, from a
15
16
  * closed list of suffixes that cannot be registered on the public internet.
16
17
  */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.isPrivateHost = isPrivateHost;
17
20
  /** Suffixes that are, by definition, not publicly routable names. */
18
21
  const PRIVATE_NAME_SUFFIXES = ['.local', '.internal', '.home.arpa', '.ts.net'];
19
22
  /** Names that are exactly the loopback host. */
@@ -64,7 +67,7 @@ function isPrivateIpv6(host) {
64
67
  * True iff `host` (a `URL.hostname`, already lowercased by the URL parser) is
65
68
  * private by literal inspection. Never resolves.
66
69
  */
67
- export function isPrivateHost(host) {
70
+ function isPrivateHost(host) {
68
71
  if (host === '')
69
72
  return false;
70
73
  if (LOOPBACK_NAMES.includes(host))