@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.
- package/dist/addon-root-inventory.js +50 -11
- package/dist/agent/addon-scan.js +44 -6
- package/dist/agent/agent-addon-runtime.js +8 -3
- package/dist/agent/agent-addon-updates.js +52 -12
- package/dist/agent/agent-cap-dispatch-service.js +5 -3
- package/dist/agent/agent-config.js +42 -7
- package/dist/agent/agent-deploy-swap.js +41 -5
- package/dist/agent/agent-group-runner.js +47 -8
- package/dist/agent/agent-http-auth.js +22 -10
- package/dist/agent/agent-http.js +113 -64
- package/dist/agent/agent-hub-addon-update.js +16 -10
- package/dist/agent/agent-hub-registration.js +7 -4
- package/dist/agent/agent-infra-capabilities.js +9 -5
- package/dist/agent/agent-json-file.js +42 -5
- package/dist/agent/agent-mesh-gate.js +8 -5
- package/dist/agent/agent-node-certificates.js +28 -25
- package/dist/agent/agent-pairing-local.js +47 -10
- package/dist/agent/agent-pairing-routes.js +20 -16
- package/dist/agent/agent-pairing-store.js +58 -18
- package/dist/agent/agent-reconnect.js +4 -1
- package/dist/agent/agent-service.js +71 -35
- package/dist/agent/agent-sniffing-listener.js +48 -11
- package/dist/agent/agent-undeploy.js +41 -5
- package/dist/agent/agent-update-routes.js +19 -14
- package/dist/agent/agent-update-service.js +80 -38
- package/dist/agent/apply-model-distribution.js +4 -1
- package/dist/agent/apply-stage-dev-uploads.js +9 -6
- package/dist/agent/derive-hub-url.js +8 -3
- package/dist/agent/fetch-bundle-from-hub.js +9 -6
- package/dist/agent/hubs-found.js +43 -6
- package/dist/agent/infra-boot-guard.js +4 -1
- package/dist/agent/infra-boot-plan.js +6 -2
- package/dist/agent/main.js +183 -148
- package/dist/agent/register-agent-cap-dispatch.js +6 -3
- package/dist/agent/serial-queue.js +7 -2
- package/dist/agent-status-page.js +4 -1
- package/dist/api/addon-upload.js +61 -22
- package/dist/api/agent-addon-delivery.js +11 -6
- package/dist/api/auth-whoami.js +4 -1
- package/dist/api/backup-download-pump.js +9 -5
- package/dist/api/backup-download.js +10 -7
- package/dist/api/core/addon-settings.router.js +19 -16
- package/dist/api/core/agent-pairing.router.js +79 -76
- package/dist/api/core/agents.router.js +24 -21
- package/dist/api/core/auth-admin-tokens.procedures.js +52 -48
- package/dist/api/core/auth-device-cert.procedures.js +67 -62
- package/dist/api/core/auth-limits.js +25 -16
- package/dist/api/core/auth-reauth.procedures.js +37 -32
- package/dist/api/core/auth-revoke-credentials.procedures.js +26 -22
- package/dist/api/core/auth-sessions.procedures.js +56 -52
- package/dist/api/core/auth.router.js +304 -300
- package/dist/api/core/cap-providers.js +121 -74
- package/dist/api/core/capabilities.router.js +37 -34
- package/dist/api/core/capability-preference-writes.js +17 -10
- package/dist/api/core/certificates.router.js +109 -106
- package/dist/api/core/cluster-nodes.router.js +18 -15
- package/dist/api/core/collection-preference.js +6 -2
- package/dist/api/core/event-bus-proxy.router.js +37 -34
- package/dist/api/core/failure-contributions.js +8 -4
- package/dist/api/core/hwaccel.router.js +20 -17
- package/dist/api/core/integration-secrets.js +12 -8
- package/dist/api/core/lifecycle-job-runner.js +49 -13
- package/dist/api/core/live-events.router.js +32 -29
- package/dist/api/core/load-contributions.js +8 -4
- package/dist/api/core/logging-settings.js +43 -30
- package/dist/api/core/logs.router.js +43 -40
- package/dist/api/core/notifications.router.js +18 -15
- package/dist/api/core/public-event-filter.js +8 -4
- package/dist/api/core/repl.router.js +21 -18
- package/dist/api/core/request-census-settings.js +16 -11
- package/dist/api/core/server-management.provider.js +4 -1
- package/dist/api/core/server-name.js +17 -9
- package/dist/api/core/site-location.js +24 -16
- package/dist/api/core/stream-probe.router.js +24 -21
- package/dist/api/core/system-events.router.js +26 -23
- package/dist/api/cors/cors-policy.js +29 -20
- package/dist/api/cors/register-cors-policy.js +14 -9
- package/dist/api/deploy-stage-registry.js +10 -6
- package/dist/api/dev-uploads-bundle.js +50 -12
- package/dist/api/health/adaptive-probe.routes.js +13 -9
- package/dist/api/health/health.routes.js +13 -8
- package/dist/api/hub-cluster-url.js +9 -3
- package/dist/api/model-distributor.js +50 -12
- package/dist/api/oauth2/consent-page.js +13 -10
- package/dist/api/oauth2/oauth2-routes.js +25 -17
- package/dist/api/oauth2/private-host.js +4 -1
- package/dist/api/server-upload-propagate.js +51 -15
- package/dist/api/server-upload.js +50 -13
- package/dist/api/sse-no-compression.js +4 -1
- package/dist/api/static/frame-policy.js +9 -4
- package/dist/api/static/precompressed-asset.js +57 -15
- package/dist/api/static/spa-mount.js +47 -8
- package/dist/api/static/spa-static.js +12 -5
- package/dist/api/tarball-manifest.js +44 -7
- package/dist/api/trpc/cap-mount-helpers.js +12 -7
- package/dist/api/trpc/cap-route-error-formatter.js +13 -10
- package/dist/api/trpc/cap-router-runtime.js +51 -40
- package/dist/api/trpc/client-ip.js +20 -9
- package/dist/api/trpc/core-cap-bridge.js +42 -32
- package/dist/api/trpc/device-collection-dispatch.js +27 -23
- package/dist/api/trpc/device-config-secret-redaction.js +40 -24
- package/dist/api/trpc/generated-cap-mounts.js +225 -219
- package/dist/api/trpc/generated-cap-routers.js +5167 -4852
- package/dist/api/trpc/http-request-census-hook.js +11 -8
- package/dist/api/trpc/http-request-census.js +41 -34
- package/dist/api/trpc/http-request-census.singleton.js +8 -4
- package/dist/api/trpc/localized-schema-paths.js +4 -1
- package/dist/api/trpc/principal-visibility.js +22 -14
- package/dist/api/trpc/remote-addon-update-grant.js +4 -1
- package/dist/api/trpc/scope-access.js +15 -10
- package/dist/api/trpc/server-provided-caps.js +7 -3
- package/dist/api/trpc/share-view-access.js +14 -6
- package/dist/api/trpc/trpc-error-device-tags.js +6 -3
- package/dist/api/trpc/trpc-error-principal.js +6 -2
- package/dist/api/trpc/trpc.context.js +25 -20
- package/dist/api/trpc/trpc.middleware.js +46 -38
- package/dist/api/trpc/trpc.router.js +99 -58
- package/dist/api/trpc/user-error.js +8 -5
- package/dist/api/trpc/ws-request-census.js +24 -17
- package/dist/api/trpc/ws-slow-consumer-guard.js +16 -11
- package/dist/api/upload-auth.js +9 -5
- package/dist/auth/addon-route-jwt-gate.js +7 -4
- package/dist/auth/addon-route-share-gate.js +12 -7
- package/dist/auth/app-confirm-page.js +22 -17
- package/dist/auth/app-confirm-routes.js +31 -26
- package/dist/auth/app-confirmations.js +44 -7
- package/dist/auth/app-page-shell.js +30 -17
- package/dist/auth/app-page-strings.js +17 -11
- package/dist/auth/app-passkey-page.js +21 -16
- package/dist/auth/app-passkey-routes.js +41 -37
- package/dist/auth/app-refused-route.js +18 -13
- package/dist/auth/auth-network-policy.js +15 -11
- package/dist/auth/auth-provider-gate.js +9 -4
- package/dist/auth/auth-rate-limit.js +7 -3
- package/dist/auth/client-address.js +9 -6
- package/dist/auth/device-enroll-proofs.js +43 -6
- package/dist/auth/external-link-intents.js +7 -3
- package/dist/auth/hub-sessions.js +12 -6
- package/dist/auth/native-link-completions.js +11 -7
- package/dist/auth/native-return.js +13 -9
- package/dist/auth/passkey-provider.js +32 -26
- package/dist/auth/second-factors.js +10 -6
- package/dist/auth/session-connections.js +12 -6
- package/dist/auth/session-cookie.js +23 -12
- package/dist/auth/session-lifetimes.js +12 -8
- package/dist/auth/session-mint.js +11 -4
- package/dist/auth/sso-finish-app.js +16 -13
- package/dist/auth/sso-finish-deps.js +27 -21
- package/dist/auth/sso-finish.js +38 -28
- package/dist/auth/sso-routes.js +25 -22
- package/dist/auth/used-bridge-ids.js +5 -1
- package/dist/boot/boot-config.js +55 -16
- package/dist/boot/init-sequence.js +4 -1
- package/dist/boot/integration-id-backfill.js +8 -3
- package/dist/boot/platform-keychain-key.js +42 -5
- package/dist/boot/post-boot.service.js +18 -14
- package/dist/boot/reconcile-lifecycle-jobs.js +6 -3
- package/dist/boot/retired-public-url-env.js +8 -4
- package/dist/bootstrap-packages.js +4 -1
- package/dist/closure-node-modules.js +38 -2
- package/dist/core/addon/addon-call-gateway.js +5 -1
- package/dist/core/addon/addon-package.service.js +123 -83
- package/dist/core/addon/addon-process-view.js +6 -2
- package/dist/core/addon/addon-realign-plan.js +4 -1
- package/dist/core/addon/addon-registry.service.js +187 -146
- package/dist/core/addon/addon-row-manifest.js +4 -1
- package/dist/core/addon/addon-search.service.js +7 -3
- package/dist/core/addon/addon-settings-provider.js +3 -1
- package/dist/core/addon/addon-uninstall.js +11 -4
- package/dist/core/addon/addon.tokens.js +5 -2
- package/dist/core/addon/device-meta-mirror.js +13 -8
- package/dist/core/addon/forked-custom-actions.js +11 -6
- package/dist/core/addon/integration-visibility.js +6 -3
- package/dist/core/addon/materialize-route-path.js +4 -1
- package/dist/core/addon/package-dir-utils.js +45 -8
- package/dist/core/addon/prune-misplaced-addons.js +43 -5
- package/dist/core/addon/runner-convergence.js +4 -1
- package/dist/core/addon/runner-serialization.js +4 -1
- package/dist/core/addon/runner-spawn-fanout.js +8 -3
- package/dist/core/addon/settings-door-wiring.js +8 -5
- package/dist/core/addon/single-flight-refresh.js +4 -1
- package/dist/core/addon-bridge/addon-bridge.service.js +44 -7
- package/dist/core/addon-pages/addon-pages.service.js +40 -3
- package/dist/core/addon-widgets/addon-widgets.service.js +42 -4
- package/dist/core/agent/agent-addon-backfill.js +17 -9
- package/dist/core/agent/agent-delivery-ledger.js +7 -3
- package/dist/core/agent/agent-liveness-event.js +6 -2
- package/dist/core/agent/agent-pairing-http.js +45 -41
- package/dist/core/agent/agent-registry.service.js +89 -50
- package/dist/core/agent/cluster-node-history-mirror.js +7 -3
- package/dist/core/agent/cluster-node-history-store.js +35 -31
- package/dist/core/agent/hub-agent-pairing.js +5 -1
- package/dist/core/agent/node-certificates-client.js +6 -3
- package/dist/core/agent/node-directory.js +4 -1
- package/dist/core/app-links/well-known-app-links.js +6 -2
- package/dist/core/auth/auth.service.js +8 -3
- package/dist/core/auth/handoff-code.service.js +49 -11
- package/dist/core/auth/record-kinds.js +19 -16
- package/dist/core/auth/share-token.service.js +79 -42
- package/dist/core/capability/capability.service.js +5 -1
- package/dist/core/config/config.schema.js +6 -1
- package/dist/core/config/config.service.js +6 -2
- package/dist/core/events/event-bus.service.js +7 -3
- package/dist/core/feature/feature.service.js +6 -2
- package/dist/core/lifecycle/lifecycle-runner.singleton.js +10 -5
- package/dist/core/lifecycle/lifecycle-state-machine.js +5 -1
- package/dist/core/logging/log-ring-buffer.js +5 -1
- package/dist/core/logging/logging.service.js +9 -5
- package/dist/core/logging/scoped-logger.js +5 -1
- package/dist/core/moleculer/agent-readiness-pull.js +4 -1
- package/dist/core/moleculer/agent-registration-request.js +7 -3
- package/dist/core/moleculer/cap-call-fn.js +7 -4
- package/dist/core/moleculer/cap-route-authority.js +8 -3
- package/dist/core/moleculer/hub-mesh-guard.js +9 -5
- package/dist/core/moleculer/moleculer.service.js +86 -79
- package/dist/core/network/network-quality.service.js +6 -2
- package/dist/core/notification/notification-wrapper.service.js +7 -3
- package/dist/core/notification/toast-wrapper.service.js +7 -3
- package/dist/core/provider/provider.tokens.js +4 -1
- package/dist/core/repl/repl-engine.service.js +8 -4
- package/dist/core/runner-health/runner-boot-check.js +15 -7
- package/dist/core/runner-health/update-preflight.js +14 -9
- package/dist/core/server-update/server-update.service.js +49 -12
- package/dist/core/server-update/system-apply-closure-patches.js +42 -6
- package/dist/core/server-update/system-ensure-prebuilds.js +6 -3
- package/dist/core/server-update/system-exec-npm.js +5 -2
- package/dist/core/storage/fs-storage-backend.js +5 -1
- package/dist/core/storage/storage-location-manager.js +5 -1
- package/dist/core/storage/storage.service.js +6 -2
- package/dist/core/streaming/ffmpeg-stream-info.js +8 -3
- package/dist/core/streaming/stream-probe.service.js +16 -12
- package/dist/core/streaming/ttl-cache.js +5 -1
- package/dist/core/topology/topology-emitter.service.js +23 -19
- package/dist/core/update-availability-emitter.js +7 -3
- package/dist/core/update-availability-store.js +45 -8
- package/dist/core/updates/agent-installed-packages.js +9 -5
- package/dist/core/updates/restart-marker.js +8 -3
- package/dist/core/updates/update-check-scheduler.js +18 -13
- package/dist/core/updates/wrapper-update-checker.js +7 -3
- package/dist/first-boot-addon-plan.js +6 -2
- package/dist/framework-nodepath.js +38 -2
- package/dist/i18n/request-lang.js +11 -7
- package/dist/launcher.js +65 -30
- package/dist/lifecycle-journal-path.js +38 -2
- package/dist/main.js +324 -286
- package/dist/manual-boot.js +156 -117
- package/dist/node-role.js +4 -1
- package/dist/package-inventory.js +48 -7
- package/dist/pending-restore.js +43 -7
- package/dist/single-copy-cleanup-runner.js +45 -9
- package/dist/single-copy-cleanup.js +15 -7
- package/dist/sqlite-restore.js +48 -9
- package/dist/starter.js +39 -4
- package/dist/ui-serving/lazy-ui-serving.js +39 -3
- package/package.json +7 -7
package/dist/main.js
CHANGED
|
@@ -1,9 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/* eslint-disable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument -- pre-existing lint debt across this 800+ line bootstrap module. The flagged sites cross typed boundaries (Fastify request typing, AddonRouteRegistry, AuthService inherited methods) where the projectService context can't trace inheritance chains. Tracked separately; do not amend in unrelated edits. */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
+
};
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
const lazy_ui_serving_js_1 = require("./ui-serving/lazy-ui-serving.js");
|
|
41
|
+
const node_child_process_1 = require("node:child_process");
|
|
42
|
+
const fs = __importStar(require("node:fs"));
|
|
43
|
+
const path = __importStar(require("node:path"));
|
|
44
|
+
const node_tls_1 = require("node:tls");
|
|
7
45
|
// Boot-time capability declaration runs over the auto-generated
|
|
8
46
|
// `ALL_CAPABILITY_DEFINITIONS` array — every `*.cap.ts` file that ships
|
|
9
47
|
// with `@camstack/types` is included automatically. Adding a new cap
|
|
@@ -14,88 +52,88 @@ import { Server as TlsServer } from 'node:tls';
|
|
|
14
52
|
// Sourced from `@camstack/system` (not `@camstack/types`) so the hub's
|
|
15
53
|
// capability surface refreshes on `camstack deploy packages/system` with no new
|
|
16
54
|
// server image. `@camstack/types` is never deployed to the hub.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
55
|
+
const system_1 = require("@camstack/system");
|
|
56
|
+
const compress_1 = __importDefault(require("@fastify/compress"));
|
|
57
|
+
const cookie_1 = __importDefault(require("@fastify/cookie"));
|
|
58
|
+
const fastify_1 = require("@trpc/server/adapters/fastify");
|
|
59
|
+
const ws_1 = require("@trpc/server/adapters/ws");
|
|
60
|
+
const ws_2 = require("ws");
|
|
61
|
+
const addon_upload_1 = require("./api/addon-upload");
|
|
62
|
+
const auth_whoami_1 = require("./api/auth-whoami");
|
|
63
|
+
const backup_download_js_1 = require("./api/backup-download.js");
|
|
64
|
+
const cap_providers_1 = require("./api/core/cap-providers");
|
|
65
|
+
const logging_settings_1 = require("./api/core/logging-settings");
|
|
66
|
+
const request_census_settings_1 = require("./api/core/request-census-settings");
|
|
67
|
+
const register_cors_policy_1 = require("./api/cors/register-cors-policy");
|
|
68
|
+
const adaptive_probe_routes_1 = require("./api/health/adaptive-probe.routes");
|
|
69
|
+
const health_routes_1 = require("./api/health/health.routes");
|
|
70
|
+
const runner_boot_check_1 = require("./core/runner-health/runner-boot-check");
|
|
71
|
+
const hub_cluster_url_1 = require("./api/hub-cluster-url");
|
|
72
|
+
const model_distributor_js_1 = require("./api/model-distributor.js");
|
|
73
|
+
const oauth2_routes_js_1 = require("./api/oauth2/oauth2-routes.js");
|
|
74
|
+
const server_upload_1 = require("./api/server-upload");
|
|
75
|
+
const server_upload_propagate_1 = require("./api/server-upload-propagate");
|
|
76
|
+
const sse_no_compression_js_1 = require("./api/sse-no-compression.js");
|
|
77
|
+
const frame_policy_1 = require("./api/static/frame-policy");
|
|
78
|
+
const precompressed_asset_js_1 = require("./api/static/precompressed-asset.js");
|
|
79
|
+
const spa_mount_1 = require("./api/static/spa-mount");
|
|
80
|
+
const spa_static_1 = require("./api/static/spa-static");
|
|
81
|
+
const core_cap_bridge_1 = require("./api/trpc/core-cap-bridge");
|
|
82
|
+
const http_request_census_singleton_1 = require("./api/trpc/http-request-census.singleton");
|
|
83
|
+
const http_request_census_hook_1 = require("./api/trpc/http-request-census-hook");
|
|
84
|
+
const trpc_context_1 = require("./api/trpc/trpc.context");
|
|
85
|
+
const session_connections_js_1 = require("./auth/session-connections.js");
|
|
86
|
+
const trpc_router_1 = require("./api/trpc/trpc.router");
|
|
87
|
+
const trpc_error_device_tags_1 = require("./api/trpc/trpc-error-device-tags");
|
|
88
|
+
const trpc_error_principal_1 = require("./api/trpc/trpc-error-principal");
|
|
89
|
+
const ws_request_census_1 = require("./api/trpc/ws-request-census");
|
|
90
|
+
const ws_slow_consumer_guard_js_1 = require("./api/trpc/ws-slow-consumer-guard.js");
|
|
91
|
+
const addon_route_jwt_gate_js_1 = require("./auth/addon-route-jwt-gate.js");
|
|
92
|
+
const addon_route_share_gate_js_1 = require("./auth/addon-route-share-gate.js");
|
|
93
|
+
const auth_network_policy_js_1 = require("./auth/auth-network-policy.js");
|
|
94
|
+
const hub_sessions_js_1 = require("./auth/hub-sessions.js");
|
|
95
|
+
const session_lifetimes_js_1 = require("./auth/session-lifetimes.js");
|
|
96
|
+
const auth_rate_limit_1 = require("./auth/auth-rate-limit");
|
|
97
|
+
const external_link_intents_js_1 = require("./auth/external-link-intents.js");
|
|
98
|
+
const session_cookie_js_1 = require("./auth/session-cookie.js");
|
|
99
|
+
const session_mint_js_1 = require("./auth/session-mint.js");
|
|
100
|
+
const sso_finish_deps_js_1 = require("./auth/sso-finish-deps.js");
|
|
101
|
+
const app_confirmations_js_1 = require("./auth/app-confirmations.js");
|
|
102
|
+
const app_confirm_routes_js_1 = require("./auth/app-confirm-routes.js");
|
|
103
|
+
const app_passkey_routes_js_1 = require("./auth/app-passkey-routes.js");
|
|
104
|
+
const app_refused_route_js_1 = require("./auth/app-refused-route.js");
|
|
105
|
+
const passkey_provider_js_1 = require("./auth/passkey-provider.js");
|
|
106
|
+
const second_factors_js_1 = require("./auth/second-factors.js");
|
|
107
|
+
const sso_routes_js_1 = require("./auth/sso-routes.js");
|
|
108
|
+
const used_bridge_ids_js_1 = require("./auth/used-bridge-ids.js");
|
|
109
|
+
const native_link_completions_js_1 = require("./auth/native-link-completions.js");
|
|
110
|
+
const boot_config_1 = require("./boot/boot-config");
|
|
111
|
+
const platform_keychain_key_1 = require("./boot/platform-keychain-key");
|
|
112
|
+
const integration_id_backfill_1 = require("./boot/integration-id-backfill");
|
|
113
|
+
const post_boot_service_1 = require("./boot/post-boot.service");
|
|
114
|
+
const retired_public_url_env_1 = require("./boot/retired-public-url-env");
|
|
115
|
+
const addon_package_service_1 = require("./core/addon/addon-package.service");
|
|
116
|
+
const addon_registry_service_1 = require("./core/addon/addon-registry.service");
|
|
117
|
+
const addon_bridge_service_1 = require("./core/addon-bridge/addon-bridge.service");
|
|
118
|
+
const addon_pages_service_1 = require("./core/addon-pages/addon-pages.service");
|
|
119
|
+
const addon_widgets_service_1 = require("./core/addon-widgets/addon-widgets.service");
|
|
120
|
+
const agent_registry_service_1 = require("./core/agent/agent-registry.service");
|
|
121
|
+
const well_known_app_links_1 = require("./core/app-links/well-known-app-links");
|
|
122
|
+
const auth_service_1 = require("./core/auth/auth.service");
|
|
123
|
+
const handoff_code_service_1 = require("./core/auth/handoff-code.service");
|
|
124
|
+
const share_token_service_1 = require("./core/auth/share-token.service");
|
|
125
|
+
const config_service_1 = require("./core/config/config.service");
|
|
126
|
+
const event_bus_service_1 = require("./core/events/event-bus.service");
|
|
127
|
+
const feature_service_1 = require("./core/feature/feature.service");
|
|
128
|
+
const logging_service_1 = require("./core/logging/logging.service");
|
|
129
|
+
const moleculer_service_1 = require("./core/moleculer/moleculer.service");
|
|
130
|
+
const network_quality_service_1 = require("./core/network/network-quality.service");
|
|
131
|
+
const repl_engine_service_1 = require("./core/repl/repl-engine.service");
|
|
132
|
+
const server_update_service_1 = require("./core/server-update/server-update.service");
|
|
133
|
+
const storage_service_1 = require("./core/storage/storage.service");
|
|
134
|
+
const stream_probe_service_1 = require("./core/streaming/stream-probe.service");
|
|
135
|
+
const manual_boot_1 = require("./manual-boot");
|
|
136
|
+
const single_copy_cleanup_runner_js_1 = require("./single-copy-cleanup-runner.js");
|
|
99
137
|
// ---- Process-level error handlers ----
|
|
100
138
|
process.on('uncaughtException', (err) => {
|
|
101
139
|
console.error('[uncaughtException] Unhandled exception — server will continue:', err);
|
|
@@ -116,7 +154,7 @@ function immediateChildCleanup(signal) {
|
|
|
116
154
|
// Every addon-runner leads its OWN process group (D668), so the hub-group kill
|
|
117
155
|
// below no longer reaches runners or their ffmpeg/llama-server children.
|
|
118
156
|
// Signal each runner group first.
|
|
119
|
-
const runnerGroups = signalAllRunnerGroups('SIGTERM');
|
|
157
|
+
const runnerGroups = (0, system_1.signalAllRunnerGroups)('SIGTERM');
|
|
120
158
|
// Synchronously kill all children of this process via the OS.
|
|
121
159
|
// This is fast and ensures no orphans even if Fastify shutdown is slow.
|
|
122
160
|
try {
|
|
@@ -126,7 +164,7 @@ function immediateChildCleanup(signal) {
|
|
|
126
164
|
const cmd = isMac
|
|
127
165
|
? `pkill -TERM -P ${myPid} 2>/dev/null; true`
|
|
128
166
|
: `kill -- -${myPid} 2>/dev/null; true`;
|
|
129
|
-
execSync(cmd, { timeout: 3000 });
|
|
167
|
+
(0, node_child_process_1.execSync)(cmd, { timeout: 3000 });
|
|
130
168
|
console.log(`[shutdown] Child processes signalled (runner groups: ${runnerGroups})`);
|
|
131
169
|
}
|
|
132
170
|
catch {
|
|
@@ -158,7 +196,7 @@ function cleanupOrphanProcesses() {
|
|
|
158
196
|
const cmd = isMac
|
|
159
197
|
? "ps -eo pid,ppid,command | grep -E 'coreml_inference\\.py' | grep -v grep"
|
|
160
198
|
: "ps -eo pid,ppid,cmd | grep -E 'coreml_inference\\.py' | grep -v grep";
|
|
161
|
-
const output = execSync(cmd, { encoding: 'utf8', timeout: 5000 }).trim();
|
|
199
|
+
const output = (0, node_child_process_1.execSync)(cmd, { encoding: 'utf8', timeout: 5000 }).trim();
|
|
162
200
|
if (!output)
|
|
163
201
|
return;
|
|
164
202
|
for (const line of output.split('\n')) {
|
|
@@ -204,9 +242,9 @@ function cleanupOrphanProcesses() {
|
|
|
204
242
|
*/
|
|
205
243
|
async function sendMaybePrecompressed(reply, absolutePath, acceptEncoding) {
|
|
206
244
|
if (reply.getHeader('content-type') === undefined) {
|
|
207
|
-
reply.type(contentTypeForPath(absolutePath));
|
|
245
|
+
reply.type((0, spa_static_1.contentTypeForPath)(absolutePath));
|
|
208
246
|
}
|
|
209
|
-
const resolved = await resolvePrecompressedAsset(absolutePath, acceptEncoding, (msg, meta) => console.log(`[static] ${msg} ${JSON.stringify(meta)}`));
|
|
247
|
+
const resolved = await (0, precompressed_asset_js_1.resolvePrecompressedAsset)(absolutePath, acceptEncoding, (msg, meta) => console.log(`[static] ${msg} ${JSON.stringify(meta)}`));
|
|
210
248
|
if (resolved.encoding === 'br') {
|
|
211
249
|
reply.header('content-encoding', 'br');
|
|
212
250
|
reply.header('vary', 'accept-encoding');
|
|
@@ -227,10 +265,10 @@ async function bootstrap() {
|
|
|
227
265
|
// retired address variable is dropped here — before any addon runner is
|
|
228
266
|
// forked, so no child can read it — and warned about once a logger exists
|
|
229
267
|
// (below). See `boot/retired-public-url-env.ts`.
|
|
230
|
-
const publicUrlWarning = dropRetiredHubAddressEnv(process.env);
|
|
268
|
+
const publicUrlWarning = (0, retired_public_url_env_1.dropRetiredHubAddressEnv)(process.env);
|
|
231
269
|
// A desktop hub's keychain master key arrives on an inherited pipe (D788).
|
|
232
270
|
// Read and closed before anything is forked, so no runner inherits it.
|
|
233
|
-
const platformKey = loadPlatformKeychainKey();
|
|
271
|
+
const platformKey = (0, platform_keychain_key_1.loadPlatformKeychainKey)();
|
|
234
272
|
if (platformKey.kind === 'loaded') {
|
|
235
273
|
console.log(`[keychain] master key provided by the ${platformKey.label}`);
|
|
236
274
|
}
|
|
@@ -259,7 +297,7 @@ async function bootstrap() {
|
|
|
259
297
|
// calls `malloc_trim`, and no V8 flavor reaches it. So the pass is a real bound on the V8
|
|
260
298
|
// share and touches none of the share that grew. It is telemetry plus a partial bound, not a
|
|
261
299
|
// fix — do not read a reclaim line as "the leak was handled".
|
|
262
|
-
const heapReclaimer = createV8Reclaimer();
|
|
300
|
+
const heapReclaimer = (0, system_1.createV8Reclaimer)();
|
|
263
301
|
const heapReclaim = heapReclaimer === undefined ? undefined : { reclaim: heapReclaimer };
|
|
264
302
|
// ...and the budget the heartbeat alarms on. hub-main has no manifest to declare one in, and
|
|
265
303
|
// the entrypoint that would be the obvious alternative is the least deployable surface here —
|
|
@@ -272,7 +310,7 @@ async function bootstrap() {
|
|
|
272
310
|
// line for every runner in the cluster and none for the largest process in it. The sink is
|
|
273
311
|
// repointed at `LoggingService` the moment it exists (below), and boot lines keep going to
|
|
274
312
|
// stdout exactly as before. See `createDeferredHeapWatchSink`.
|
|
275
|
-
const heapWatchSink = createDeferredHeapWatchSink(HUB_MAIN_HEAP_WATCH_LABEL);
|
|
313
|
+
const heapWatchSink = (0, system_1.createDeferredHeapWatchSink)(system_1.HUB_MAIN_HEAP_WATCH_LABEL);
|
|
276
314
|
// ...and the event planes, which is the OTHER half of what this process is.
|
|
277
315
|
// hub-main's `arrayBuffers` is a rate, not a set: every forced compaction
|
|
278
316
|
// drops it to 12-29MB (ten passes out of ten, 2026-08-29), so the number to
|
|
@@ -287,12 +325,12 @@ async function bootstrap() {
|
|
|
287
325
|
// the reader reports `undefined` and the line carries no fan-out fields at all
|
|
288
326
|
// — a plane that does not exist yet must not be reported as a silent one.
|
|
289
327
|
let moleculerForEventPlane = null;
|
|
290
|
-
startHeapWatch(HUB_MAIN_HEAP_WATCH_LABEL, heapWatchSink.sink, undefined, heapReclaim, undefined, undefined, true, hubMainRssBudget(), {
|
|
291
|
-
eventPlane: createEventPlaneReader({
|
|
328
|
+
(0, system_1.startHeapWatch)(system_1.HUB_MAIN_HEAP_WATCH_LABEL, heapWatchSink.sink, undefined, heapReclaim, undefined, undefined, true, (0, system_1.hubMainRssBudget)(), {
|
|
329
|
+
eventPlane: (0, system_1.createEventPlaneReader)({
|
|
292
330
|
registry: () => moleculerForEventPlane?.childRegistry ?? null,
|
|
293
331
|
crossNodeStats: () => {
|
|
294
332
|
const broker = moleculerForEventPlane?.broker;
|
|
295
|
-
return broker === undefined ? null : getMoleculerEventStats(broker);
|
|
333
|
+
return broker === undefined ? null : (0, system_1.getMoleculerEventStats)(broker);
|
|
296
334
|
},
|
|
297
335
|
}),
|
|
298
336
|
// The fan-out counters above answered their own question and sharpened
|
|
@@ -303,7 +341,7 @@ async function bootstrap() {
|
|
|
303
341
|
// analytics` computed from a runner whose rchar also counts page-cache
|
|
304
342
|
// reads. These counters live on the channel itself, so the attribution is
|
|
305
343
|
// per peer and per frame kind. Same lazy registry, same reason.
|
|
306
|
-
socketPlane: createSocketPlaneReader({
|
|
344
|
+
socketPlane: (0, system_1.createSocketPlaneReader)({
|
|
307
345
|
registry: () => moleculerForEventPlane?.childRegistry ?? null,
|
|
308
346
|
}),
|
|
309
347
|
// The write queue to every peer NODE, from Moleculer's own writer
|
|
@@ -311,7 +349,7 @@ async function bootstrap() {
|
|
|
311
349
|
// exclusion of "every socket queue" — a sum over `_getActiveHandles()` —
|
|
312
350
|
// never saw them. With the UDS queues above, every outbound plane this
|
|
313
351
|
// process writes to is now on the line and judged on every probe (D446).
|
|
314
|
-
meshQueue: createMeshQueueReader(() => moleculerForEventPlane?.broker ?? null),
|
|
352
|
+
meshQueue: (0, system_1.createMeshQueueReader)(() => moleculerForEventPlane?.broker ?? null),
|
|
315
353
|
// The ArrayBuffer census, armed by the probe itself. Twice on 2026-09-10
|
|
316
354
|
// this process's `arrayBuffers` climbed linearly for an hour (to 1.3 GB
|
|
317
355
|
// and to 5 GB, both LIVE across a forced compaction) and released in one
|
|
@@ -321,7 +359,7 @@ async function bootstrap() {
|
|
|
321
359
|
// the pause a reclaim pass already costs — walked in memory, nothing
|
|
322
360
|
// written, on a threshold held for a minute, at most twice an hour.
|
|
323
361
|
// It is NOT a heap snapshot; see `array-buffer-census.ts`.
|
|
324
|
-
arrayBufferCensus: { census: createInspectorArrayBufferCensus() },
|
|
362
|
+
arrayBufferCensus: { census: (0, system_1.createInspectorArrayBufferCensus)() },
|
|
325
363
|
});
|
|
326
364
|
// Clean up orphaned processes from previous crashes before starting
|
|
327
365
|
cleanupOrphanProcesses();
|
|
@@ -335,14 +373,14 @@ async function bootstrap() {
|
|
|
335
373
|
// path for local/dev runs where neither env var is set.
|
|
336
374
|
const configPath = process.env.CONFIG_PATH ??
|
|
337
375
|
path.join(process.env.CAMSTACK_DATA ?? path.join(process.cwd(), 'camstack-data'), 'config.yaml');
|
|
338
|
-
const bootstrapConfig = loadBootstrapConfig(configPath);
|
|
339
|
-
const infra = await setupInfra(configPath, bootstrapConfig);
|
|
376
|
+
const bootstrapConfig = (0, boot_config_1.loadBootstrapConfig)(configPath);
|
|
377
|
+
const infra = await (0, boot_config_1.setupInfra)(configPath, bootstrapConfig);
|
|
340
378
|
const { dataPath, tlsOptions, tlsCert } = infra;
|
|
341
379
|
const port = infra.bootstrapConfig.server.port;
|
|
342
380
|
const host = infra.bootstrapConfig.server.host;
|
|
343
381
|
// --- Phase 3: Create app + tRPC register + listen ---
|
|
344
382
|
const fastifyOpts = tlsOptions ? { https: tlsOptions } : {};
|
|
345
|
-
const app = await bootManual({ infra, fastifyOpts });
|
|
383
|
+
const app = await (0, manual_boot_1.bootManual)({ infra, fastifyOpts });
|
|
346
384
|
app.enableShutdownHooks();
|
|
347
385
|
const fastify = app.getHttpAdapter().getInstance();
|
|
348
386
|
// Which browser origins may read hub responses, and open the /trpc socket
|
|
@@ -350,19 +388,19 @@ async function bootstrap() {
|
|
|
350
388
|
// `null`, and the operator's `server.corsOrigins`. First hook on the
|
|
351
389
|
// instance so every route — and every OPTIONS — is judged.
|
|
352
390
|
if (publicUrlWarning !== undefined) {
|
|
353
|
-
app.get(LoggingService).createLogger('public-url').warn(publicUrlWarning);
|
|
391
|
+
app.get(logging_service_1.LoggingService).createLogger('public-url').warn(publicUrlWarning);
|
|
354
392
|
}
|
|
355
|
-
const corsConfig = app.get(ConfigService);
|
|
356
|
-
const corsPolicy = createCorsPolicy({
|
|
393
|
+
const corsConfig = app.get(config_service_1.ConfigService);
|
|
394
|
+
const corsPolicy = (0, register_cors_policy_1.createCorsPolicy)({
|
|
357
395
|
configuredOrigins: () => corsConfig.get('server.corsOrigins'),
|
|
358
|
-
logger: app.get(LoggingService).createLogger('cors'),
|
|
396
|
+
logger: app.get(logging_service_1.LoggingService).createLogger('cors'),
|
|
359
397
|
});
|
|
360
|
-
registerCorsPolicy(fastify, corsPolicy);
|
|
361
|
-
await fastify.register(
|
|
398
|
+
(0, register_cors_policy_1.registerCorsPolicy)(fastify, corsPolicy);
|
|
399
|
+
await fastify.register(cookie_1.default);
|
|
362
400
|
// Every HTML document the hub serves may be framed by its own origin only
|
|
363
401
|
// (D425). Stamped here, on the one instance, so no shell-send site added
|
|
364
402
|
// later can ship without it.
|
|
365
|
-
registerFramePolicy(fastify);
|
|
403
|
+
(0, frame_policy_1.registerFramePolicy)(fastify);
|
|
366
404
|
// Gzip/Brotli compression for all responses (including static JS/CSS).
|
|
367
405
|
// Registered before @fastify/static so the compress plugin wraps the
|
|
368
406
|
// static send path — hashed admin-ui chunks go from ~2MB to ~600KB on
|
|
@@ -372,9 +410,9 @@ async function bootstrap() {
|
|
|
372
410
|
// silently in the compressor buffer — see `api/sse-no-compression.ts` for
|
|
373
411
|
// the mechanism and the live measurement.
|
|
374
412
|
fastify.addHook('onRequest', async (request) => {
|
|
375
|
-
markSseRequestNoCompression(request);
|
|
413
|
+
(0, sse_no_compression_js_1.markSseRequestNoCompression)(request);
|
|
376
414
|
});
|
|
377
|
-
await fastify.register(
|
|
415
|
+
await fastify.register(compress_1.default, { global: true, threshold: 1024 });
|
|
378
416
|
// Data-plane POST bodies: the addon reverse-proxy (`proxyToUpstream`) pipes
|
|
379
417
|
// `request.raw` upstream, but Fastify's default application/json parser would
|
|
380
418
|
// drain it first, so a POST body would reach the addon empty. Register a
|
|
@@ -383,53 +421,53 @@ async function bootstrap() {
|
|
|
383
421
|
// the raw stream intact for piping. No effect on JSON API routes.
|
|
384
422
|
fastify.addContentTypeParser('application/octet-stream', (_req, _payload, done) => done(null, undefined));
|
|
385
423
|
// Make LocationManager available to StorageService before lifecycle hooks run
|
|
386
|
-
const storageService = app.get(StorageService);
|
|
424
|
+
const storageService = app.get(storage_service_1.StorageService);
|
|
387
425
|
storageService.setLocationManager(infra.locationManager);
|
|
388
426
|
// ConfigService — SettingsStore is wired later by the settings-store capability consumer
|
|
389
|
-
const config = app.get(ConfigService);
|
|
427
|
+
const config = app.get(config_service_1.ConfigService);
|
|
390
428
|
// The real client address behind a trusted proxy, and the opt-in trusted
|
|
391
429
|
// networks — read from settings per request (auth-network-policy.ts).
|
|
392
|
-
const authNetwork = createAuthNetworkPolicy((key) => config.get(key));
|
|
430
|
+
const authNetwork = (0, auth_network_policy_js_1.createAuthNetworkPolicy)((key) => config.get(key));
|
|
393
431
|
// Public addon routes that declare `rateLimit: 'auth'` (an IdP start /
|
|
394
432
|
// callback) and the SSO finish: 30 per minute per real client address.
|
|
395
|
-
const authRouteLimiter = createRateLimiter({ windowMs: 60_000, max: 30 });
|
|
433
|
+
const authRouteLimiter = (0, auth_rate_limit_1.createRateLimiter)({ windowMs: 60_000, max: 30 });
|
|
396
434
|
// Login sessions (local-auth's table, reached through its hub-internal
|
|
397
435
|
// surface): every session token minted from here on carries a `sid`, and
|
|
398
436
|
// every verify of one asks whether that session is still live.
|
|
399
|
-
const sessionLifetimes = () => readSessionLifetimes((key) => config.get(key));
|
|
437
|
+
const sessionLifetimes = () => (0, session_lifetimes_js_1.readSessionLifetimes)((key) => config.get(key));
|
|
400
438
|
// Register addon upload route (multipart — must be registered before tRPC).
|
|
401
439
|
// We pass AddonRegistryService so the handler can resolve the
|
|
402
440
|
// `user-management` cap singleton at request time (the only working
|
|
403
441
|
// path to validate `cst_*` scoped tokens — see addon-upload.ts).
|
|
404
442
|
try {
|
|
405
|
-
const uploadAuthService = app.get(AuthService);
|
|
406
|
-
const uploadAddonBridge = app.get(AddonBridgeService);
|
|
407
|
-
const uploadMoleculer = app.get(MoleculerService);
|
|
408
|
-
const uploadAddonRegistry = app.get(AddonRegistryService);
|
|
409
|
-
const uploadAddonPackage = app.get(AddonPackageService);
|
|
410
|
-
const uploadLogger = app.get(LoggingService).createLogger('addon-upload');
|
|
443
|
+
const uploadAuthService = app.get(auth_service_1.AuthService);
|
|
444
|
+
const uploadAddonBridge = app.get(addon_bridge_service_1.AddonBridgeService);
|
|
445
|
+
const uploadMoleculer = app.get(moleculer_service_1.MoleculerService);
|
|
446
|
+
const uploadAddonRegistry = app.get(addon_registry_service_1.AddonRegistryService);
|
|
447
|
+
const uploadAddonPackage = app.get(addon_package_service_1.AddonPackageService);
|
|
448
|
+
const uploadLogger = app.get(logging_service_1.LoggingService).createLogger('addon-upload');
|
|
411
449
|
// The delivery ledger marks "the hub is writing addons to this node" for
|
|
412
450
|
// the whole deploy+reload, so the addon back-fill cannot read the roster
|
|
413
451
|
// gap a deploy opens and repair the node over the bytes just shipped.
|
|
414
|
-
await registerAddonUploadRoute(fastify, uploadAddonBridge, uploadAuthService, uploadMoleculer, uploadAddonRegistry, uploadAddonPackage, uploadLogger, clusterBaseUrlResolver(() => uploadAddonRegistry
|
|
452
|
+
await (0, addon_upload_1.registerAddonUploadRoute)(fastify, uploadAddonBridge, uploadAuthService, uploadMoleculer, uploadAddonRegistry, uploadAddonPackage, uploadLogger, (0, hub_cluster_url_1.clusterBaseUrlResolver)(() => uploadAddonRegistry
|
|
415
453
|
.getCapabilityRegistry()
|
|
416
|
-
.getSingleton('local-network')), app.get(AgentRegistryService).deliveryLedger);
|
|
454
|
+
.getSingleton('local-network')), app.get(agent_registry_service_1.AgentRegistryService).deliveryLedger);
|
|
417
455
|
console.log('[bootstrap] Addon upload route registered at POST /api/addons/upload');
|
|
418
456
|
// Dev server-deploy channel gateway (`camstack deploy-server`). MUST be
|
|
419
457
|
// registered AFTER registerAddonUploadRoute — it reuses the multipart
|
|
420
458
|
// plugin that route installs on this instance.
|
|
421
|
-
registerServerUploadRoute(fastify, {
|
|
459
|
+
(0, server_upload_1.registerServerUploadRoute)(fastify, {
|
|
422
460
|
authService: uploadAuthService,
|
|
423
461
|
addonRegistry: uploadAddonRegistry,
|
|
424
|
-
logger: app.get(LoggingService).createLogger('server-upload'),
|
|
462
|
+
logger: app.get(logging_service_1.LoggingService).createLogger('server-upload'),
|
|
425
463
|
});
|
|
426
464
|
console.log('[bootstrap] Server upload route registered at POST /api/server-upload');
|
|
427
|
-
registerServerUploadPropagateRoute(fastify, {
|
|
465
|
+
(0, server_upload_propagate_1.registerServerUploadPropagateRoute)(fastify, {
|
|
428
466
|
authService: uploadAuthService,
|
|
429
467
|
addonRegistry: uploadAddonRegistry,
|
|
430
|
-
logger: app.get(LoggingService).createLogger('server-upload-propagate'),
|
|
468
|
+
logger: app.get(logging_service_1.LoggingService).createLogger('server-upload-propagate'),
|
|
431
469
|
broker: uploadMoleculer.broker,
|
|
432
|
-
resolveClusterBaseUrl: clusterBaseUrlResolver(() => uploadAddonRegistry
|
|
470
|
+
resolveClusterBaseUrl: (0, hub_cluster_url_1.clusterBaseUrlResolver)(() => uploadAddonRegistry
|
|
433
471
|
.getCapabilityRegistry()
|
|
434
472
|
.getSingleton('local-network')),
|
|
435
473
|
});
|
|
@@ -438,7 +476,7 @@ async function bootstrap() {
|
|
|
438
476
|
// scoped tokens, returns the resolved identity + scope summary.
|
|
439
477
|
// Mirrors the addon-upload auth chain so the CLI can ping for
|
|
440
478
|
// token-still-valid without consuming a real cap.
|
|
441
|
-
await registerAuthWhoamiRoute(fastify, uploadAuthService, uploadAddonRegistry);
|
|
479
|
+
await (0, auth_whoami_1.registerAuthWhoamiRoute)(fastify, uploadAuthService, uploadAddonRegistry);
|
|
442
480
|
console.log('[bootstrap] Auth whoami route registered at GET /api/auth/whoami');
|
|
443
481
|
}
|
|
444
482
|
catch (err) {
|
|
@@ -447,7 +485,7 @@ async function bootstrap() {
|
|
|
447
485
|
// Register tRPC plugin on Fastify BEFORE listen.
|
|
448
486
|
// If registration fails, start in degraded mode: serve a health warning endpoint.
|
|
449
487
|
// Instantiate new core services
|
|
450
|
-
const loggingService = app.get(LoggingService);
|
|
488
|
+
const loggingService = app.get(logging_service_1.LoggingService);
|
|
451
489
|
// The heap heartbeat's handover: from here on hub-main's `[mem]` lines go through the log
|
|
452
490
|
// manager like every runner's do — buffer, console destination, rotated file and Loki — so
|
|
453
491
|
// the one process that mediates every cross-runner call is finally trendable next to the
|
|
@@ -478,19 +516,19 @@ async function bootstrap() {
|
|
|
478
516
|
// interval is `unref`ed, so it cannot hold the process open, and hub-main's
|
|
479
517
|
// shutdown is process exit.
|
|
480
518
|
const stallLogger = loggingService.createLogger('event-loop');
|
|
481
|
-
startEventLoopStallMonitor(stallLogger);
|
|
482
|
-
const addonRouteRegistry = new AddonRouteRegistry();
|
|
483
|
-
const dataPlaneRegistry = new DataPlaneRegistry();
|
|
519
|
+
(0, system_1.startEventLoopStallMonitor)(stallLogger);
|
|
520
|
+
const addonRouteRegistry = new system_1.AddonRouteRegistry();
|
|
521
|
+
const dataPlaneRegistry = new system_1.DataPlaneRegistry();
|
|
484
522
|
// Use Fastify-managed notification/toast wrappers (globally provided by NotificationModule)
|
|
485
|
-
const { NotificationServiceWrapper } = await
|
|
486
|
-
const { ToastServiceWrapper } = await
|
|
523
|
+
const { NotificationServiceWrapper } = await Promise.resolve().then(() => __importStar(require('./core/notification/notification-wrapper.service')));
|
|
524
|
+
const { ToastServiceWrapper } = await Promise.resolve().then(() => __importStar(require('./core/notification/toast-wrapper.service')));
|
|
487
525
|
const notificationWrapper = app.get(NotificationServiceWrapper);
|
|
488
526
|
const toastWrapper = app.get(ToastServiceWrapper);
|
|
489
527
|
// Expose the underlying core services for the tRPC router
|
|
490
528
|
const notificationService = notificationWrapper.service;
|
|
491
529
|
const toastService = toastWrapper.service;
|
|
492
530
|
// Wire AddonRouteRegistry and NotificationService
|
|
493
|
-
const addonRegistry = app.get(AddonRegistryService);
|
|
531
|
+
const addonRegistry = app.get(addon_registry_service_1.AddonRegistryService);
|
|
494
532
|
addonRegistry.setAddonRouteRegistry(addonRouteRegistry);
|
|
495
533
|
addonRegistry.setDataPlaneRegistry(dataPlaneRegistry);
|
|
496
534
|
// ── Configure the CapabilityRegistry (created in AddonRegistryService constructor) ──
|
|
@@ -501,7 +539,7 @@ async function bootstrap() {
|
|
|
501
539
|
hubInstalledVersion: (name) => {
|
|
502
540
|
try {
|
|
503
541
|
return (app
|
|
504
|
-
.get(AddonPackageService)
|
|
542
|
+
.get(addon_package_service_1.AddonPackageService)
|
|
505
543
|
.listInstalled()
|
|
506
544
|
.find((p) => p.name === name)?.version ?? null);
|
|
507
545
|
}
|
|
@@ -511,7 +549,7 @@ async function bootstrap() {
|
|
|
511
549
|
},
|
|
512
550
|
audit: async (event) => {
|
|
513
551
|
try {
|
|
514
|
-
const internal = getUserManagementInternal(capabilityRegistry.getSingleton('user-management'));
|
|
552
|
+
const internal = (0, system_1.getUserManagementInternal)(capabilityRegistry.getSingleton('user-management'));
|
|
515
553
|
if (internal === null) {
|
|
516
554
|
console.warn('[bootstrap] agent addon update not audited: no user-management internal');
|
|
517
555
|
return;
|
|
@@ -523,17 +561,17 @@ async function bootstrap() {
|
|
|
523
561
|
}
|
|
524
562
|
},
|
|
525
563
|
});
|
|
526
|
-
const sessionBacking = sessionBackingFrom(capabilityRegistry, sessionLifetimes);
|
|
564
|
+
const sessionBacking = (0, hub_sessions_js_1.sessionBackingFrom)(capabilityRegistry, sessionLifetimes);
|
|
527
565
|
// From here on every verify of a session-grade token — tRPC, addon routes,
|
|
528
566
|
// the session cookie, OAuth authorize, uploads, health — requires its
|
|
529
567
|
// session to be live (`hub-sessions.ts`).
|
|
530
|
-
app.get(AuthService).setSessionCheck(createSessionTokenCheck(capabilityRegistry));
|
|
568
|
+
app.get(auth_service_1.AuthService).setSessionCheck((0, hub_sessions_js_1.createSessionTokenCheck)(capabilityRegistry));
|
|
531
569
|
// Declare every shipped capability BEFORE app.init() so addon
|
|
532
570
|
// registerProvider() calls (in-process or via the Moleculer bridge
|
|
533
571
|
// from forked workers / agents) find their definition during
|
|
534
572
|
// onModuleInit. The list comes from the codegen — see the import
|
|
535
573
|
// comment above for the rationale.
|
|
536
|
-
for (const capDef of ALL_CAPABILITY_DEFINITIONS) {
|
|
574
|
+
for (const capDef of system_1.ALL_CAPABILITY_DEFINITIONS) {
|
|
537
575
|
capabilityRegistry.declareCapability(capDef);
|
|
538
576
|
}
|
|
539
577
|
// Hub-internal `sso-bridge` provider — gives auth-provider addons
|
|
@@ -541,7 +579,7 @@ async function bootstrap() {
|
|
|
541
579
|
// bridge token before redirecting to `/api/auth/sso/finish`. Without
|
|
542
580
|
// this, the finish endpoint would have to trust unsigned query params
|
|
543
581
|
// (anyone could craft `?isAdmin=1`). Backed by AuthService.
|
|
544
|
-
const authServiceForBridge = app.get(AuthService);
|
|
582
|
+
const authServiceForBridge = app.get(auth_service_1.AuthService);
|
|
545
583
|
capabilityRegistry.registerProvider('sso-bridge', '$hub', {
|
|
546
584
|
signBridgeToken: async ({ claims, ttlSec, }) => {
|
|
547
585
|
const token = authServiceForBridge.signSsoBridgeToken(claims, ttlSec ?? 300);
|
|
@@ -560,39 +598,39 @@ async function bootstrap() {
|
|
|
560
598
|
// Share-view (`csv_*`) tokens — hub-resident mint/verify/revoke over the
|
|
561
599
|
// settings backend (lazy getter: the backend lands after the sqlite-storage
|
|
562
600
|
// builtin registers; the service resolves it per call).
|
|
563
|
-
const shareTokenService = new ShareTokenService(() => addonRegistry.getSettingsBackend(), loggingService.createLogger('share-tokens'));
|
|
601
|
+
const shareTokenService = new share_token_service_1.ShareTokenService(() => addonRegistry.getSettingsBackend(), loggingService.createLogger('share-tokens'));
|
|
564
602
|
addonRegistry.setShareTokenService(shareTokenService);
|
|
565
603
|
// One-time native-app login handoff codes (in-memory, 60s TTL, single-use) —
|
|
566
604
|
// minted by `auth.createHandoffCode`, redeemed by the viewer app via the
|
|
567
605
|
// public `auth.redeemHandoffCode`.
|
|
568
|
-
const handoffCodeService = new HandoffCodeService();
|
|
606
|
+
const handoffCodeService = new handoff_code_service_1.HandoffCodeService();
|
|
569
607
|
// Pending "link this sign-in account" intents (D782) — minted by
|
|
570
608
|
// `auth.beginExternalLink`, consumed once by `/api/auth/sso/finish`.
|
|
571
|
-
const externalLinkIntents = new ExternalLinkIntents();
|
|
609
|
+
const externalLinkIntents = new external_link_intents_js_1.ExternalLinkIntents();
|
|
572
610
|
// Native-app links parked for the app to claim, and one-time codes that
|
|
573
611
|
// open the account page signed in, in a browser (D801).
|
|
574
|
-
const nativeLinkCompletions = new NativeLinkCompletions();
|
|
612
|
+
const nativeLinkCompletions = new native_link_completions_js_1.NativeLinkCompletions();
|
|
575
613
|
// `jti`s of login bridges already finished — a bridge is single-use.
|
|
576
|
-
const usedBridgeIds = new UsedBridgeIds();
|
|
577
|
-
const browserHandoffCodes = new HandoffCodeService();
|
|
614
|
+
const usedBridgeIds = new used_bridge_ids_js_1.UsedBridgeIds();
|
|
615
|
+
const browserHandoffCodes = new handoff_code_service_1.HandoffCodeService();
|
|
578
616
|
// Parked "sign the app in?" confirmations of the two native app flows (D858).
|
|
579
|
-
const appConfirmations = new AppConfirmations();
|
|
580
|
-
const nativeLinkMinter = createSessionMinter({
|
|
581
|
-
signer: app.get(AuthService),
|
|
617
|
+
const appConfirmations = new app_confirmations_js_1.AppConfirmations();
|
|
618
|
+
const nativeLinkMinter = (0, session_mint_js_1.createSessionMinter)({
|
|
619
|
+
signer: app.get(auth_service_1.AuthService),
|
|
582
620
|
directory: () => capabilityRegistry.getSingleton('user-management'),
|
|
583
621
|
sessions: sessionBacking,
|
|
584
622
|
});
|
|
585
623
|
const nativeLinkWiring = () => ({
|
|
586
|
-
auth: app.get(AuthService),
|
|
624
|
+
auth: app.get(auth_service_1.AuthService),
|
|
587
625
|
registry: capabilityRegistry,
|
|
588
|
-
moleculer: app.get(MoleculerService),
|
|
626
|
+
moleculer: app.get(moleculer_service_1.MoleculerService),
|
|
589
627
|
minter: nativeLinkMinter,
|
|
590
628
|
linkIntents: externalLinkIntents,
|
|
591
629
|
nativeLinks: nativeLinkCompletions,
|
|
592
630
|
usedBridgeIds,
|
|
593
631
|
});
|
|
594
|
-
const buildRouter = () => buildAppRouter({
|
|
595
|
-
authService: app.get(AuthService),
|
|
632
|
+
const buildRouter = () => (0, trpc_router_1.buildAppRouter)({
|
|
633
|
+
authService: app.get(auth_service_1.AuthService),
|
|
596
634
|
shareTokenService,
|
|
597
635
|
handoffCodeService,
|
|
598
636
|
externalLinkIntents,
|
|
@@ -601,26 +639,26 @@ async function bootstrap() {
|
|
|
601
639
|
browserHandoffs: browserHandoffCodes,
|
|
602
640
|
// The SSO finish's own link step — the same conflict rule, the same
|
|
603
641
|
// store — run for the app's claim instead of the browser's return.
|
|
604
|
-
link: (input) => createSsoFinishDeps(nativeLinkWiring(), undefined).identities.link(input),
|
|
642
|
+
link: (input) => (0, sso_finish_deps_js_1.createSsoFinishDeps)(nativeLinkWiring(), undefined).identities.link(input),
|
|
605
643
|
},
|
|
606
644
|
configService: config,
|
|
607
645
|
authNetworkPolicy: authNetwork,
|
|
608
646
|
sessionBacking,
|
|
609
|
-
featureService: app.get(FeatureService),
|
|
647
|
+
featureService: app.get(feature_service_1.FeatureService),
|
|
610
648
|
loggingService,
|
|
611
|
-
eventBus: app.get(EventBusService),
|
|
612
|
-
agentRegistry: app.get(AgentRegistryService),
|
|
613
|
-
moleculer: app.get(MoleculerService),
|
|
649
|
+
eventBus: app.get(event_bus_service_1.EventBusService),
|
|
650
|
+
agentRegistry: app.get(agent_registry_service_1.AgentRegistryService),
|
|
651
|
+
moleculer: app.get(moleculer_service_1.MoleculerService),
|
|
614
652
|
addonRegistry,
|
|
615
|
-
replEngine: app.get(ReplEngineService),
|
|
616
|
-
networkQualityService: app.get(NetworkQualityService),
|
|
617
|
-
addonBridge: app.get(AddonBridgeService),
|
|
618
|
-
addonPackageService: app.get(AddonPackageService),
|
|
653
|
+
replEngine: app.get(repl_engine_service_1.ReplEngineService),
|
|
654
|
+
networkQualityService: app.get(network_quality_service_1.NetworkQualityService),
|
|
655
|
+
addonBridge: app.get(addon_bridge_service_1.AddonBridgeService),
|
|
656
|
+
addonPackageService: app.get(addon_package_service_1.AddonPackageService),
|
|
619
657
|
notificationService,
|
|
620
658
|
toastService,
|
|
621
659
|
capabilityRegistry,
|
|
622
|
-
streamProbe: app.get(StreamProbeService),
|
|
623
|
-
serverUpdateService: app.get(ServerUpdateService),
|
|
660
|
+
streamProbe: app.get(stream_probe_service_1.StreamProbeService),
|
|
661
|
+
serverUpdateService: app.get(server_update_service_1.ServerUpdateService),
|
|
624
662
|
});
|
|
625
663
|
// ── The core-cap mesh bridge, mounted BEFORE a single addon boots (D171) ──
|
|
626
664
|
//
|
|
@@ -645,9 +683,9 @@ async function bootstrap() {
|
|
|
645
683
|
try {
|
|
646
684
|
appRouter = buildRouter();
|
|
647
685
|
{
|
|
648
|
-
const meshBroker = app.get(MoleculerService);
|
|
686
|
+
const meshBroker = app.get(moleculer_service_1.MoleculerService);
|
|
649
687
|
// D802: another node's call runs as `node:<id>`, never the hub's own principal.
|
|
650
|
-
meshBroker.registerCoreCapService(buildCoreCapService(appRouter, undefined, {
|
|
688
|
+
meshBroker.registerCoreCapService((0, core_cap_bridge_1.buildCoreCapService)(appRouter, undefined, {
|
|
651
689
|
ownNodeId: meshBroker.nodeId,
|
|
652
690
|
remoteUpdateGrant: remoteUpdateGrantDeps(),
|
|
653
691
|
}));
|
|
@@ -667,7 +705,7 @@ async function bootstrap() {
|
|
|
667
705
|
capabilityRegistry.ready();
|
|
668
706
|
// Register log-receiver service for agent log forwarding (after app.init
|
|
669
707
|
// so Moleculer re-advertises the service list to the network)
|
|
670
|
-
const moleculer = app.get(MoleculerService);
|
|
708
|
+
const moleculer = app.get(moleculer_service_1.MoleculerService);
|
|
671
709
|
// Hand the heartbeat its event-plane sources. The reader holds this by
|
|
672
710
|
// closure and re-reads `childRegistry` / `broker` on every line, so a registry
|
|
673
711
|
// that is rebuilt later is picked up without re-wiring anything.
|
|
@@ -679,26 +717,26 @@ async function bootstrap() {
|
|
|
679
717
|
// router) so forked addons (addon-model-studio) can reach it via `ctx.api`,
|
|
680
718
|
// not only external HTTP clients. Needs the broker + the deploy-stage
|
|
681
719
|
// registry, which an addon can't access.
|
|
682
|
-
capabilityRegistry.registerProvider('model-distributor', '$hub', buildModelDistributorProvider(moleculer, loggingService, clusterBaseUrlResolver(() => capabilityRegistry.getSingleton('local-network'))));
|
|
720
|
+
capabilityRegistry.registerProvider('model-distributor', '$hub', (0, model_distributor_js_1.buildModelDistributorProvider)(moleculer, loggingService, (0, hub_cluster_url_1.clusterBaseUrlResolver)(() => capabilityRegistry.getSingleton('local-network'))));
|
|
683
721
|
// ── Health routes (hub self + agent forwarding) ──────────────────
|
|
684
722
|
// Registered after app.init() so the AgentRegistryService is wired and
|
|
685
723
|
// the Moleculer broker is ready to forward `$agent.health` calls.
|
|
686
724
|
try {
|
|
687
725
|
const hubVersion = readHubVersion();
|
|
688
|
-
registerHealthRoutes(fastify, {
|
|
726
|
+
(0, health_routes_1.registerHealthRoutes)(fastify, {
|
|
689
727
|
moleculer,
|
|
690
|
-
agentRegistry: app.get(AgentRegistryService),
|
|
728
|
+
agentRegistry: app.get(agent_registry_service_1.AgentRegistryService),
|
|
691
729
|
hubVersion,
|
|
692
730
|
// Read the live flag at request time — flips to true once the tRPC
|
|
693
731
|
// router finishes registering (see `trpcRegistered = true` below).
|
|
694
732
|
isReady: () => trpcRegistered,
|
|
695
|
-
verifyToken: (token) => app.get(AuthService).verifyToken(token),
|
|
696
|
-
runnerBootCheck: () => app.get(RunnerBootCheckService).current(),
|
|
733
|
+
verifyToken: (token) => app.get(auth_service_1.AuthService).verifyToken(token),
|
|
734
|
+
runnerBootCheck: () => app.get(runner_boot_check_1.RunnerBootCheckService).current(),
|
|
697
735
|
});
|
|
698
736
|
console.log(`[bootstrap] Health routes registered (hub v${hubVersion})`);
|
|
699
|
-
registerAdaptiveProbeRoute(fastify, {
|
|
700
|
-
verifyToken: (token) => app.get(AuthService).verifyToken(token),
|
|
701
|
-
limiter: createRateLimiter({ windowMs: 60_000, max: ADAPTIVE_PROBE_PER_IP_PER_MINUTE }),
|
|
737
|
+
(0, adaptive_probe_routes_1.registerAdaptiveProbeRoute)(fastify, {
|
|
738
|
+
verifyToken: (token) => app.get(auth_service_1.AuthService).verifyToken(token),
|
|
739
|
+
limiter: (0, auth_rate_limit_1.createRateLimiter)({ windowMs: 60_000, max: adaptive_probe_routes_1.ADAPTIVE_PROBE_PER_IP_PER_MINUTE }),
|
|
702
740
|
network: authNetwork,
|
|
703
741
|
});
|
|
704
742
|
}
|
|
@@ -731,12 +769,12 @@ async function bootstrap() {
|
|
|
731
769
|
// this boot unless `restore()` (below, just before `listen`) finds a window
|
|
732
770
|
// an operator armed earlier. The logger is attached now so a restored census
|
|
733
771
|
// has somewhere to report before the first request arrives.
|
|
734
|
-
const httpRequestCensus = getHttpRequestCensus();
|
|
772
|
+
const httpRequestCensus = (0, http_request_census_singleton_1.getHttpRequestCensus)();
|
|
735
773
|
const trpcLogger = loggingService.createLogger('tRPC');
|
|
736
774
|
httpRequestCensus.setLogger(trpcLogger);
|
|
737
|
-
setRemotePrivilegeLogSink(trpcLogger);
|
|
775
|
+
(0, core_cap_bridge_1.setRemotePrivilegeLogSink)(trpcLogger);
|
|
738
776
|
try {
|
|
739
|
-
const authService = app.get(AuthService);
|
|
777
|
+
const authService = app.get(auth_service_1.AuthService);
|
|
740
778
|
// Normally already built and bridged onto the mesh in `beforeAddonBoot`
|
|
741
779
|
// above — this is the fallback for the case where that failed, so a hub
|
|
742
780
|
// whose mesh bridge could not be mounted still serves HTTP.
|
|
@@ -744,9 +782,9 @@ async function bootstrap() {
|
|
|
744
782
|
appRouter = buildRouter();
|
|
745
783
|
try {
|
|
746
784
|
{
|
|
747
|
-
const meshBroker = app.get(MoleculerService);
|
|
785
|
+
const meshBroker = app.get(moleculer_service_1.MoleculerService);
|
|
748
786
|
// D802: another node's call runs as `node:<id>`, never the hub's own principal.
|
|
749
|
-
meshBroker.registerCoreCapService(buildCoreCapService(appRouter, undefined, {
|
|
787
|
+
meshBroker.registerCoreCapService((0, core_cap_bridge_1.buildCoreCapService)(appRouter, undefined, {
|
|
750
788
|
ownNodeId: meshBroker.nodeId,
|
|
751
789
|
remoteUpdateGrant: remoteUpdateGrantDeps(),
|
|
752
790
|
}));
|
|
@@ -757,30 +795,30 @@ async function bootstrap() {
|
|
|
757
795
|
console.warn('[bootstrap] Failed to register core-cap mesh bridge:', err);
|
|
758
796
|
}
|
|
759
797
|
}
|
|
760
|
-
await fastify.register(fastifyTRPCPlugin, {
|
|
798
|
+
await fastify.register(fastify_1.fastifyTRPCPlugin, {
|
|
761
799
|
prefix: '/trpc',
|
|
762
800
|
trpcOptions: {
|
|
763
801
|
router: appRouter,
|
|
764
802
|
createContext: async ({ req }) => {
|
|
765
|
-
const trpcCtx = await createTrpcContext(req, authService, addonRegistry, shareTokenService,
|
|
803
|
+
const trpcCtx = await (0, trpc_context_1.createTrpcContext)(req, authService, addonRegistry, shareTokenService,
|
|
766
804
|
// A bearer refused for NOT being an API credential never reaches a
|
|
767
805
|
// procedure, so `onError` below never sees it — the refusal would
|
|
768
806
|
// be silent without this. Same reason `gateAddonJwt` logs (D103).
|
|
769
|
-
app.get(LoggingService).createLogger('tRPC'));
|
|
807
|
+
app.get(logging_service_1.LoggingService).createLogger('tRPC'));
|
|
770
808
|
// WHO called, counted here because this is the first point at which
|
|
771
809
|
// a principal exists AND the only one tRPC runs exactly once per
|
|
772
810
|
// HTTP request (batched or not). Disarmed this is a boolean read and
|
|
773
811
|
// a return — see `http-request-census-hook.ts`.
|
|
774
|
-
recordTrpcHttpRequest(httpRequestCensus, req, trpcCtx.user);
|
|
812
|
+
(0, http_request_census_hook_1.recordTrpcHttpRequest)(httpRequestCensus, req, trpcCtx.user);
|
|
775
813
|
return trpcCtx;
|
|
776
814
|
},
|
|
777
815
|
onError: ({ path: trpcPath, error, ctx, input, }) => {
|
|
778
|
-
const trpcLogger = app.get(LoggingService).createLogger('tRPC');
|
|
816
|
+
const trpcLogger = app.get(logging_service_1.LoggingService).createLogger('tRPC');
|
|
779
817
|
trpcLogger.warn('tRPC error', {
|
|
780
818
|
// WHICH camera. A refusal on a device-scoped path that names no
|
|
781
819
|
// deviceId cannot answer "one camera or all of them?" — the
|
|
782
820
|
// question always asked first (2026-08-29, `intercom.startSession`).
|
|
783
|
-
tags: trpcErrorDeviceTags(trpcPath, input),
|
|
821
|
+
tags: (0, trpc_error_device_tags_1.trpcErrorDeviceTags)(trpcPath, input),
|
|
784
822
|
meta: {
|
|
785
823
|
code: error.code,
|
|
786
824
|
path: trpcPath ?? '?',
|
|
@@ -788,7 +826,7 @@ async function bootstrap() {
|
|
|
788
826
|
// to the integration that hit it, and an operator grepping for
|
|
789
827
|
// the integration finds nothing — which reads as "the hub logged
|
|
790
828
|
// nothing" (2026-08-09).
|
|
791
|
-
principal: describeTrpcPrincipal(ctx?.user),
|
|
829
|
+
principal: (0, trpc_error_principal_1.describeTrpcPrincipal)(ctx?.user),
|
|
792
830
|
message: error.message,
|
|
793
831
|
},
|
|
794
832
|
});
|
|
@@ -803,7 +841,7 @@ async function bootstrap() {
|
|
|
803
841
|
});
|
|
804
842
|
trpcRegistered = true;
|
|
805
843
|
// Register addon-pages static file endpoint
|
|
806
|
-
const addonPagesService = app.get(AddonPagesService);
|
|
844
|
+
const addonPagesService = app.get(addon_pages_service_1.AddonPagesService);
|
|
807
845
|
fastify.get('/api/addon-pages/:addonId/*', async (request, reply) => {
|
|
808
846
|
const { addonId } = request.params;
|
|
809
847
|
const filePath = request.params['*'];
|
|
@@ -826,7 +864,7 @@ async function bootstrap() {
|
|
|
826
864
|
: 'application/octet-stream';
|
|
827
865
|
const stream = fs.createReadStream(resolved);
|
|
828
866
|
return reply
|
|
829
|
-
.header('cache-control', addonBundleCacheControl(resolved))
|
|
867
|
+
.header('cache-control', (0, spa_static_1.addonBundleCacheControl)(resolved))
|
|
830
868
|
.type(contentType)
|
|
831
869
|
.send(stream);
|
|
832
870
|
});
|
|
@@ -835,7 +873,7 @@ async function bootstrap() {
|
|
|
835
873
|
// `dist/widgets.mjs` (declared per-widget in `addon-widgets-source`
|
|
836
874
|
// metadata). Path-traversal protection + cap-registration check
|
|
837
875
|
// both live in `AddonWidgetsService.resolveBundle`.
|
|
838
|
-
const addonWidgetsService = app.get(AddonWidgetsService);
|
|
876
|
+
const addonWidgetsService = app.get(addon_widgets_service_1.AddonWidgetsService);
|
|
839
877
|
fastify.get('/api/addon-widgets/:addonId/*', async (request, reply) => {
|
|
840
878
|
const { addonId } = request.params;
|
|
841
879
|
const filePath = request.params['*'];
|
|
@@ -861,10 +899,10 @@ async function bootstrap() {
|
|
|
861
899
|
// fixed-name `_stub.js`/`remoteEntry.js` — is safely immutable (this
|
|
862
900
|
// defeats a CDN edge serving a stale stub). Legacy unversioned requests
|
|
863
901
|
// keep the per-file revalidation policy.
|
|
864
|
-
const { versioned } = stripBundleVersionSegment(filePath);
|
|
902
|
+
const { versioned } = (0, addon_widgets_service_1.stripBundleVersionSegment)(filePath);
|
|
865
903
|
const cacheControl = versioned
|
|
866
904
|
? 'public, max-age=31536000, immutable'
|
|
867
|
-
: addonBundleCacheControl(resolved);
|
|
905
|
+
: (0, spa_static_1.addonBundleCacheControl)(resolved);
|
|
868
906
|
const stream = fs.createReadStream(resolved);
|
|
869
907
|
return reply.header('cache-control', cacheControl).type(contentType).send(stream);
|
|
870
908
|
});
|
|
@@ -905,16 +943,16 @@ async function bootstrap() {
|
|
|
905
943
|
// bridge bound to the browser that started it; the session is minted by
|
|
906
944
|
// THE session mint from the user record as it is now (D712). Rules in
|
|
907
945
|
// `auth/sso-finish.ts`, routes in `auth/sso-routes.ts`.
|
|
908
|
-
const ssoMinter = createSessionMinter({
|
|
909
|
-
signer: app.get(AuthService),
|
|
946
|
+
const ssoMinter = (0, session_mint_js_1.createSessionMinter)({
|
|
947
|
+
signer: app.get(auth_service_1.AuthService),
|
|
910
948
|
directory: () => capabilityRegistry.getSingleton('user-management'),
|
|
911
949
|
sessions: sessionBacking,
|
|
912
950
|
});
|
|
913
|
-
registerSsoRoutes(fastify, {
|
|
951
|
+
(0, sso_routes_js_1.registerSsoRoutes)(fastify, {
|
|
914
952
|
wiring: {
|
|
915
|
-
auth: app.get(AuthService),
|
|
953
|
+
auth: app.get(auth_service_1.AuthService),
|
|
916
954
|
registry: capabilityRegistry,
|
|
917
|
-
moleculer: app.get(MoleculerService),
|
|
955
|
+
moleculer: app.get(moleculer_service_1.MoleculerService),
|
|
918
956
|
minter: ssoMinter,
|
|
919
957
|
linkIntents: externalLinkIntents,
|
|
920
958
|
nativeLinks: nativeLinkCompletions,
|
|
@@ -925,46 +963,46 @@ async function bootstrap() {
|
|
|
925
963
|
browserHandoffCodes,
|
|
926
964
|
confirmations: appConfirmations,
|
|
927
965
|
minter: ssoMinter,
|
|
928
|
-
logger: app.get(LoggingService).createLogger('sso-finish'),
|
|
966
|
+
logger: app.get(logging_service_1.LoggingService).createLogger('sso-finish'),
|
|
929
967
|
});
|
|
930
968
|
// ── Passkey sign-in for the native app (D858) ───────────────────
|
|
931
969
|
// A standalone page + two same-origin legs; the assertion ends in a handoff
|
|
932
970
|
// code at the app's custom scheme, never in a web session.
|
|
933
|
-
registerAppPasskeyRoutes(fastify, {
|
|
934
|
-
passkeys: () => resolvePasskeyProvider(capabilityRegistry, app.get(MoleculerService)),
|
|
971
|
+
(0, app_passkey_routes_js_1.registerAppPasskeyRoutes)(fastify, {
|
|
972
|
+
passkeys: () => (0, passkey_provider_js_1.resolvePasskeyProvider)(capabilityRegistry, app.get(moleculer_service_1.MoleculerService)),
|
|
935
973
|
secondFactors: (userId) => {
|
|
936
974
|
const um = capabilityRegistry.getSingleton('user-management');
|
|
937
|
-
return collectSecondFactors({
|
|
975
|
+
return (0, second_factors_js_1.collectSecondFactors)({
|
|
938
976
|
...(um && typeof um.getTotpStatus === 'function'
|
|
939
977
|
? { getTotpStatus: (input) => um.getTotpStatus(input) }
|
|
940
978
|
: {}),
|
|
941
|
-
passkeyProvider: () => resolvePasskeyProvider(capabilityRegistry, app.get(MoleculerService)),
|
|
979
|
+
passkeyProvider: () => (0, passkey_provider_js_1.resolvePasskeyProvider)(capabilityRegistry, app.get(moleculer_service_1.MoleculerService)),
|
|
942
980
|
}, userId, 'passkey');
|
|
943
981
|
},
|
|
944
982
|
minter: ssoMinter,
|
|
945
983
|
confirmations: appConfirmations,
|
|
946
984
|
network: authNetwork,
|
|
947
985
|
limiter: authRouteLimiter,
|
|
948
|
-
logger: app.get(LoggingService).createLogger('app-passkey'),
|
|
986
|
+
logger: app.get(logging_service_1.LoggingService).createLogger('app-passkey'),
|
|
949
987
|
});
|
|
950
|
-
registerAppRefusedRoute(fastify);
|
|
988
|
+
(0, app_refused_route_js_1.registerAppRefusedRoute)(fastify);
|
|
951
989
|
// The last step of both app flows: "Sign in the app as <user>?" - the
|
|
952
990
|
// handoff code is minted only when the person presses Continue (D858).
|
|
953
|
-
registerAppConfirmRoutes(fastify, {
|
|
991
|
+
(0, app_confirm_routes_js_1.registerAppConfirmRoutes)(fastify, {
|
|
954
992
|
confirmations: appConfirmations,
|
|
955
993
|
handoffCodes: handoffCodeService,
|
|
956
994
|
network: authNetwork,
|
|
957
995
|
limiter: authRouteLimiter,
|
|
958
|
-
logger: app.get(LoggingService).createLogger('app-confirm'),
|
|
996
|
+
logger: app.get(logging_service_1.LoggingService).createLogger('app-confirm'),
|
|
959
997
|
});
|
|
960
998
|
// ── Backup archive download ─────────────────────────────────────
|
|
961
999
|
// Streams an archive through the storage cap's chunked-download
|
|
962
1000
|
// protocol at the pace the client reads it (D447). The route, its
|
|
963
1001
|
// auth chain and the drain-respecting pump live in `api/backup-download*`.
|
|
964
|
-
registerBackupDownloadRoute(fastify, {
|
|
965
|
-
verifier: app.get(AuthService),
|
|
1002
|
+
(0, backup_download_js_1.registerBackupDownloadRoute)(fastify, {
|
|
1003
|
+
verifier: app.get(auth_service_1.AuthService),
|
|
966
1004
|
capabilities: capabilityRegistry,
|
|
967
|
-
logger: app.get(LoggingService).createLogger('backup-download'),
|
|
1005
|
+
logger: app.get(logging_service_1.LoggingService).createLogger('backup-download'),
|
|
968
1006
|
});
|
|
969
1007
|
// POST /api/auth/session — upgrade a tRPC-issued JWT to a browser cookie.
|
|
970
1008
|
fastify.post('/api/auth/session', async (request, reply) => {
|
|
@@ -978,7 +1016,7 @@ async function bootstrap() {
|
|
|
978
1016
|
// e.g. the totp-challenge from login leg 1) verify under the same
|
|
979
1017
|
// secret — accepting one here handed out a cookie that bypassed
|
|
980
1018
|
// the second factor on every cookie-gated surface.
|
|
981
|
-
if (!isSessionGradeJwtPayload(payload)) {
|
|
1019
|
+
if (!(0, session_cookie_js_1.isSessionGradeJwtPayload)(payload)) {
|
|
982
1020
|
return reply.status(401).send({ error: 'invalid token' });
|
|
983
1021
|
}
|
|
984
1022
|
const expSec = typeof payload.exp === 'number' ? payload.exp : 0;
|
|
@@ -987,16 +1025,16 @@ async function bootstrap() {
|
|
|
987
1025
|
catch {
|
|
988
1026
|
return reply.status(401).send({ error: 'invalid token' });
|
|
989
1027
|
}
|
|
990
|
-
const c = buildSessionCookie(token, ttlSec, {
|
|
991
|
-
secure: sessionCookieIsSecure(request.protocol, request.headers, FORWARDED_PREFIX_HEADER),
|
|
1028
|
+
const c = (0, session_cookie_js_1.buildSessionCookie)(token, ttlSec, {
|
|
1029
|
+
secure: (0, session_cookie_js_1.sessionCookieIsSecure)(request.protocol, request.headers, spa_mount_1.FORWARDED_PREFIX_HEADER),
|
|
992
1030
|
});
|
|
993
1031
|
reply.setCookie(c.name, c.value, c.options);
|
|
994
1032
|
return reply.send({ ok: true });
|
|
995
1033
|
});
|
|
996
1034
|
// DELETE /api/auth/session — clear the cookie on logout.
|
|
997
1035
|
fastify.delete('/api/auth/session', async (request, reply) => {
|
|
998
|
-
const c = clearSessionCookie({
|
|
999
|
-
secure: sessionCookieIsSecure(request.protocol, request.headers, FORWARDED_PREFIX_HEADER),
|
|
1036
|
+
const c = (0, session_cookie_js_1.clearSessionCookie)({
|
|
1037
|
+
secure: (0, session_cookie_js_1.sessionCookieIsSecure)(request.protocol, request.headers, spa_mount_1.FORWARDED_PREFIX_HEADER),
|
|
1000
1038
|
});
|
|
1001
1039
|
reply.setCookie(c.name, c.value, c.options);
|
|
1002
1040
|
return reply.send({ ok: true });
|
|
@@ -1016,7 +1054,7 @@ async function bootstrap() {
|
|
|
1016
1054
|
if (!token)
|
|
1017
1055
|
return reply.status(401).send({ error: 'Bearer token required' });
|
|
1018
1056
|
const next = request.query?.next ?? '';
|
|
1019
|
-
if (!isEmbedRedirectTarget(next))
|
|
1057
|
+
if (!(0, session_cookie_js_1.isEmbedRedirectTarget)(next))
|
|
1020
1058
|
return reply.status(400).send({ error: 'invalid next' });
|
|
1021
1059
|
let ttlSec;
|
|
1022
1060
|
try {
|
|
@@ -1027,8 +1065,8 @@ async function bootstrap() {
|
|
|
1027
1065
|
catch {
|
|
1028
1066
|
return reply.status(401).send({ error: 'invalid token' });
|
|
1029
1067
|
}
|
|
1030
|
-
const c = buildSessionCookie(token, ttlSec, {
|
|
1031
|
-
secure: sessionCookieIsSecure(request.protocol, request.headers, FORWARDED_PREFIX_HEADER),
|
|
1068
|
+
const c = (0, session_cookie_js_1.buildSessionCookie)(token, ttlSec, {
|
|
1069
|
+
secure: (0, session_cookie_js_1.sessionCookieIsSecure)(request.protocol, request.headers, spa_mount_1.FORWARDED_PREFIX_HEADER),
|
|
1032
1070
|
});
|
|
1033
1071
|
reply.setCookie(c.name, c.value, c.options);
|
|
1034
1072
|
return reply.redirect(next);
|
|
@@ -1036,7 +1074,7 @@ async function bootstrap() {
|
|
|
1036
1074
|
// Every refusal on the addon gate is a request an operator will be asking
|
|
1037
1075
|
// about ("why did Home Assistant stop actuating?"). Its own scope so the
|
|
1038
1076
|
// reason is greppable rather than buried in the bootstrap logger.
|
|
1039
|
-
const addonGateLogger = app.get(LoggingService).createLogger('addon-route-auth');
|
|
1077
|
+
const addonGateLogger = app.get(logging_service_1.LoggingService).createLogger('addon-route-auth');
|
|
1040
1078
|
// Addon HTTP API route catch-all: /addon/:addonId/*
|
|
1041
1079
|
// Only handles non-GET or routes that actually exist in the addon route registry.
|
|
1042
1080
|
// GET requests that don't match an addon route are SPA pages — handled by the /* fallback.
|
|
@@ -1070,7 +1108,7 @@ async function bootstrap() {
|
|
|
1070
1108
|
let shareHeaders = null;
|
|
1071
1109
|
if (access !== 'public') {
|
|
1072
1110
|
const authHeader = request.headers.authorization;
|
|
1073
|
-
const cookieToken = request.cookies?.[SESSION_COOKIE];
|
|
1111
|
+
const cookieToken = request.cookies?.[session_cookie_js_1.SESSION_COOKIE];
|
|
1074
1112
|
if (!authHeader && !cookieToken) {
|
|
1075
1113
|
return reply.status(401).send({ error: 'Unauthorized' });
|
|
1076
1114
|
}
|
|
@@ -1081,7 +1119,7 @@ async function bootstrap() {
|
|
|
1081
1119
|
// HUB sets — whatever the client sent under those names is dropped
|
|
1082
1120
|
// (see `addon-route-share-gate.ts`).
|
|
1083
1121
|
const record = await shareTokenService.validate(token);
|
|
1084
|
-
const gate = gateAddonShareToken({ record, endpoint: dpMatch.endpoint });
|
|
1122
|
+
const gate = (0, addon_route_share_gate_js_1.gateAddonShareToken)({ record, endpoint: dpMatch.endpoint });
|
|
1085
1123
|
if (!gate.ok)
|
|
1086
1124
|
return reply.status(gate.status).send({ error: gate.error });
|
|
1087
1125
|
shareHeaders = gate.headers;
|
|
@@ -1104,7 +1142,7 @@ async function bootstrap() {
|
|
|
1104
1142
|
catch {
|
|
1105
1143
|
return reply.status(401).send({ error: 'Invalid token' });
|
|
1106
1144
|
}
|
|
1107
|
-
const gate = gateAddonJwt({ payload, addonId, method, access }, addonGateLogger);
|
|
1145
|
+
const gate = (0, addon_route_jwt_gate_js_1.gateAddonJwt)({ payload, addonId, method, access }, addonGateLogger);
|
|
1108
1146
|
if (!gate.ok) {
|
|
1109
1147
|
return reply.status(gate.status).send({ error: gate.error });
|
|
1110
1148
|
}
|
|
@@ -1119,8 +1157,8 @@ async function bootstrap() {
|
|
|
1119
1157
|
// The share headers are the HUB's to write: drop whatever the client
|
|
1120
1158
|
// sent under those names, then set the validated scope, if any.
|
|
1121
1159
|
for (const name of Object.keys(request.raw.headers)) {
|
|
1122
|
-
if (name.toLowerCase() === SHARE_KIND_HEADER ||
|
|
1123
|
-
name.toLowerCase() === SHARE_DEVICES_HEADER)
|
|
1160
|
+
if (name.toLowerCase() === addon_route_share_gate_js_1.SHARE_KIND_HEADER ||
|
|
1161
|
+
name.toLowerCase() === addon_route_share_gate_js_1.SHARE_DEVICES_HEADER)
|
|
1124
1162
|
delete request.raw.headers[name];
|
|
1125
1163
|
}
|
|
1126
1164
|
if (shareHeaders !== null)
|
|
@@ -1132,7 +1170,7 @@ async function bootstrap() {
|
|
|
1132
1170
|
: Buffer.isBuffer(request.body)
|
|
1133
1171
|
? request.body
|
|
1134
1172
|
: Buffer.from(typeof request.body === 'string' ? request.body : JSON.stringify(request.body));
|
|
1135
|
-
proxyToUpstream({
|
|
1173
|
+
(0, system_1.proxyToUpstream)({
|
|
1136
1174
|
baseUrl: dpMatch.endpoint.baseUrl,
|
|
1137
1175
|
secret: dpMatch.endpoint.secret,
|
|
1138
1176
|
upstreamPath,
|
|
@@ -1144,7 +1182,7 @@ async function bootstrap() {
|
|
|
1144
1182
|
}
|
|
1145
1183
|
const match = addonRouteRegistry.matchRoute(method, fullPath);
|
|
1146
1184
|
if (!match) {
|
|
1147
|
-
if (isRetiredPublicPath(fullPath)) {
|
|
1185
|
+
if ((0, spa_static_1.isRetiredPublicPath)(fullPath)) {
|
|
1148
1186
|
return reply.status(404).send({ error: 'Not found' });
|
|
1149
1187
|
}
|
|
1150
1188
|
if (method === 'GET' && spaIndexHtml) {
|
|
@@ -1153,14 +1191,14 @@ async function bootstrap() {
|
|
|
1153
1191
|
// send used to carry no cache header at all, so browsers kept the
|
|
1154
1192
|
// index.html of a previous build (and its dead hashed asset names)
|
|
1155
1193
|
// across deploys until a force refresh.
|
|
1156
|
-
return sendSpaShell(reply, spaIndexHtml, request.headers);
|
|
1194
|
+
return (0, spa_mount_1.sendSpaShell)(reply, spaIndexHtml, request.headers);
|
|
1157
1195
|
}
|
|
1158
1196
|
return reply.status(404).send({ error: 'Not found' });
|
|
1159
1197
|
}
|
|
1160
1198
|
// A route that asked for it (an IdP start / callback) is limited per
|
|
1161
1199
|
// REAL client address before its handler runs.
|
|
1162
1200
|
if (match.route.rateLimit === 'auth') {
|
|
1163
|
-
const routeClient = clientKeyFromRequest(request, authNetwork);
|
|
1201
|
+
const routeClient = (0, auth_rate_limit_1.clientKeyFromRequest)(request, authNetwork);
|
|
1164
1202
|
if (routeClient !== null) {
|
|
1165
1203
|
const verdict = authRouteLimiter.check(`route:${addonId}:${routeClient}`);
|
|
1166
1204
|
if (!verdict.allowed) {
|
|
@@ -1174,11 +1212,11 @@ async function bootstrap() {
|
|
|
1174
1212
|
const authHeader = request.headers.authorization;
|
|
1175
1213
|
// Browser navigation has no Authorization header — fall back to the
|
|
1176
1214
|
// session cookie, and if that is missing bounce to the login page.
|
|
1177
|
-
const cookieToken = request.cookies?.[SESSION_COOKIE];
|
|
1215
|
+
const cookieToken = request.cookies?.[session_cookie_js_1.SESSION_COOKIE];
|
|
1178
1216
|
if (!authHeader && !cookieToken) {
|
|
1179
|
-
if (shouldRedirectToLogin(request.method, request.headers.accept)) {
|
|
1217
|
+
if ((0, session_cookie_js_1.shouldRedirectToLogin)(request.method, request.headers.accept)) {
|
|
1180
1218
|
const qs = request.url.includes('?') ? request.url.slice(request.url.indexOf('?')) : '';
|
|
1181
|
-
return reply.redirect(loginRedirectUrl(fullPath + qs, parseForwardedPrefix(request.headers['x-forwarded-prefix'])));
|
|
1219
|
+
return reply.redirect((0, session_cookie_js_1.loginRedirectUrl)(fullPath + qs, (0, spa_mount_1.parseForwardedPrefix)(request.headers['x-forwarded-prefix'])));
|
|
1182
1220
|
}
|
|
1183
1221
|
return reply.status(401).send({ error: 'Unauthorized' });
|
|
1184
1222
|
}
|
|
@@ -1226,7 +1264,7 @@ async function bootstrap() {
|
|
|
1226
1264
|
}
|
|
1227
1265
|
// NOTE: the handler call used to sit INSIDE this try, so a throw from
|
|
1228
1266
|
// an addon's own route handler was reported as `401 Invalid token`.
|
|
1229
|
-
const gate = gateAddonJwt({ payload, addonId, method, access: match.route.access }, addonGateLogger);
|
|
1267
|
+
const gate = (0, addon_route_jwt_gate_js_1.gateAddonJwt)({ payload, addonId, method, access: match.route.access }, addonGateLogger);
|
|
1230
1268
|
if (!gate.ok) {
|
|
1231
1269
|
return reply.status(gate.status).send({ error: gate.error });
|
|
1232
1270
|
}
|
|
@@ -1260,17 +1298,17 @@ async function bootstrap() {
|
|
|
1260
1298
|
// namespace already excluded from the SPA catch-all everywhere.
|
|
1261
1299
|
// getRegistry is a closure so it always resolves the live registry at
|
|
1262
1300
|
// request time (safe even if called before ready()).
|
|
1263
|
-
registerOauth2Routes(fastify, {
|
|
1301
|
+
(0, oauth2_routes_js_1.registerOauth2Routes)(fastify, {
|
|
1264
1302
|
getRegistry: () => capabilityRegistry,
|
|
1265
1303
|
verifyToken: (t) => authService.verifyToken(t),
|
|
1266
1304
|
// The hub's public endpoint from the `local-network` cap (the flagged
|
|
1267
1305
|
// address, else tunnel, then mesh, then LAN). `localhost` only when the
|
|
1268
1306
|
// palette names nothing — the dev case, where it is the truth.
|
|
1269
|
-
publicHubUrl: () => resolveHubBaseUrl(() => capabilityRegistry.getSingleton('local-network'), 'publicEndpoint').catch(() => `https://localhost:${port}`),
|
|
1307
|
+
publicHubUrl: () => (0, hub_cluster_url_1.resolveHubBaseUrl)(() => capabilityRegistry.getSingleton('local-network'), 'publicEndpoint').catch(() => `https://localhost:${port}`),
|
|
1270
1308
|
// Every /authorize refusal is a dropped account-linking attempt. Without
|
|
1271
1309
|
// this scope the drop is invisible in Loki and the only signal left is an
|
|
1272
1310
|
// operator noticing that linking stopped working.
|
|
1273
|
-
logger: app.get(LoggingService).createLogger('oauth2'),
|
|
1311
|
+
logger: app.get(logging_service_1.LoggingService).createLogger('oauth2'),
|
|
1274
1312
|
});
|
|
1275
1313
|
console.log('[bootstrap] OAuth2 routes registered at /api/oauth2/*');
|
|
1276
1314
|
// Attach tRPC WebSocket handler using noServer mode to avoid
|
|
@@ -1290,7 +1328,7 @@ async function bootstrap() {
|
|
|
1290
1328
|
// per viewer is exactly the kind of growth that is invisible until it is
|
|
1291
1329
|
// not. `threshold` leaves small frames (subscription ticks) alone, where
|
|
1292
1330
|
// framing overhead would exceed the saving.
|
|
1293
|
-
const wss = new WebSocketServer({
|
|
1331
|
+
const wss = new ws_2.WebSocketServer({
|
|
1294
1332
|
noServer: true,
|
|
1295
1333
|
perMessageDeflate: {
|
|
1296
1334
|
threshold: 1024,
|
|
@@ -1315,19 +1353,19 @@ async function bootstrap() {
|
|
|
1315
1353
|
// in the background, JS suspended, TCP open) queued 88 MB of JSON strings
|
|
1316
1354
|
// in hub-main's old_space with no bound and no line. See
|
|
1317
1355
|
// `ws-slow-consumer-guard.ts` for the policy and the alternatives it beat.
|
|
1318
|
-
const wsSlowConsumerGuard = new WsSlowConsumerGuard({
|
|
1319
|
-
logger: app.get(LoggingService).createLogger('tRPC:ws'),
|
|
1356
|
+
const wsSlowConsumerGuard = new ws_slow_consumer_guard_js_1.WsSlowConsumerGuard({
|
|
1357
|
+
logger: app.get(logging_service_1.LoggingService).createLogger('tRPC:ws'),
|
|
1320
1358
|
});
|
|
1321
1359
|
wsSlowConsumerGuard.start();
|
|
1322
1360
|
wss.on('connection', (client, req) => {
|
|
1323
|
-
attachWsCensusSession(httpRequestCensus, client, req, app.get(LoggingService).createLogger('tRPC:ws'));
|
|
1324
|
-
wsSlowConsumerGuard.attach(client, wsConnectionFacts(req));
|
|
1361
|
+
(0, ws_request_census_1.attachWsCensusSession)(httpRequestCensus, client, req, app.get(logging_service_1.LoggingService).createLogger('tRPC:ws'));
|
|
1362
|
+
wsSlowConsumerGuard.attach(client, (0, ws_slow_consumer_guard_js_1.wsConnectionFacts)(req));
|
|
1325
1363
|
});
|
|
1326
1364
|
// Revoking a login session ends what it holds: its sockets (close 4401
|
|
1327
1365
|
// `session-ended`) and its live media. See `auth/session-connections.ts`.
|
|
1328
|
-
const sessionConnections = getSessionConnections();
|
|
1329
|
-
sessionConnections.setLogger(app.get(LoggingService).createLogger('session-revocation'));
|
|
1330
|
-
onSessionsRevoked((event) => {
|
|
1366
|
+
const sessionConnections = (0, session_connections_js_1.getSessionConnections)();
|
|
1367
|
+
sessionConnections.setLogger(app.get(logging_service_1.LoggingService).createLogger('session-revocation'));
|
|
1368
|
+
(0, system_1.onSessionsRevoked)((event) => {
|
|
1331
1369
|
sessionConnections.endSessions({
|
|
1332
1370
|
sessionIds: event.sessionIds,
|
|
1333
1371
|
userId: event.userId,
|
|
@@ -1336,7 +1374,7 @@ async function bootstrap() {
|
|
|
1336
1374
|
reason: event.reason,
|
|
1337
1375
|
});
|
|
1338
1376
|
});
|
|
1339
|
-
applyWSSHandler({
|
|
1377
|
+
(0, ws_1.applyWSSHandler)({
|
|
1340
1378
|
wss,
|
|
1341
1379
|
router: appRouter,
|
|
1342
1380
|
// The complement of the bound above, for the SUSPENDED client: a PING is
|
|
@@ -1349,22 +1387,22 @@ async function bootstrap() {
|
|
|
1349
1387
|
// A termination here closes with 1006; the guard's close line names it.
|
|
1350
1388
|
keepAlive: { enabled: true, pingMs: 30_000, pongWaitMs: 10_000 },
|
|
1351
1389
|
createContext: async (opts) => {
|
|
1352
|
-
const wsCtx = await createWsTrpcContext(opts, authService, addonRegistry, shareTokenService, app.get(LoggingService).createLogger('tRPC:ws'));
|
|
1390
|
+
const wsCtx = await (0, trpc_context_1.createWsTrpcContext)(opts, authService, addonRegistry, shareTokenService, app.get(logging_service_1.LoggingService).createLogger('tRPC:ws'));
|
|
1353
1391
|
// The connection's identity, derived ONCE and reused for every
|
|
1354
1392
|
// operation on this socket. Frames that arrived while the bearer was
|
|
1355
1393
|
// still resolving are held by the session and released here.
|
|
1356
|
-
const principal = describeTrpcPrincipal(wsCtx.user);
|
|
1357
|
-
identifyWsCensusSession(opts.res, principal);
|
|
1394
|
+
const principal = (0, trpc_error_principal_1.describeTrpcPrincipal)(wsCtx.user);
|
|
1395
|
+
(0, ws_request_census_1.identifyWsCensusSession)(opts.res, principal);
|
|
1358
1396
|
wsSlowConsumerGuard.identify(opts.res, principal);
|
|
1359
|
-
const connectionLogger = app.get(LoggingService).createLogger('tRPC:ws');
|
|
1397
|
+
const connectionLogger = app.get(logging_service_1.LoggingService).createLogger('tRPC:ws');
|
|
1360
1398
|
if (wsCtx.credentialRejected === true) {
|
|
1361
1399
|
// A bearer that resolves to nobody (revoked, expired): say so with
|
|
1362
1400
|
// the close code the client recognises, instead of leaving an
|
|
1363
1401
|
// anonymous socket open for the client to poll.
|
|
1364
1402
|
connectionLogger.info('Closing a socket whose credential was refused', {
|
|
1365
|
-
meta: { principal, code: SESSION_ENDED_CLOSE_CODE },
|
|
1403
|
+
meta: { principal, code: session_connections_js_1.SESSION_ENDED_CLOSE_CODE },
|
|
1366
1404
|
});
|
|
1367
|
-
opts.res.close(SESSION_ENDED_CLOSE_CODE, SESSION_ENDED_CLOSE_REASON);
|
|
1405
|
+
opts.res.close(session_connections_js_1.SESSION_ENDED_CLOSE_CODE, session_connections_js_1.SESSION_ENDED_CLOSE_REASON);
|
|
1368
1406
|
}
|
|
1369
1407
|
else if (wsCtx.user !== null) {
|
|
1370
1408
|
const untrack = sessionConnections.trackSocket(opts.res, {
|
|
@@ -1376,15 +1414,15 @@ async function bootstrap() {
|
|
|
1376
1414
|
return wsCtx;
|
|
1377
1415
|
},
|
|
1378
1416
|
onError: ({ path: trpcPath, error, ctx, input, }) => {
|
|
1379
|
-
const trpcLogger = app.get(LoggingService).createLogger('tRPC:ws');
|
|
1417
|
+
const trpcLogger = app.get(logging_service_1.LoggingService).createLogger('tRPC:ws');
|
|
1380
1418
|
trpcLogger.warn('tRPC error', {
|
|
1381
1419
|
// The socket the viewer uses — this is the transport that logged the
|
|
1382
1420
|
// four `intercom.startSession` refusals with no camera on them.
|
|
1383
|
-
tags: trpcErrorDeviceTags(trpcPath, input),
|
|
1421
|
+
tags: (0, trpc_error_device_tags_1.trpcErrorDeviceTags)(trpcPath, input),
|
|
1384
1422
|
meta: {
|
|
1385
1423
|
code: error.code,
|
|
1386
1424
|
path: trpcPath ?? '?',
|
|
1387
|
-
principal: describeTrpcPrincipal(ctx?.user),
|
|
1425
|
+
principal: (0, trpc_error_principal_1.describeTrpcPrincipal)(ctx?.user),
|
|
1388
1426
|
message: error.message,
|
|
1389
1427
|
},
|
|
1390
1428
|
});
|
|
@@ -1406,7 +1444,7 @@ async function bootstrap() {
|
|
|
1406
1444
|
const pathname = (request.url ?? '').split('?')[0];
|
|
1407
1445
|
if (pathname === '/trpc') {
|
|
1408
1446
|
// CORS does not cover a WebSocket: refuse a foreign page here (D707).
|
|
1409
|
-
if (refuseForeignWsUpgrade(corsPolicy, request.headers, socket))
|
|
1447
|
+
if ((0, register_cors_policy_1.refuseForeignWsUpgrade)(corsPolicy, request.headers, socket))
|
|
1410
1448
|
return;
|
|
1411
1449
|
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
1412
1450
|
wss.emit('connection', ws, request);
|
|
@@ -1453,25 +1491,25 @@ async function bootstrap() {
|
|
|
1453
1491
|
// HUB-NODE-SCOPED resolution — never the cluster-global singleton. An agent
|
|
1454
1492
|
// node registers the same cap (agent-only placement) and its `getStaticDir()`
|
|
1455
1493
|
// answers with a path on the agent's filesystem.
|
|
1456
|
-
const capRegistry = app.get(AddonRegistryService).getCapabilityRegistry();
|
|
1494
|
+
const capRegistry = app.get(addon_registry_service_1.AddonRegistryService).getCapabilityRegistry();
|
|
1457
1495
|
return capRegistry?.getSingletonForNode(capName, 'hub') ?? null;
|
|
1458
1496
|
};
|
|
1459
|
-
const adminUi = createLazyUiServing({
|
|
1497
|
+
const adminUi = (0, lazy_ui_serving_js_1.createLazyUiServing)({
|
|
1460
1498
|
label: 'Admin UI',
|
|
1461
1499
|
// CAMSTACK_SKIP_ADMIN_UI_WAIT: e2e runs that do not need the SPA.
|
|
1462
1500
|
lookup: () => process.env['CAMSTACK_SKIP_ADMIN_UI_WAIT'] === '1' ? null : hubUiProvider('admin-ui'),
|
|
1463
1501
|
log: uiLogger,
|
|
1464
1502
|
onServed: ({ staticDir, indexPath }) => {
|
|
1465
1503
|
spaIndexHtml = indexPath;
|
|
1466
|
-
warmPrecompressedAssets(staticDir, (msg, meta) => console.log(`[static] ${msg} ${JSON.stringify(meta)}`));
|
|
1504
|
+
(0, precompressed_asset_js_1.warmPrecompressedAssets)(staticDir, (msg, meta) => console.log(`[static] ${msg} ${JSON.stringify(meta)}`));
|
|
1467
1505
|
},
|
|
1468
1506
|
});
|
|
1469
|
-
const viewerUi = createLazyUiServing({
|
|
1507
|
+
const viewerUi = (0, lazy_ui_serving_js_1.createLazyUiServing)({
|
|
1470
1508
|
label: 'Viewer UI',
|
|
1471
1509
|
lookup: () => hubUiProvider('viewer-ui'),
|
|
1472
1510
|
log: uiLogger,
|
|
1473
1511
|
onServed: ({ staticDir }) => {
|
|
1474
|
-
warmPrecompressedAssets(staticDir, (msg, meta) => console.log(`[static] ${msg} ${JSON.stringify(meta)}`));
|
|
1512
|
+
(0, precompressed_asset_js_1.warmPrecompressedAssets)(staticDir, (msg, meta) => console.log(`[static] ${msg} ${JSON.stringify(meta)}`));
|
|
1475
1513
|
},
|
|
1476
1514
|
});
|
|
1477
1515
|
const VIEWER_MOUNT = '/viewer/camstack';
|
|
@@ -1483,7 +1521,7 @@ async function bootstrap() {
|
|
|
1483
1521
|
// Unauthenticated by design — Apple's CDN and Android's verifier fetch these
|
|
1484
1522
|
// with no cookies; content-type must be application/json and no redirect.
|
|
1485
1523
|
{
|
|
1486
|
-
const { appleAppSiteAssociation, assetLinks } = buildAppLinkFiles(parseCertFingerprints(process.env['CAMSTACK_ANDROID_CERT_SHA256']));
|
|
1524
|
+
const { appleAppSiteAssociation, assetLinks } = (0, well_known_app_links_1.buildAppLinkFiles)((0, well_known_app_links_1.parseCertFingerprints)(process.env['CAMSTACK_ANDROID_CERT_SHA256']));
|
|
1487
1525
|
const aasa = JSON.stringify(appleAppSiteAssociation);
|
|
1488
1526
|
const assetlinks = JSON.stringify(assetLinks);
|
|
1489
1527
|
fastify.get('/.well-known/apple-app-site-association', async (_request, reply) => reply.type('application/json').send(aasa));
|
|
@@ -1512,18 +1550,18 @@ async function bootstrap() {
|
|
|
1512
1550
|
if (rel && /\.[a-zA-Z0-9]+$/.test(pathOnly)) {
|
|
1513
1551
|
const abs = path.join(staticDir, rel);
|
|
1514
1552
|
if ((abs === staticDir || abs.startsWith(staticDir + path.sep)) && fs.existsSync(abs)) {
|
|
1515
|
-
reply.header('cache-control', spaAssetCacheControl(rel));
|
|
1516
|
-
reply.type(contentTypeForPath(rel));
|
|
1553
|
+
reply.header('cache-control', (0, spa_static_1.spaAssetCacheControl)(rel));
|
|
1554
|
+
reply.type((0, spa_static_1.contentTypeForPath)(rel));
|
|
1517
1555
|
return sendMaybePrecompressed(reply, abs, request.headers['accept-encoding']);
|
|
1518
1556
|
}
|
|
1519
1557
|
return reply.callNotFound();
|
|
1520
1558
|
}
|
|
1521
|
-
reply.header('cache-control', spaShellCacheControl());
|
|
1559
|
+
reply.header('cache-control', (0, spa_static_1.spaShellCacheControl)());
|
|
1522
1560
|
return reply.type('text/html').send(fs.createReadStream(indexPath));
|
|
1523
1561
|
});
|
|
1524
1562
|
fastify.get('/*', async (request, reply) => {
|
|
1525
1563
|
const url = request.url;
|
|
1526
|
-
if (isRetiredPublicPath(url))
|
|
1564
|
+
if ((0, spa_static_1.isRetiredPublicPath)(url))
|
|
1527
1565
|
return reply.callNotFound();
|
|
1528
1566
|
if (url.startsWith('/trpc') ||
|
|
1529
1567
|
url.startsWith('/api/') ||
|
|
@@ -1545,14 +1583,14 @@ async function bootstrap() {
|
|
|
1545
1583
|
const rel = pathOnly.replace(/^\/+/, '');
|
|
1546
1584
|
const abs = path.join(staticDir, rel);
|
|
1547
1585
|
if ((abs === staticDir || abs.startsWith(staticDir + path.sep)) && fs.existsSync(abs)) {
|
|
1548
|
-
reply.header('cache-control', spaAssetCacheControl(rel));
|
|
1586
|
+
reply.header('cache-control', (0, spa_static_1.spaAssetCacheControl)(rel));
|
|
1549
1587
|
return sendMaybePrecompressed(reply, abs, request.headers['accept-encoding']);
|
|
1550
1588
|
}
|
|
1551
1589
|
return reply.callNotFound();
|
|
1552
1590
|
}
|
|
1553
1591
|
// A relayed navigation (`X-Forwarded-Prefix`) gets a shell that says where
|
|
1554
1592
|
// it is mounted; without the header the shell is served as before.
|
|
1555
|
-
return sendSpaShell(reply, indexPath, request.headers);
|
|
1593
|
+
return (0, spa_mount_1.sendSpaShell)(reply, indexPath, request.headers);
|
|
1556
1594
|
});
|
|
1557
1595
|
// Boot-time attempt, after listen. Later attempts are driven by requests.
|
|
1558
1596
|
const resolveAdminUi = async () => {
|
|
@@ -1573,12 +1611,12 @@ async function bootstrap() {
|
|
|
1573
1611
|
// fails to boot, hence the catch — and a restore that fails leaves the
|
|
1574
1612
|
// mirror at its default rather than inventing a level (D49).
|
|
1575
1613
|
try {
|
|
1576
|
-
const settingsStore = buildSettingsStoreGateway(capabilityRegistry);
|
|
1614
|
+
const settingsStore = (0, cap_providers_1.buildSettingsStoreGateway)(capabilityRegistry);
|
|
1577
1615
|
const loggingLogger = loggingService.createLogger('logging-settings');
|
|
1578
|
-
await new LoggingSettingsService({
|
|
1616
|
+
await new logging_settings_1.LoggingSettingsService({
|
|
1579
1617
|
store: settingsStore,
|
|
1580
|
-
gate: getLoggingGate(),
|
|
1581
|
-
requestCensus: new RequestCensusService({
|
|
1618
|
+
gate: (0, system_1.getLoggingGate)(),
|
|
1619
|
+
requestCensus: new request_census_settings_1.RequestCensusService({
|
|
1582
1620
|
census: httpRequestCensus,
|
|
1583
1621
|
store: settingsStore,
|
|
1584
1622
|
logger: loggingLogger,
|
|
@@ -1590,7 +1628,7 @@ async function bootstrap() {
|
|
|
1590
1628
|
console.warn('[bootstrap] logging settings restore skipped:', censusErr instanceof Error ? censusErr.message : censusErr);
|
|
1591
1629
|
}
|
|
1592
1630
|
try {
|
|
1593
|
-
const listenHost = allFamiliesListenHost(host).host;
|
|
1631
|
+
const listenHost = (0, system_1.allFamiliesListenHost)(host).host;
|
|
1594
1632
|
try {
|
|
1595
1633
|
await app.listen(port, listenHost);
|
|
1596
1634
|
}
|
|
@@ -1613,15 +1651,15 @@ async function bootstrap() {
|
|
|
1613
1651
|
}
|
|
1614
1652
|
throw listenErr;
|
|
1615
1653
|
}
|
|
1616
|
-
const logger = app.get(LoggingService).createLogger('System');
|
|
1654
|
+
const logger = app.get(logging_service_1.LoggingService).createLogger('System');
|
|
1617
1655
|
const protocol = tlsOptions ? 'https' : 'http';
|
|
1618
1656
|
logger.info('CamStack server listening', { meta: { protocol, host, port, trpcRegistered } });
|
|
1619
1657
|
// Certificate actions (Network → Local access) swap the served certificate
|
|
1620
1658
|
// in place through this registration — without it an upload sat on disk
|
|
1621
1659
|
// while the listener kept serving the boot-time leaf (D726).
|
|
1622
1660
|
if (tlsOptions) {
|
|
1623
|
-
if (fastify.server instanceof
|
|
1624
|
-
registerHttpsListener(fastify.server, tlsOptions);
|
|
1661
|
+
if (fastify.server instanceof node_tls_1.Server) {
|
|
1662
|
+
(0, system_1.registerHttpsListener)(fastify.server, tlsOptions);
|
|
1625
1663
|
}
|
|
1626
1664
|
else {
|
|
1627
1665
|
logger.warn('HTTPS listener is not a TLS server — certificate changes need a restart');
|
|
@@ -1630,7 +1668,7 @@ async function bootstrap() {
|
|
|
1630
1668
|
// LAN HTTP sibling — same Fastify request graph, dedicated port. Handler
|
|
1631
1669
|
// is registered as soon as we have the instance; bind happens after HTTPS
|
|
1632
1670
|
// is up so a failed HTTPS listen does not leave HTTP serving alone.
|
|
1633
|
-
registerLanHttpHandler({
|
|
1671
|
+
(0, system_1.registerLanHttpHandler)({
|
|
1634
1672
|
onRequest: (req, res) => {
|
|
1635
1673
|
fastify.server.emit('request', req, res);
|
|
1636
1674
|
},
|
|
@@ -1639,7 +1677,7 @@ async function bootstrap() {
|
|
|
1639
1677
|
},
|
|
1640
1678
|
});
|
|
1641
1679
|
try {
|
|
1642
|
-
const lanHttp = await bindPendingLanHttp();
|
|
1680
|
+
const lanHttp = await (0, system_1.bindPendingLanHttp)();
|
|
1643
1681
|
if (lanHttp.listening) {
|
|
1644
1682
|
logger.info('LAN HTTP listening', { meta: { port: lanHttp.port } });
|
|
1645
1683
|
}
|
|
@@ -1656,17 +1694,17 @@ async function bootstrap() {
|
|
|
1656
1694
|
// state switches from 503 to static serving as soon as each capability is up.
|
|
1657
1695
|
void Promise.all([resolveAdminUi(), resolveViewerUi()]);
|
|
1658
1696
|
// Post-boot: fork workers, register device streams, emit system.boot
|
|
1659
|
-
const postBoot = app.get(PostBootService);
|
|
1697
|
+
const postBoot = app.get(post_boot_service_1.PostBootService);
|
|
1660
1698
|
await postBoot.run({ port, host, dataPath, trpcRegistered, tlsCert });
|
|
1661
1699
|
// D877: ONE check, ~60 s after the boot sequence, of the runners this node
|
|
1662
1700
|
// planned against what its process service holds. Stored in memory and served
|
|
1663
1701
|
// on `getServerPackageStatus` / `/health`; not a timer loop.
|
|
1664
|
-
app.get(RunnerBootCheckService).scheduleAfterBoot();
|
|
1702
|
+
app.get(runner_boot_check_1.RunnerBootCheckService).scheduleAfterBoot();
|
|
1665
1703
|
// The hub reached ready — when this boot is the PROBATION boot of a freshly
|
|
1666
1704
|
// staged @camstack/server root, promote it (currentVersion ← pending, N-1
|
|
1667
1705
|
// retained for rollback) and disarm the starter's crash-loop auto-rollback.
|
|
1668
1706
|
try {
|
|
1669
|
-
const confirm = app.get(ServerUpdateService).confirmBootHealthy();
|
|
1707
|
+
const confirm = app.get(server_update_service_1.ServerUpdateService).confirmBootHealthy();
|
|
1670
1708
|
if (confirm.promoted !== null) {
|
|
1671
1709
|
logger.info('Server root package update confirmed healthy', {
|
|
1672
1710
|
meta: { version: confirm.promoted },
|
|
@@ -1690,7 +1728,7 @@ async function bootstrap() {
|
|
|
1690
1728
|
// seeds them for exactly the boot that would otherwise fail. The agent runs
|
|
1691
1729
|
// the SAME function at its own confirmation point; neither role owns a
|
|
1692
1730
|
// private idea of what may be deleted.
|
|
1693
|
-
void runSingleCopyCleanup({
|
|
1731
|
+
void (0, single_copy_cleanup_runner_js_1.runSingleCopyCleanup)({
|
|
1694
1732
|
dataDir: dataPath,
|
|
1695
1733
|
addonRoot: process.env['CAMSTACK_ADDONS_DIR'] ?? path.join(dataPath, 'addons'),
|
|
1696
1734
|
log: (line) => logger.info(line),
|
|
@@ -1706,7 +1744,7 @@ async function bootstrap() {
|
|
|
1706
1744
|
const listAll = dmForBackfill.listAll;
|
|
1707
1745
|
const setIntegrationId = dmForBackfill.setIntegrationId;
|
|
1708
1746
|
const backfillLogger = loggingService.createLogger('integration-backfill');
|
|
1709
|
-
await runIntegrationIdBackfill({
|
|
1747
|
+
await (0, integration_id_backfill_1.runIntegrationIdBackfill)({
|
|
1710
1748
|
listIntegrations: async () => (await integrationRegistry.listIntegrations()).map((i) => ({
|
|
1711
1749
|
id: i.id,
|
|
1712
1750
|
addonId: i.addonId,
|