@camstack/server 1.2.592 → 1.2.594
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon-root-inventory.js +11 -50
- package/dist/agent/addon-scan.js +6 -44
- package/dist/agent/agent-addon-runtime.js +3 -8
- package/dist/agent/agent-addon-updates.js +12 -52
- package/dist/agent/agent-cap-dispatch-service.js +3 -5
- package/dist/agent/agent-config.js +7 -42
- package/dist/agent/agent-deploy-swap.js +5 -41
- package/dist/agent/agent-group-runner.js +8 -47
- package/dist/agent/agent-http-auth.js +10 -22
- package/dist/agent/agent-http.js +69 -115
- package/dist/agent/agent-hub-addon-update.js +10 -16
- package/dist/agent/agent-hub-registration.js +4 -7
- package/dist/agent/agent-infra-capabilities.js +5 -9
- package/dist/agent/agent-json-file.js +5 -42
- package/dist/agent/agent-mesh-gate.js +5 -8
- package/dist/agent/agent-node-certificates.js +25 -28
- package/dist/agent/agent-pairing-local.js +10 -47
- package/dist/agent/agent-pairing-routes.js +16 -20
- package/dist/agent/agent-pairing-store.js +18 -58
- package/dist/agent/agent-reconnect.js +1 -4
- package/dist/agent/agent-service.js +42 -78
- package/dist/agent/agent-sniffing-listener.js +11 -48
- package/dist/agent/agent-undeploy.js +5 -41
- package/dist/agent/agent-update-routes.js +14 -19
- package/dist/agent/agent-update-service.js +38 -80
- package/dist/agent/apply-model-distribution.js +1 -4
- package/dist/agent/apply-stage-dev-uploads.js +6 -9
- package/dist/agent/derive-hub-url.js +3 -8
- package/dist/agent/fetch-bundle-from-hub.js +6 -9
- package/dist/agent/hubs-found.js +6 -43
- package/dist/agent/infra-boot-guard.js +1 -4
- package/dist/agent/infra-boot-plan.js +2 -6
- package/dist/agent/main.js +158 -186
- package/dist/agent/register-agent-cap-dispatch.js +3 -6
- package/dist/agent/serial-queue.js +2 -7
- package/dist/agent-status-page.js +1 -4
- package/dist/api/addon-upload.js +22 -61
- package/dist/api/agent-addon-delivery.js +6 -11
- package/dist/api/auth-whoami.js +1 -4
- package/dist/api/backup-download-pump.js +5 -9
- package/dist/api/backup-download.js +7 -10
- package/dist/api/core/addon-settings.router.js +16 -19
- package/dist/api/core/agent-pairing.router.js +76 -79
- package/dist/api/core/agents.router.js +21 -24
- package/dist/api/core/auth-admin-tokens.procedures.js +48 -52
- package/dist/api/core/auth-device-cert.procedures.js +62 -67
- package/dist/api/core/auth-limits.js +16 -25
- package/dist/api/core/auth-reauth.procedures.js +32 -37
- package/dist/api/core/auth-revoke-credentials.procedures.js +22 -26
- package/dist/api/core/auth-sessions.procedures.js +52 -56
- package/dist/api/core/auth.router.js +300 -304
- package/dist/api/core/cap-providers.js +74 -121
- package/dist/api/core/capabilities.router.js +34 -37
- package/dist/api/core/capability-preference-writes.js +10 -17
- package/dist/api/core/certificates.router.js +106 -109
- package/dist/api/core/cluster-nodes.router.js +15 -18
- package/dist/api/core/collection-preference.js +2 -6
- package/dist/api/core/event-bus-proxy.router.js +34 -37
- package/dist/api/core/failure-contributions.js +4 -8
- package/dist/api/core/hwaccel.router.js +17 -20
- package/dist/api/core/integration-secrets.js +8 -12
- package/dist/api/core/lifecycle-job-runner.js +13 -49
- package/dist/api/core/live-events.router.js +29 -32
- package/dist/api/core/load-contributions.js +4 -8
- package/dist/api/core/logging-settings.js +30 -43
- package/dist/api/core/logs.router.js +40 -43
- package/dist/api/core/notifications.router.js +15 -18
- package/dist/api/core/public-event-filter.js +4 -8
- package/dist/api/core/repl.router.js +18 -21
- package/dist/api/core/request-census-settings.js +11 -16
- package/dist/api/core/server-management.provider.js +1 -4
- package/dist/api/core/server-name.js +9 -17
- package/dist/api/core/site-location.js +16 -24
- package/dist/api/core/stream-probe.router.js +21 -24
- package/dist/api/core/system-events.router.js +23 -26
- package/dist/api/cors/cors-policy.js +20 -29
- package/dist/api/cors/register-cors-policy.js +9 -14
- package/dist/api/deploy-stage-registry.js +6 -10
- package/dist/api/dev-uploads-bundle.js +12 -50
- package/dist/api/health/adaptive-probe.routes.js +9 -13
- package/dist/api/health/health.routes.js +8 -13
- package/dist/api/hub-cluster-url.js +3 -9
- package/dist/api/model-distributor.js +12 -50
- package/dist/api/oauth2/consent-page.js +10 -13
- package/dist/api/oauth2/oauth2-routes.js +17 -25
- package/dist/api/oauth2/private-host.js +1 -4
- package/dist/api/server-upload-propagate.js +15 -51
- package/dist/api/server-upload.js +13 -50
- package/dist/api/sse-no-compression.js +1 -4
- package/dist/api/static/frame-policy.js +4 -9
- package/dist/api/static/precompressed-asset.js +15 -57
- package/dist/api/static/spa-mount.js +8 -47
- package/dist/api/static/spa-static.js +5 -12
- package/dist/api/tarball-manifest.js +7 -44
- package/dist/api/trpc/cap-mount-helpers.js +7 -12
- package/dist/api/trpc/cap-route-error-formatter.js +10 -13
- package/dist/api/trpc/cap-router-runtime.js +40 -51
- package/dist/api/trpc/client-ip.js +9 -20
- package/dist/api/trpc/core-cap-bridge.js +32 -42
- package/dist/api/trpc/device-collection-dispatch.js +23 -27
- package/dist/api/trpc/device-config-secret-redaction.js +24 -40
- package/dist/api/trpc/generated-cap-mounts.js +219 -221
- package/dist/api/trpc/generated-cap-routers.js +4878 -4726
- package/dist/api/trpc/http-request-census-hook.js +8 -11
- package/dist/api/trpc/http-request-census.js +34 -41
- package/dist/api/trpc/http-request-census.singleton.js +4 -8
- package/dist/api/trpc/localized-schema-paths.js +1 -4
- package/dist/api/trpc/principal-visibility.js +14 -22
- package/dist/api/trpc/remote-addon-update-grant.js +1 -4
- package/dist/api/trpc/scope-access.js +10 -15
- package/dist/api/trpc/server-provided-caps.js +3 -7
- package/dist/api/trpc/share-view-access.js +6 -14
- package/dist/api/trpc/trpc-error-device-tags.js +3 -6
- package/dist/api/trpc/trpc-error-principal.js +2 -6
- package/dist/api/trpc/trpc.context.js +20 -25
- package/dist/api/trpc/trpc.middleware.js +38 -46
- package/dist/api/trpc/trpc.router.js +58 -99
- package/dist/api/trpc/user-error.js +5 -8
- package/dist/api/trpc/ws-request-census.js +17 -24
- package/dist/api/trpc/ws-slow-consumer-guard.js +11 -16
- package/dist/api/upload-auth.js +5 -9
- package/dist/auth/addon-route-jwt-gate.js +4 -7
- package/dist/auth/addon-route-share-gate.js +7 -12
- package/dist/auth/app-confirm-page.js +17 -22
- package/dist/auth/app-confirm-routes.js +26 -31
- package/dist/auth/app-confirmations.js +7 -44
- package/dist/auth/app-page-shell.js +17 -30
- package/dist/auth/app-page-strings.js +11 -17
- package/dist/auth/app-passkey-page.js +16 -21
- package/dist/auth/app-passkey-routes.js +37 -41
- package/dist/auth/app-refused-route.js +13 -18
- package/dist/auth/auth-network-policy.js +11 -15
- package/dist/auth/auth-provider-gate.js +4 -9
- package/dist/auth/auth-rate-limit.js +3 -7
- package/dist/auth/client-address.js +6 -9
- package/dist/auth/device-enroll-proofs.js +6 -43
- package/dist/auth/external-link-intents.js +3 -7
- package/dist/auth/hub-sessions.js +6 -12
- package/dist/auth/native-link-completions.js +7 -11
- package/dist/auth/native-return.js +9 -13
- package/dist/auth/passkey-provider.js +26 -32
- package/dist/auth/second-factors.js +6 -10
- package/dist/auth/session-connections.js +6 -12
- package/dist/auth/session-cookie.js +12 -23
- package/dist/auth/session-lifetimes.js +8 -12
- package/dist/auth/session-mint.js +4 -11
- package/dist/auth/sso-finish-app.js +13 -16
- package/dist/auth/sso-finish-deps.js +21 -27
- package/dist/auth/sso-finish.js +28 -38
- package/dist/auth/sso-routes.js +22 -25
- package/dist/auth/used-bridge-ids.js +1 -5
- package/dist/boot/boot-config.js +16 -55
- package/dist/boot/init-sequence.js +1 -4
- package/dist/boot/integration-id-backfill.js +3 -8
- package/dist/boot/platform-keychain-key.js +5 -42
- package/dist/boot/post-boot.service.js +14 -18
- package/dist/boot/reconcile-lifecycle-jobs.js +3 -6
- package/dist/boot/retired-public-url-env.js +4 -8
- package/dist/bootstrap-packages.js +1 -4
- package/dist/closure-node-modules.js +2 -38
- package/dist/closure-patches/patch-reach.json +6 -2
- package/dist/core/addon/addon-call-gateway.js +1 -5
- package/dist/core/addon/addon-package.service.js +83 -123
- package/dist/core/addon/addon-process-view.js +2 -6
- package/dist/core/addon/addon-realign-plan.js +1 -4
- package/dist/core/addon/addon-registry.service.js +254 -197
- package/dist/core/addon/addon-row-manifest.js +1 -4
- package/dist/core/addon/addon-search.service.js +3 -7
- package/dist/core/addon/addon-settings-provider.js +1 -3
- package/dist/core/addon/addon-uninstall.js +4 -11
- package/dist/core/addon/addon.tokens.js +2 -5
- package/dist/core/addon/device-meta-mirror.js +8 -13
- package/dist/core/addon/forked-custom-actions.js +6 -11
- package/dist/core/addon/integration-visibility.js +3 -6
- package/dist/core/addon/materialize-route-path.js +1 -4
- package/dist/core/addon/package-dir-utils.js +8 -45
- package/dist/core/addon/prune-misplaced-addons.js +5 -43
- package/dist/core/addon/runner-convergence.js +1 -4
- package/dist/core/addon/runner-serialization.js +1 -4
- package/dist/core/addon/runner-spawn-fanout.js +3 -8
- package/dist/core/addon/settings-door-wiring.js +5 -8
- package/dist/core/addon/single-flight-refresh.js +1 -4
- package/dist/core/addon-bridge/addon-bridge.service.js +7 -44
- package/dist/core/addon-pages/addon-pages.service.js +3 -40
- package/dist/core/addon-widgets/addon-widgets.service.js +4 -42
- package/dist/core/agent/agent-addon-backfill.js +9 -17
- package/dist/core/agent/agent-delivery-ledger.js +3 -7
- package/dist/core/agent/agent-liveness-event.js +2 -6
- package/dist/core/agent/agent-pairing-http.js +41 -45
- package/dist/core/agent/agent-registry.service.js +53 -92
- package/dist/core/agent/cluster-node-history-mirror.js +3 -7
- package/dist/core/agent/cluster-node-history-store.js +113 -58
- package/dist/core/agent/hub-agent-pairing.js +1 -5
- package/dist/core/agent/node-certificates-client.js +3 -6
- package/dist/core/agent/node-directory.js +1 -4
- package/dist/core/app-links/well-known-app-links.js +2 -6
- package/dist/core/auth/auth.service.js +3 -8
- package/dist/core/auth/handoff-code.service.js +11 -49
- package/dist/core/auth/record-kinds.js +35 -0
- package/dist/core/auth/share-token.service.js +174 -122
- package/dist/core/capability/capability.service.js +1 -5
- package/dist/core/config/config.schema.js +1 -6
- package/dist/core/config/config.service.js +2 -6
- package/dist/core/events/event-bus.service.js +3 -7
- package/dist/core/feature/feature.service.js +2 -6
- package/dist/core/lifecycle/lifecycle-runner.singleton.js +5 -10
- package/dist/core/lifecycle/lifecycle-state-machine.js +1 -5
- package/dist/core/logging/log-ring-buffer.js +1 -5
- package/dist/core/logging/logging.service.js +5 -9
- package/dist/core/logging/scoped-logger.js +1 -5
- package/dist/core/moleculer/agent-readiness-pull.js +1 -4
- package/dist/core/moleculer/agent-registration-request.js +3 -7
- package/dist/core/moleculer/cap-call-fn.js +39 -5
- package/dist/core/moleculer/cap-route-authority.js +3 -8
- package/dist/core/moleculer/hub-mesh-guard.js +5 -9
- package/dist/core/moleculer/moleculer.service.js +108 -119
- package/dist/core/network/network-quality.service.js +2 -6
- package/dist/core/notification/notification-wrapper.service.js +3 -7
- package/dist/core/notification/toast-wrapper.service.js +3 -7
- package/dist/core/provider/provider.tokens.js +1 -4
- package/dist/core/repl/repl-engine.service.js +4 -8
- package/dist/core/runner-health/runner-boot-check.js +7 -15
- package/dist/core/runner-health/update-preflight.js +9 -14
- package/dist/core/server-update/server-update.service.js +12 -49
- package/dist/core/server-update/system-apply-closure-patches.js +6 -42
- package/dist/core/server-update/system-ensure-prebuilds.js +3 -6
- package/dist/core/server-update/system-exec-npm.js +2 -5
- package/dist/core/storage/fs-storage-backend.js +1 -5
- package/dist/core/storage/storage-location-manager.js +1 -5
- package/dist/core/storage/storage.service.js +2 -6
- package/dist/core/streaming/ffmpeg-stream-info.js +3 -8
- package/dist/core/streaming/stream-probe.service.js +12 -16
- package/dist/core/streaming/ttl-cache.js +1 -5
- package/dist/core/topology/topology-emitter.service.js +19 -23
- package/dist/core/update-availability-emitter.js +3 -7
- package/dist/core/update-availability-store.js +8 -45
- package/dist/core/updates/agent-installed-packages.js +5 -9
- package/dist/core/updates/restart-marker.js +3 -8
- package/dist/core/updates/update-check-scheduler.js +13 -18
- package/dist/core/updates/wrapper-update-checker.js +3 -7
- package/dist/first-boot-addon-plan.js +2 -6
- package/dist/framework-nodepath.js +2 -38
- package/dist/i18n/request-lang.js +7 -11
- package/dist/launcher.js +30 -65
- package/dist/lifecycle-journal-path.js +2 -38
- package/dist/main.js +287 -324
- package/dist/manual-boot.js +120 -157
- package/dist/node-role.js +1 -4
- package/dist/package-inventory.js +7 -48
- package/dist/pending-restore.js +7 -43
- package/dist/single-copy-cleanup-runner.js +9 -45
- package/dist/single-copy-cleanup.js +7 -15
- package/dist/sqlite-restore.js +9 -48
- package/dist/starter.js +4 -39
- package/dist/ui-serving/lazy-ui-serving.js +3 -39
- package/package.json +13 -13
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const types_1 = require("@camstack/types");
|
|
8
|
-
const auth_network_policy_js_1 = require("../../auth/auth-network-policy.js");
|
|
9
|
-
const share_token_service_js_1 = require("../../core/auth/share-token.service.js");
|
|
10
|
-
const request_lang_js_1 = require("../../i18n/request-lang.js");
|
|
11
|
-
const trpc_error_principal_js_1 = require("./trpc-error-principal.js");
|
|
1
|
+
import { ADMIN_TOKEN_PREFIX, getUserManagementInternal } from '@camstack/system';
|
|
2
|
+
import { classifyBearerPrincipal, normalizeTokenScopes } from '@camstack/types';
|
|
3
|
+
import { DEFAULT_AUTH_NETWORK_POLICY } from '../../auth/auth-network-policy.js';
|
|
4
|
+
import { SHARE_TOKEN_PREFIX, } from '../../core/auth/share-token.service.js';
|
|
5
|
+
import { requestLangInputFrom, resolveRequestLang } from '../../i18n/request-lang.js';
|
|
6
|
+
import { readCredentialIdentity } from './trpc-error-principal.js';
|
|
12
7
|
/**
|
|
13
8
|
* Live-scope refresh memo (see the JWT branch of `resolveUser`).
|
|
14
9
|
*
|
|
@@ -36,7 +31,7 @@ async function refreshScopesFromStore(userId, addonRegistry) {
|
|
|
36
31
|
? (await userMgmt.listUsers()).find((u) => u.id === userId)
|
|
37
32
|
: null;
|
|
38
33
|
if (fresh)
|
|
39
|
-
scopes =
|
|
34
|
+
scopes = normalizeTokenScopes(fresh.scopes ?? []);
|
|
40
35
|
}
|
|
41
36
|
catch {
|
|
42
37
|
scopes = null;
|
|
@@ -92,7 +87,7 @@ function extractTokenFromRequest(req) {
|
|
|
92
87
|
function requestFacts(req) {
|
|
93
88
|
if (req === undefined)
|
|
94
89
|
return {};
|
|
95
|
-
const ip =
|
|
90
|
+
const ip = DEFAULT_AUTH_NETWORK_POLICY.clientAddress(req).ip;
|
|
96
91
|
const url = req.url;
|
|
97
92
|
const path = typeof url === 'string' ? url.split('?')[0] : undefined;
|
|
98
93
|
return { ...(path !== undefined ? { path } : {}), ...(ip !== null ? { ip } : {}) };
|
|
@@ -103,7 +98,7 @@ function requestFacts(req) {
|
|
|
103
98
|
* an admin, not revoked, not expired) is local-auth's (`AdminTokenManager`).
|
|
104
99
|
*/
|
|
105
100
|
async function resolveAdminToken(token, addonRegistry, facts) {
|
|
106
|
-
const internal =
|
|
101
|
+
const internal = getUserManagementInternal(addonRegistry.getCapabilityRegistry().getSingleton('user-management'));
|
|
107
102
|
if (internal === null)
|
|
108
103
|
return null;
|
|
109
104
|
const record = await internal.adminTokens.validate(token).catch(() => null);
|
|
@@ -133,13 +128,13 @@ async function resolveAdminToken(token, addonRegistry, facts) {
|
|
|
133
128
|
async function resolveUser(token, authService, addonRegistry, shareTokens = null, logger = null, facts = {}) {
|
|
134
129
|
if (!token)
|
|
135
130
|
return null;
|
|
136
|
-
if (token.startsWith(
|
|
131
|
+
if (token.startsWith(ADMIN_TOKEN_PREFIX))
|
|
137
132
|
return resolveAdminToken(token, addonRegistry, facts);
|
|
138
133
|
// Share-token path (`csv_*`): resolve through the ShareTokenService.
|
|
139
134
|
// The synthetic principal is maximally restricted — non-admin, no
|
|
140
135
|
// scopes; the `shareView` grant routes it into the fail-closed
|
|
141
136
|
// allowlist in `protectedProcedure` instead of the scope matcher.
|
|
142
|
-
if (token.startsWith(
|
|
137
|
+
if (token.startsWith(SHARE_TOKEN_PREFIX)) {
|
|
143
138
|
if (!shareTokens)
|
|
144
139
|
return null;
|
|
145
140
|
try {
|
|
@@ -191,7 +186,7 @@ async function resolveUser(token, authService, addonRegistry, shareTokens = null
|
|
|
191
186
|
isScoped: true,
|
|
192
187
|
// Migrate any v2 `device:targets` grant to a v3 selector at the
|
|
193
188
|
// boundary so the enforcement matcher only ever sees v3.
|
|
194
|
-
scopes:
|
|
189
|
+
scopes: normalizeTokenScopes(record.scopes),
|
|
195
190
|
};
|
|
196
191
|
}
|
|
197
192
|
catch {
|
|
@@ -212,7 +207,7 @@ async function resolveUser(token, authService, addonRegistry, shareTokens = null
|
|
|
212
207
|
}
|
|
213
208
|
// What the token IS decides both WHETHER it authenticates at all and
|
|
214
209
|
// WHERE its scopes come from.
|
|
215
|
-
const principal =
|
|
210
|
+
const principal = classifyBearerPrincipal(payload);
|
|
216
211
|
// ── The allowlist ────────────────────────────────────────────────
|
|
217
212
|
// Every token this hub mints verifies under the same `auth.jwtSecret`, so
|
|
218
213
|
// `verifyToken` succeeding means "we minted this", never "this is an API
|
|
@@ -244,7 +239,7 @@ async function resolveUser(token, authService, addonRegistry, shareTokens = null
|
|
|
244
239
|
// What the token says it IS. An `oauth-access` token is an account link,
|
|
245
240
|
// and until this was carried onto the principal a refusal of one was
|
|
246
241
|
// indistinguishable in the logs from a refusal of a browser session.
|
|
247
|
-
const credential =
|
|
242
|
+
const credential = readCredentialIdentity(payload);
|
|
248
243
|
return {
|
|
249
244
|
id: payload.userId ?? 'unknown',
|
|
250
245
|
username: payload.username ?? 'unknown',
|
|
@@ -280,7 +275,7 @@ async function resolveUser(token, authService, addonRegistry, shareTokens = null
|
|
|
280
275
|
// Assistant grant with `[]` and the hub refused the component's first
|
|
281
276
|
// call with `Have: (none)` (2026-08-19). The user store knows nothing
|
|
282
277
|
// about a link and must not get a vote on one.
|
|
283
|
-
...(payload.scopes !== undefined ? { scopes:
|
|
278
|
+
...(payload.scopes !== undefined ? { scopes: normalizeTokenScopes(payload.scopes) } : {}),
|
|
284
279
|
...(!payload.isAdmin && principal.kind === 'session'
|
|
285
280
|
? await (async () => {
|
|
286
281
|
const fresh = await refreshScopesFromStore(payload.userId ?? 'unknown', addonRegistry);
|
|
@@ -331,7 +326,7 @@ function makeDeviceScopeLookup(addonRegistry) {
|
|
|
331
326
|
* next step once the mesh census has measured what each node calls (D802).
|
|
332
327
|
* There is no HTTP request behind the call.
|
|
333
328
|
*/
|
|
334
|
-
function createMeshTrpcContext(principal = 'mesh') {
|
|
329
|
+
export function createMeshTrpcContext(principal = 'mesh') {
|
|
335
330
|
const user = {
|
|
336
331
|
id: principal,
|
|
337
332
|
username: principal,
|
|
@@ -342,12 +337,12 @@ function createMeshTrpcContext(principal = 'mesh') {
|
|
|
342
337
|
return { user };
|
|
343
338
|
}
|
|
344
339
|
/** Context factory for HTTP tRPC requests (Fastify adapter). */
|
|
345
|
-
async function createTrpcContext(req, authService, addonRegistry, shareTokens = null, logger = null) {
|
|
340
|
+
export async function createTrpcContext(req, authService, addonRegistry, shareTokens = null, logger = null) {
|
|
346
341
|
const token = extractTokenFromRequest(req);
|
|
347
342
|
return {
|
|
348
343
|
user: await resolveUser(token, authService, addonRegistry, shareTokens, logger, requestFacts(req)),
|
|
349
344
|
req,
|
|
350
|
-
lang:
|
|
345
|
+
lang: resolveRequestLang(requestLangInputFrom(req.headers, readQuery(req))),
|
|
351
346
|
deviceScopeLookup: makeDeviceScopeLookup(addonRegistry),
|
|
352
347
|
deviceFleet: () => addonRegistry.getPersistedDeviceList(),
|
|
353
348
|
};
|
|
@@ -357,7 +352,7 @@ async function createTrpcContext(req, authService, addonRegistry, shareTokens =
|
|
|
357
352
|
* Token is sent via tRPC connectionParams (a JSON message sent right after
|
|
358
353
|
* the WS handshake), which is more reliable than query params through proxies.
|
|
359
354
|
*/
|
|
360
|
-
async function createWsTrpcContext(opts, authService, addonRegistry, shareTokens = null, logger = null) {
|
|
355
|
+
export async function createWsTrpcContext(opts, authService, addonRegistry, shareTokens = null, logger = null) {
|
|
361
356
|
// 1. connectionParams.token (sent by BackendClient's createWSClient)
|
|
362
357
|
const paramToken = opts.info.connectionParams?.['token'];
|
|
363
358
|
const token = (typeof paramToken === 'string' ? paramToken : null) ?? extractTokenFromRequest(opts.req);
|
|
@@ -366,7 +361,7 @@ async function createWsTrpcContext(opts, authService, addonRegistry, shareTokens
|
|
|
366
361
|
return {
|
|
367
362
|
user,
|
|
368
363
|
req: opts.req,
|
|
369
|
-
lang:
|
|
364
|
+
lang: resolveRequestLang(requestLangInputFrom(opts.req.headers, readQuery(opts.req), opts.info.connectionParams?.['lang'])),
|
|
370
365
|
...(user === null && token !== null && token !== '' ? { credentialRejected: true } : {}),
|
|
371
366
|
...(user !== null && sessionId !== undefined
|
|
372
367
|
? {
|
|
@@ -1,25 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const principal_visibility_js_1 = require("./principal-visibility.js");
|
|
16
|
-
const localized_schema_paths_js_1 = require("./localized-schema-paths.js");
|
|
17
|
-
const scope_access_js_1 = require("./scope-access.js");
|
|
18
|
-
const share_view_access_js_1 = require("./share-view-access.js");
|
|
19
|
-
const user_error_js_1 = require("./user-error.js");
|
|
20
|
-
const t = server_1.initTRPC.context().create({
|
|
21
|
-
transformer: superjson_1.default,
|
|
22
|
-
errorFormatter: cap_route_error_formatter_js_1.formatTrpcError,
|
|
1
|
+
import { getCatalogRegistry, METHOD_ACCESS_MAP } from '@camstack/system';
|
|
2
|
+
import { DEFAULT_CATALOG_LANG, localizeConfigTree } from '@camstack/types';
|
|
3
|
+
import { initTRPC, TRPCError } from '@trpc/server';
|
|
4
|
+
import superjson from 'superjson';
|
|
5
|
+
import { formatTrpcError } from './cap-route-error-formatter.js';
|
|
6
|
+
import { NON_ADMIN_CONFIG_REDACTED_METHODS } from './device-config-secret-redaction.js';
|
|
7
|
+
import { projectListAllForPrincipal } from './principal-visibility.js';
|
|
8
|
+
import { LOCALIZED_SCHEMA_PATHS } from './localized-schema-paths.js';
|
|
9
|
+
import { checkScopeAccess, DEVICE_ENUMERATION_METHODS } from './scope-access.js';
|
|
10
|
+
import { checkShareViewAccess, projectListAllForShareScope, projectShareScopeRows, SHARE_SCOPE_PROJECTED_METHODS, } from './share-view-access.js';
|
|
11
|
+
import { trpcUserError } from './user-error.js';
|
|
12
|
+
const t = initTRPC.context().create({
|
|
13
|
+
transformer: superjson,
|
|
14
|
+
errorFormatter: formatTrpcError,
|
|
23
15
|
});
|
|
24
16
|
// ---------------------------------------------------------------------------
|
|
25
17
|
// Async-generator subscription helpers (tRPC v11 — replaces deprecated observable)
|
|
@@ -30,7 +22,7 @@ const t = server_1.initTRPC.context().create({
|
|
|
30
22
|
*
|
|
31
23
|
* @param subscribe — called once; receives a `push` callback and must return an unsubscribe fn.
|
|
32
24
|
*/
|
|
33
|
-
async function* iterableSubscription(subscribe) {
|
|
25
|
+
export async function* iterableSubscription(subscribe) {
|
|
34
26
|
const queue = [];
|
|
35
27
|
let resolve = null;
|
|
36
28
|
const unsub = subscribe((value) => {
|
|
@@ -55,7 +47,7 @@ async function* iterableSubscription(subscribe) {
|
|
|
55
47
|
* Create an interval-based async generator that yields a value on each tick.
|
|
56
48
|
* Useful for polling subscriptions.
|
|
57
49
|
*/
|
|
58
|
-
async function* iterableInterval(intervalMs, getValue) {
|
|
50
|
+
export async function* iterableInterval(intervalMs, getValue) {
|
|
59
51
|
try {
|
|
60
52
|
while (true) {
|
|
61
53
|
yield getValue();
|
|
@@ -74,22 +66,22 @@ async function* iterableInterval(intervalMs, getValue) {
|
|
|
74
66
|
*/
|
|
75
67
|
const localizeSchemaOutput = t.middleware(async ({ ctx, path, next }) => {
|
|
76
68
|
const out = await next();
|
|
77
|
-
const lang = ctx.lang ??
|
|
78
|
-
if (!out.ok || lang ===
|
|
69
|
+
const lang = ctx.lang ?? DEFAULT_CATALOG_LANG;
|
|
70
|
+
if (!out.ok || lang === DEFAULT_CATALOG_LANG || !LOCALIZED_SCHEMA_PATHS.has(path))
|
|
79
71
|
return out;
|
|
80
|
-
return { ...out, data:
|
|
72
|
+
return { ...out, data: localizeConfigTree(out.data, getCatalogRegistry().lookupFor(lang)) };
|
|
81
73
|
});
|
|
82
74
|
/** Every authenticated procedure starts from here, so the localizing middleware is the outermost. */
|
|
83
75
|
const localized = t.procedure.use(localizeSchemaOutput);
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
export const trpcRouter = t.router;
|
|
77
|
+
export const publicProcedure = t.procedure;
|
|
86
78
|
/**
|
|
87
79
|
* Server-side caller factory — turns the hub appRouter into a directly
|
|
88
80
|
* invokable record under a supplied `TrpcContext`. The core-cap bridge
|
|
89
81
|
* (`core-cap-bridge.ts`) uses it to expose core routers over the
|
|
90
82
|
* Moleculer mesh without an HTTP round-trip.
|
|
91
83
|
*/
|
|
92
|
-
|
|
84
|
+
export const createCallerFactory = t.createCallerFactory;
|
|
93
85
|
/**
|
|
94
86
|
* Caps-only authenticated procedure (v2).
|
|
95
87
|
*
|
|
@@ -110,15 +102,15 @@ exports.createCallerFactory = t.createCallerFactory;
|
|
|
110
102
|
* Single source of authority for caps: `isAdmin`. The legacy role enum
|
|
111
103
|
* collapsed onto this boolean in v2.
|
|
112
104
|
*/
|
|
113
|
-
|
|
105
|
+
export const protectedProcedure = localized.use(async ({ ctx, next, path, getRawInput }) => {
|
|
114
106
|
if (!ctx.user) {
|
|
115
|
-
throw new
|
|
107
|
+
throw new TRPCError({ code: 'UNAUTHORIZED' });
|
|
116
108
|
}
|
|
117
109
|
// A WebSocket resolves its principal once, at connect. Its login session is
|
|
118
110
|
// re-checked on every call, so a logout or revocation ends a socket that is
|
|
119
111
|
// already open — not only the next one.
|
|
120
112
|
if (ctx.sessionLive !== undefined && !ctx.sessionLive()) {
|
|
121
|
-
throw
|
|
113
|
+
throw trpcUserError('UNAUTHORIZED', 'auth.session-ended', undefined, 'Session ended — sign in again');
|
|
122
114
|
}
|
|
123
115
|
// Share-view principals (`csv_*` tokens) NEVER reach the admin bypass,
|
|
124
116
|
// the hand-written-route pass-through, or the scope matcher below —
|
|
@@ -126,9 +118,9 @@ exports.protectedProcedure = localized.use(async ({ ctx, next, path, getRawInput
|
|
|
126
118
|
// (`share-view-access.ts`): enumerated methods only, in-scope devices only.
|
|
127
119
|
if (ctx.user.shareView) {
|
|
128
120
|
const rawInput = await getRawInput();
|
|
129
|
-
const result =
|
|
121
|
+
const result = checkShareViewAccess(ctx.user.shareView.scope, path, rawInput);
|
|
130
122
|
if (!result.ok) {
|
|
131
|
-
throw new
|
|
123
|
+
throw new TRPCError({ code: 'FORBIDDEN', message: result.reason });
|
|
132
124
|
}
|
|
133
125
|
// `deviceManager.listAll` is allowlisted for the embed's tile names,
|
|
134
126
|
// but its raw rows describe EVERY device (config incl. credentials).
|
|
@@ -136,7 +128,7 @@ exports.protectedProcedure = localized.use(async ({ ctx, next, path, getRawInput
|
|
|
136
128
|
if (path === 'deviceManager.listAll') {
|
|
137
129
|
const out = await next({ ctx: { ...ctx, user: ctx.user } });
|
|
138
130
|
if (out.ok) {
|
|
139
|
-
return { ...out, data:
|
|
131
|
+
return { ...out, data: projectListAllForShareScope(out.data, ctx.user.shareView.scope) };
|
|
140
132
|
}
|
|
141
133
|
return out;
|
|
142
134
|
}
|
|
@@ -147,10 +139,10 @@ exports.protectedProcedure = localized.use(async ({ ctx, next, path, getRawInput
|
|
|
147
139
|
// those calls through — this is where the answer is cut. Without it the
|
|
148
140
|
// allowlist would be a doorman who checks the ticket and then hands over
|
|
149
141
|
// the whole building.
|
|
150
|
-
if (
|
|
142
|
+
if (SHARE_SCOPE_PROJECTED_METHODS.has(path)) {
|
|
151
143
|
const out = await next({ ctx: { ...ctx, user: ctx.user } });
|
|
152
144
|
if (out.ok) {
|
|
153
|
-
return { ...out, data:
|
|
145
|
+
return { ...out, data: projectShareScopeRows(out.data, ctx.user.shareView.scope) };
|
|
154
146
|
}
|
|
155
147
|
return out;
|
|
156
148
|
}
|
|
@@ -168,16 +160,16 @@ exports.protectedProcedure = localized.use(async ({ ctx, next, path, getRawInput
|
|
|
168
160
|
// already passed; defer further gating to any explicit
|
|
169
161
|
// `adminProcedure` chained on top of this one. A cap route is
|
|
170
162
|
// scope-matched first.
|
|
171
|
-
if (path in
|
|
163
|
+
if (path in METHOD_ACCESS_MAP) {
|
|
172
164
|
// Device-scope caps may be gated by a `device:N` scope. Resolve the
|
|
173
165
|
// raw input once so the matcher can read `input.deviceId` without
|
|
174
166
|
// re-doing the Zod parse (tRPC caches the parsed input downstream).
|
|
175
167
|
// The `getDeviceAncestors` hook lets the matcher walk parent → child
|
|
176
168
|
// accessory inheritance (grant on Reolink also covers its siren / PIR).
|
|
177
169
|
const rawInput = await getRawInput();
|
|
178
|
-
const result =
|
|
170
|
+
const result = checkScopeAccess(ctx.user.scopes ?? [], path, rawInput, ctx.deviceScopeLookup);
|
|
179
171
|
if (!result.ok) {
|
|
180
|
-
throw new
|
|
172
|
+
throw new TRPCError({ code: 'FORBIDDEN', message: result.reason });
|
|
181
173
|
}
|
|
182
174
|
}
|
|
183
175
|
// A non-admin who is allowed to READ a device is not thereby allowed to
|
|
@@ -187,7 +179,7 @@ exports.protectedProcedure = localized.use(async ({ ctx, next, path, getRawInput
|
|
|
187
179
|
// every camera in the deployment. The value is withheld HERE, at the
|
|
188
180
|
// transport boundary, so in-process callers (`ctx.api`, the pipeline
|
|
189
181
|
// orchestrator, the drivers that must actually connect) are unaffected.
|
|
190
|
-
const redactConfigSecrets =
|
|
182
|
+
const redactConfigSecrets = NON_ADMIN_CONFIG_REDACTED_METHODS.get(path);
|
|
191
183
|
const out = await next({ ctx: { ...ctx, user: ctx.user } });
|
|
192
184
|
if (!out.ok)
|
|
193
185
|
return out;
|
|
@@ -195,8 +187,8 @@ exports.protectedProcedure = localized.use(async ({ ctx, next, path, getRawInput
|
|
|
195
187
|
// matcher lets a `device`-selector grant reach `deviceManager.listAll`
|
|
196
188
|
// precisely because the answer is cut here; without this the grant would
|
|
197
189
|
// hand back the whole fleet — names, locations, online state.
|
|
198
|
-
if (
|
|
199
|
-
const projected =
|
|
190
|
+
if (DEVICE_ENUMERATION_METHODS.has(path)) {
|
|
191
|
+
const projected = projectListAllForPrincipal(out.data, ctx.user.isAdmin, ctx.user.scopes ?? [], ctx.deviceFleet?.() ?? []);
|
|
200
192
|
return {
|
|
201
193
|
...out,
|
|
202
194
|
data: redactConfigSecrets ? redactConfigSecrets(projected) : projected,
|
|
@@ -217,9 +209,9 @@ exports.protectedProcedure = localized.use(async ({ ctx, next, path, getRawInput
|
|
|
217
209
|
* `protectedProcedure`. Useful on hand-written routes whose admin-only
|
|
218
210
|
* nature should be obvious to a code reader.
|
|
219
211
|
*/
|
|
220
|
-
|
|
212
|
+
export const adminProcedure = protectedProcedure.use(({ ctx, next }) => {
|
|
221
213
|
if (!ctx.user.isAdmin) {
|
|
222
|
-
throw
|
|
214
|
+
throw trpcUserError('FORBIDDEN', 'auth.admin-required', undefined, 'Admin required');
|
|
223
215
|
}
|
|
224
216
|
return next({ ctx });
|
|
225
217
|
});
|
|
@@ -1,66 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.enrichInputWithUserAgent = enrichInputWithUserAgent;
|
|
37
|
-
exports.enrichInputWithRelayClass = enrichInputWithRelayClass;
|
|
38
|
-
exports.stripTalkbackFromRequest = stripTalkbackFromRequest;
|
|
39
|
-
exports.enrichHintsWithClientClass = enrichHintsWithClientClass;
|
|
40
|
-
exports.wrapWebrtcSessionProviderWithRelay = wrapWebrtcSessionProviderWithRelay;
|
|
41
|
-
exports.buildAppRouter = buildAppRouter;
|
|
42
|
-
const path = __importStar(require("node:path"));
|
|
43
|
-
const addon_settings_router_js_1 = require("../core/addon-settings.router.js");
|
|
44
|
-
const session_connections_js_1 = require("../../auth/session-connections.js");
|
|
45
|
-
const agent_pairing_router_js_1 = require("../core/agent-pairing.router.js");
|
|
46
|
-
const certificates_router_js_1 = require("../core/certificates.router.js");
|
|
47
|
-
const node_certificates_client_js_1 = require("../../core/agent/node-certificates-client.js");
|
|
48
|
-
const auth_router_js_1 = require("../core/auth.router.js");
|
|
49
|
-
const cap_providers_js_1 = require("../core/cap-providers.js");
|
|
50
|
-
const capabilities_router_js_1 = require("../core/capabilities.router.js");
|
|
51
|
-
const cluster_nodes_router_js_1 = require("../core/cluster-nodes.router.js");
|
|
52
|
-
const event_bus_proxy_router_js_1 = require("../core/event-bus-proxy.router.js");
|
|
53
|
-
const hwaccel_router_js_1 = require("../core/hwaccel.router.js");
|
|
54
|
-
const live_events_router_js_1 = require("../core/live-events.router.js");
|
|
55
|
-
const logs_router_js_1 = require("../core/logs.router.js");
|
|
56
|
-
const notifications_router_js_1 = require("../core/notifications.router.js");
|
|
57
|
-
const repl_router_js_1 = require("../core/repl.router.js");
|
|
58
|
-
const server_management_provider_js_1 = require("../core/server-management.provider.js");
|
|
59
|
-
const stream_probe_router_js_1 = require("../core/stream-probe.router.js");
|
|
60
|
-
const system_events_router_js_1 = require("../core/system-events.router.js");
|
|
61
|
-
const cap_router_runtime_js_1 = require("./cap-router-runtime.js");
|
|
62
|
-
const client_ip_js_1 = require("./client-ip.js");
|
|
63
|
-
const trpc_middleware_1 = require("./trpc.middleware");
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import { createAddonSettingsRouter } from '../core/addon-settings.router.js';
|
|
3
|
+
import { getSessionConnections } from '../../auth/session-connections.js';
|
|
4
|
+
import { createAgentPairingRouter } from '../core/agent-pairing.router.js';
|
|
5
|
+
import { createCertificatesRouter } from '../core/certificates.router.js';
|
|
6
|
+
import { createNodeCertificatesClient } from '../../core/agent/node-certificates-client.js';
|
|
7
|
+
import { createAuthRouter } from '../core/auth.router.js';
|
|
8
|
+
import { buildAddonsProvider, buildIntegrationsProvider, buildNetworkQualityProvider, buildNodesProvider, buildSystemProvider, buildToastProvider, createNodeRootPackageLookup, } from '../core/cap-providers.js';
|
|
9
|
+
import { createCapabilitiesRouter } from '../core/capabilities.router.js';
|
|
10
|
+
import { createClusterNodesRouter } from '../core/cluster-nodes.router.js';
|
|
11
|
+
import { createEventBusProxyRouter } from '../core/event-bus-proxy.router.js';
|
|
12
|
+
import { createHwAccelRouter } from '../core/hwaccel.router.js';
|
|
13
|
+
import { createLiveEventsRouter } from '../core/live-events.router.js';
|
|
14
|
+
import { createLogsRouter } from '../core/logs.router.js';
|
|
15
|
+
import { createNotificationsRouter } from '../core/notifications.router.js';
|
|
16
|
+
import { createReplRouter } from '../core/repl.router.js';
|
|
17
|
+
import { buildServerManagementProvider } from '../core/server-management.provider.js';
|
|
18
|
+
import { createStreamProbeRouter } from '../core/stream-probe.router.js';
|
|
19
|
+
import { createSystemEventsRouter } from '../core/system-events.router.js';
|
|
20
|
+
import { buildRuntimeCapRouters } from './cap-router-runtime.js';
|
|
21
|
+
import { classifyClientRequest, deriveRelayOnly, extractUserAgent, } from './client-ip.js';
|
|
22
|
+
import { trpcRouter } from './trpc.middleware';
|
|
64
23
|
/**
|
|
65
24
|
* Merge the server-read User-Agent into a signaling call's
|
|
66
25
|
* `consumerAttribution`, building a NEW input object (immutable — never
|
|
@@ -69,7 +28,7 @@ const trpc_middleware_1 = require("./trpc.middleware");
|
|
|
69
28
|
* unchanged. Any client-supplied `userAgent` is OVERWRITTEN — the hub
|
|
70
29
|
* trusts only the request context, never the client.
|
|
71
30
|
*/
|
|
72
|
-
function enrichInputWithUserAgent(input, userAgent) {
|
|
31
|
+
export function enrichInputWithUserAgent(input, userAgent) {
|
|
73
32
|
if (userAgent === null)
|
|
74
33
|
return input;
|
|
75
34
|
const base = input.consumerAttribution ?? { kind: 'webrtc-browser' };
|
|
@@ -128,10 +87,10 @@ const FORCE_RELAY_REMOTE = process.env.CAMSTACK_FORCE_RELAY_REMOTE === '1' ||
|
|
|
128
87
|
*
|
|
129
88
|
* Immutable — builds a NEW input object, never mutates the caller's.
|
|
130
89
|
*/
|
|
131
|
-
function enrichInputWithRelayClass(input, clientClass) {
|
|
90
|
+
export function enrichInputWithRelayClass(input, clientClass) {
|
|
132
91
|
if (clientClass === null)
|
|
133
92
|
return input;
|
|
134
|
-
const relayOnly = FORCE_RELAY_REMOTE ?
|
|
93
|
+
const relayOnly = FORCE_RELAY_REMOTE ? deriveRelayOnly(clientClass) : false;
|
|
135
94
|
return { ...input, relayOnly };
|
|
136
95
|
}
|
|
137
96
|
/**
|
|
@@ -147,7 +106,7 @@ function enrichInputWithRelayClass(input, clientClass) {
|
|
|
147
106
|
*
|
|
148
107
|
* Immutable — builds a NEW input object, never mutates the caller's.
|
|
149
108
|
*/
|
|
150
|
-
function stripTalkbackFromRequest(input, clientClass) {
|
|
109
|
+
export function stripTalkbackFromRequest(input, clientClass) {
|
|
151
110
|
if (clientClass === null || input.talkback === undefined)
|
|
152
111
|
return input;
|
|
153
112
|
const { talkback: _dropped, ...rest } = input;
|
|
@@ -161,7 +120,7 @@ function stripTalkbackFromRequest(input, clientClass) {
|
|
|
161
120
|
* stays as the documented seam so a future probe can still thread class
|
|
162
121
|
* without a cap change; today it is a no-op.
|
|
163
122
|
*/
|
|
164
|
-
function enrichHintsWithClientClass(input, _clientClass) {
|
|
123
|
+
export function enrichHintsWithClientClass(input, _clientClass) {
|
|
165
124
|
return input;
|
|
166
125
|
}
|
|
167
126
|
/**
|
|
@@ -197,16 +156,16 @@ function enrichHintsWithClientClass(input, _clientClass) {
|
|
|
197
156
|
* All OTHER methods delegate straight through — auth, the remote-proxy
|
|
198
157
|
* factory and every signaling behaviour are untouched.
|
|
199
158
|
*/
|
|
200
|
-
function wrapWebrtcSessionProviderWithRelay(provider, ctx) {
|
|
201
|
-
const userAgent =
|
|
202
|
-
const clientClass =
|
|
159
|
+
export function wrapWebrtcSessionProviderWithRelay(provider, ctx) {
|
|
160
|
+
const userAgent = extractUserAgent(ctx.req);
|
|
161
|
+
const clientClass = classifyClientRequest(ctx.req);
|
|
203
162
|
// The login session this request runs under: media opened here dies with it
|
|
204
163
|
// (`session-connections.ts`). A principal with no `sid` has nothing to tie to.
|
|
205
164
|
const authSessionId = ctx.user?.sessionId;
|
|
206
165
|
const hold = (deviceId, mediaSessionId) => {
|
|
207
166
|
if (authSessionId === undefined)
|
|
208
167
|
return;
|
|
209
|
-
|
|
168
|
+
getSessionConnections().trackMedia(authSessionId, {
|
|
210
169
|
deviceId,
|
|
211
170
|
mediaSessionId,
|
|
212
171
|
close: () => provider.closeSession({ deviceId, sessionId: mediaSessionId }),
|
|
@@ -226,7 +185,7 @@ function wrapWebrtcSessionProviderWithRelay(provider, ctx) {
|
|
|
226
185
|
},
|
|
227
186
|
closeSession: (input) => {
|
|
228
187
|
if (authSessionId !== undefined) {
|
|
229
|
-
|
|
188
|
+
getSessionConnections().forgetMedia(authSessionId, input.sessionId);
|
|
230
189
|
}
|
|
231
190
|
return provider.closeSession(input);
|
|
232
191
|
},
|
|
@@ -247,14 +206,14 @@ function wrapWebrtcSessionProviderWithRelay(provider, ctx) {
|
|
|
247
206
|
function buildServerProviders(services) {
|
|
248
207
|
const wrap = (fn) => (ctx) => fn(ctx);
|
|
249
208
|
return {
|
|
250
|
-
'network-quality': wrap(() =>
|
|
251
|
-
system: wrap(() =>
|
|
252
|
-
toast: wrap((ctx) =>
|
|
253
|
-
integrations: wrap(() =>
|
|
254
|
-
nodes: wrap(() =>
|
|
209
|
+
'network-quality': wrap(() => buildNetworkQualityProvider(services.networkQualityService)),
|
|
210
|
+
system: wrap(() => buildSystemProvider(services.featureService, services.capabilityRegistry, services.loggingService.createLogger('site-location'))),
|
|
211
|
+
toast: wrap((ctx) => buildToastProvider(services.toastService, ctx)),
|
|
212
|
+
integrations: wrap(() => buildIntegrationsProvider(services.addonRegistry, services.eventBus, services.loggingService, services.capabilityRegistry)),
|
|
213
|
+
nodes: wrap(() => buildNodesProvider(services.agentRegistry, services.moleculer, services.addonRegistry, createNodeRootPackageLookup(services.moleculer, services.serverUpdateService), services.loggingService.createLogger('nodes'))),
|
|
255
214
|
// server-management — runtime-updatable root package (phase 1: hub only).
|
|
256
|
-
'server-management': wrap(() =>
|
|
257
|
-
addons: wrap((ctx) =>
|
|
215
|
+
'server-management': wrap(() => buildServerManagementProvider(services.serverUpdateService)),
|
|
216
|
+
addons: wrap((ctx) => buildAddonsProvider(services.addonRegistry, services.addonPackageService, services.loggingService, services.moleculer, services.configService, ctx, services.agentRegistry)),
|
|
258
217
|
// webrtc-session — the resolved broker singleton, wrapped per request to
|
|
259
218
|
// inject the server-read User-Agent into signaling attribution (the broker
|
|
260
219
|
// is a forked addon that can't see the HTTP request). Cross-node (agent-
|
|
@@ -296,7 +255,7 @@ function buildCapabilityRouters(services) {
|
|
|
296
255
|
// (`import type`) — its value is never called; the codegen
|
|
297
256
|
// `generated-cap-mounts.ts` / `generated-cap-routers.ts` remain the TYPE
|
|
298
257
|
// source of record.
|
|
299
|
-
const dynamicCaps =
|
|
258
|
+
const dynamicCaps = buildRuntimeCapRouters({
|
|
300
259
|
capabilityRegistry: services.capabilityRegistry,
|
|
301
260
|
moleculer: services.moleculer,
|
|
302
261
|
serverProviders: buildServerProviders(services),
|
|
@@ -311,44 +270,44 @@ function buildCapabilityRouters(services) {
|
|
|
311
270
|
// by `buildServerProviders`. ──────
|
|
312
271
|
...dynamicCaps,
|
|
313
272
|
// ── Non-cap (core) routers — hand-written, single-impl ──────────
|
|
314
|
-
notifications:
|
|
273
|
+
notifications: createNotificationsRouter(services.notificationService),
|
|
315
274
|
// Raw DB proxy for forked workers to read/write addon store.
|
|
316
275
|
// Workers use ctx.api.addonSettingsRaw.getGlobal.query({...}).
|
|
317
276
|
// NOT the three-level settings gateway — that's the
|
|
318
277
|
// `addonSettings` cap router (mounted dynamically above).
|
|
319
|
-
addonSettingsRaw:
|
|
320
|
-
eventBusProxy:
|
|
321
|
-
repl:
|
|
322
|
-
systemEvents:
|
|
323
|
-
capabilities:
|
|
324
|
-
logs:
|
|
325
|
-
live:
|
|
278
|
+
addonSettingsRaw: createAddonSettingsRouter(services.configService),
|
|
279
|
+
eventBusProxy: createEventBusProxyRouter(services.eventBus),
|
|
280
|
+
repl: createReplRouter(services.replEngine),
|
|
281
|
+
systemEvents: createSystemEventsRouter(services.eventBus),
|
|
282
|
+
capabilities: createCapabilitiesRouter(services.capabilityRegistry, services.configService),
|
|
283
|
+
logs: createLogsRouter(services.loggingService),
|
|
284
|
+
live: createLiveEventsRouter(services.eventBus, services.addonRegistry),
|
|
326
285
|
// stream-probe — fixed core API (ffprobe wrapper), not a cap.
|
|
327
|
-
streamProbe:
|
|
286
|
+
streamProbe: createStreamProbeRouter(services.streamProbe),
|
|
328
287
|
// hwaccel — fixed core API, repointed onto the `platform-probe` cap
|
|
329
288
|
// (the sole cross-node-pinnable hwaccel surface). UI pipeline /
|
|
330
289
|
// NodeDetail pages query per-node to show which hardware backend each
|
|
331
290
|
// agent will use.
|
|
332
|
-
hwaccel:
|
|
291
|
+
hwaccel: createHwAccelRouter(services.capabilityRegistry, services.moleculer),
|
|
333
292
|
// clusterNodes — fixed core API. Write-side purge for the durable
|
|
334
293
|
// offline-node history (Track A "Forget node"); read side is push-only.
|
|
335
|
-
clusterNodes:
|
|
294
|
+
clusterNodes: createClusterNodesRouter(services.agentRegistry),
|
|
336
295
|
// certificates - Identity -> Certificates inventory (HTTPS per node, mesh CA). D855.
|
|
337
|
-
certificates:
|
|
296
|
+
certificates: createCertificatesRouter({
|
|
338
297
|
registry: services.capabilityRegistry,
|
|
339
298
|
agentRegistry: services.agentRegistry,
|
|
340
|
-
nodeClient: (nodeId) =>
|
|
299
|
+
nodeClient: (nodeId) => createNodeCertificatesClient(services.moleculer, nodeId),
|
|
341
300
|
nodeAddonIds: (nodeId) => services.moleculer.getNodeAddonIds(nodeId),
|
|
342
301
|
hubDataDir: path.resolve(services.configService.get('server.dataPath') ?? 'camstack-data'),
|
|
343
302
|
log: services.loggingService.createLogger('certificates'),
|
|
344
303
|
}),
|
|
345
304
|
// agentPairing - hub-initiated pairing of agents, unpairing (D857).
|
|
346
|
-
agentPairing:
|
|
305
|
+
agentPairing: createAgentPairingRouter({
|
|
347
306
|
registry: services.capabilityRegistry,
|
|
348
|
-
nodeClient: (nodeId) =>
|
|
307
|
+
nodeClient: (nodeId) => createNodeCertificatesClient(services.moleculer, nodeId),
|
|
349
308
|
log: services.loggingService.createLogger('agent-pairing'),
|
|
350
309
|
}),
|
|
351
|
-
auth:
|
|
310
|
+
auth: createAuthRouter(services.authService, services.capabilityRegistry, services.moleculer, services.shareTokenService, services.handoffCodeService, services.externalLinkIntents, services.nativeLink ?? null, {
|
|
352
311
|
...(services.authNetworkPolicy !== undefined
|
|
353
312
|
? { network: services.authNetworkPolicy }
|
|
354
313
|
: {}),
|
|
@@ -363,8 +322,8 @@ function buildCapabilityRouters(services) {
|
|
|
363
322
|
// - restreamer / streaming-engine / webrtc
|
|
364
323
|
};
|
|
365
324
|
}
|
|
366
|
-
function buildAppRouter(services) {
|
|
367
|
-
return
|
|
325
|
+
export function buildAppRouter(services) {
|
|
326
|
+
return trpcRouter({
|
|
368
327
|
...buildCapabilityRouters(services),
|
|
369
328
|
});
|
|
370
329
|
}
|
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.trpcUserError = trpcUserError;
|
|
4
|
-
const server_1 = require("@trpc/server");
|
|
5
|
-
const types_1 = require("@camstack/types");
|
|
1
|
+
import { TRPCError } from '@trpc/server';
|
|
2
|
+
import { userError } from '@camstack/types';
|
|
6
3
|
/**
|
|
7
4
|
* A `TRPCError` that carries a stable i18n code (D863). `message` stays the
|
|
8
5
|
* English text; the error formatter swaps it for the `server` catalog text in
|
|
9
6
|
* the request language and keeps `{ code, params }` in `data.i18n`.
|
|
10
7
|
*/
|
|
11
|
-
function trpcUserError(trpcCode, i18nCode, params, englishFallback) {
|
|
12
|
-
return new
|
|
8
|
+
export function trpcUserError(trpcCode, i18nCode, params, englishFallback) {
|
|
9
|
+
return new TRPCError({
|
|
13
10
|
code: trpcCode,
|
|
14
11
|
message: englishFallback,
|
|
15
|
-
cause:
|
|
12
|
+
cause: userError(i18nCode, params, englishFallback),
|
|
16
13
|
});
|
|
17
14
|
}
|