@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,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Small helpers for wiring capability routers to the `CapabilityRegistry`
|
|
4
3
|
* in `trpc.router.ts`. These functions don't generate code — they just
|
|
@@ -16,20 +15,16 @@
|
|
|
16
15
|
* provider responsible for a given `streamId`) are NOT covered here —
|
|
17
16
|
* they have app-specific routing logic that belongs in the mount.
|
|
18
17
|
*/
|
|
19
|
-
|
|
20
|
-
exports.requireSingleton = requireSingleton;
|
|
21
|
-
exports.requireDeviceScoped = requireDeviceScoped;
|
|
22
|
-
exports.concatCollection = concatCollection;
|
|
23
|
-
const server_1 = require("@trpc/server");
|
|
18
|
+
import { TRPCError } from '@trpc/server';
|
|
24
19
|
/**
|
|
25
20
|
* Fetch the currently active singleton provider for a capability.
|
|
26
21
|
* Returns null if no provider is registered; the downstream codegen'd
|
|
27
22
|
* router surfaces this as `PRECONDITION_FAILED` to the caller.
|
|
28
23
|
*/
|
|
29
|
-
function requireSingleton(registry, capName) {
|
|
24
|
+
export function requireSingleton(registry, capName) {
|
|
30
25
|
return registry?.getSingleton(capName) ?? null;
|
|
31
26
|
}
|
|
32
|
-
function requireDeviceScoped(registry, capName) {
|
|
27
|
+
export function requireDeviceScoped(registry, capName) {
|
|
33
28
|
if (!registry)
|
|
34
29
|
return null;
|
|
35
30
|
// The Proxy is the singleton stand-in. Each property access returns
|
|
@@ -43,7 +38,7 @@ function requireDeviceScoped(registry, capName) {
|
|
|
43
38
|
return async (input) => {
|
|
44
39
|
const deviceId = input?.deviceId;
|
|
45
40
|
if (typeof deviceId !== 'number') {
|
|
46
|
-
throw new
|
|
41
|
+
throw new TRPCError({
|
|
47
42
|
code: 'BAD_REQUEST',
|
|
48
43
|
message: `${String(capName)}.${prop}: input must carry numeric "deviceId"`,
|
|
49
44
|
});
|
|
@@ -66,14 +61,14 @@ function requireDeviceScoped(registry, capName) {
|
|
|
66
61
|
// cap with no provider at all still answered. Wiring was deleted on
|
|
67
62
|
// 2026-08-08 — a composed device's caps are native to it, so there
|
|
68
63
|
// is nothing to conjure and the honest answer is the error.
|
|
69
|
-
throw new
|
|
64
|
+
throw new TRPCError({
|
|
70
65
|
code: 'PRECONDITION_FAILED',
|
|
71
66
|
message: `Capability "${String(capName)}" not registered for device ${deviceId}`,
|
|
72
67
|
});
|
|
73
68
|
}
|
|
74
69
|
const fn = provider[prop];
|
|
75
70
|
if (typeof fn !== 'function') {
|
|
76
|
-
throw new
|
|
71
|
+
throw new TRPCError({
|
|
77
72
|
code: 'NOT_IMPLEMENTED',
|
|
78
73
|
message: `Capability "${String(capName)}" provider for device ${deviceId} does not implement "${prop}"`,
|
|
79
74
|
});
|
|
@@ -93,7 +88,7 @@ function requireDeviceScoped(registry, capName) {
|
|
|
93
88
|
* and concatenates their array results. Useful for contribution-style
|
|
94
89
|
* caps where each provider adds to a shared pool.
|
|
95
90
|
*/
|
|
96
|
-
function concatCollection(providers, method) {
|
|
91
|
+
export function concatCollection(providers, method) {
|
|
97
92
|
const wrapper = async (...args) => {
|
|
98
93
|
const results = await Promise.all(providers.map(async (p) => {
|
|
99
94
|
const member = Reflect.get(p, method);
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatTrpcError = formatTrpcError;
|
|
4
1
|
/**
|
|
5
2
|
* tRPC error formatter that serializes CapRouteError diagnostic fields
|
|
6
3
|
* across the server→client boundary.
|
|
@@ -16,8 +13,8 @@ exports.formatTrpcError = formatTrpcError;
|
|
|
16
13
|
*
|
|
17
14
|
* The formatter is EXPORTED for unit testing (no side-effects, pure function).
|
|
18
15
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
import { CapRouteError, getCatalogRegistry, SERVER_NAMESPACE } from '@camstack/system';
|
|
17
|
+
import { DEFAULT_CATALOG_LANG, interpolate, readErrorI18n, } from '@camstack/types';
|
|
21
18
|
// ---------------------------------------------------------------------------
|
|
22
19
|
// Type guards
|
|
23
20
|
// ---------------------------------------------------------------------------
|
|
@@ -57,7 +54,7 @@ function extractCapRouteError(err) {
|
|
|
57
54
|
for (let depth = 0; depth < 8; depth++) {
|
|
58
55
|
if (current === null || current === undefined)
|
|
59
56
|
return null;
|
|
60
|
-
if (current instanceof
|
|
57
|
+
if (current instanceof CapRouteError) {
|
|
61
58
|
return current;
|
|
62
59
|
}
|
|
63
60
|
// Duck-type fallback: err.name + err.reason field present
|
|
@@ -84,7 +81,7 @@ function extractCapRouteError(err) {
|
|
|
84
81
|
const rawCapName = Reflect.get(current, 'capName');
|
|
85
82
|
const capName = typeof rawCapName === 'string' ? rawCapName : '(unknown)';
|
|
86
83
|
// Build a minimal object with the same shape — enough for the formatter.
|
|
87
|
-
const synthetic = Object.assign(new
|
|
84
|
+
const synthetic = Object.assign(new CapRouteError(capName, undefined, {
|
|
88
85
|
reason,
|
|
89
86
|
rejected,
|
|
90
87
|
...(typeof nodeId === 'string' ? { nodeId } : {}),
|
|
@@ -110,7 +107,7 @@ function extractCapRouteError(err) {
|
|
|
110
107
|
* when the thrown error (or any error in its `.cause` chain) is a CapRouteError.
|
|
111
108
|
* Returns the shape unchanged for all other errors.
|
|
112
109
|
*/
|
|
113
|
-
function formatTrpcError(opts) {
|
|
110
|
+
export function formatTrpcError(opts) {
|
|
114
111
|
return withErrorI18n(opts, withCapRouteData(opts));
|
|
115
112
|
}
|
|
116
113
|
/**
|
|
@@ -120,16 +117,16 @@ function formatTrpcError(opts) {
|
|
|
120
117
|
* unknown code and English all pass through with the original message.
|
|
121
118
|
*/
|
|
122
119
|
function withErrorI18n(opts, shape) {
|
|
123
|
-
const coded =
|
|
120
|
+
const coded = readErrorI18n(opts.error);
|
|
124
121
|
if (coded === null)
|
|
125
122
|
return shape;
|
|
126
|
-
const lang = opts.ctx?.lang ??
|
|
127
|
-
const text = lang ===
|
|
123
|
+
const lang = opts.ctx?.lang ?? DEFAULT_CATALOG_LANG;
|
|
124
|
+
const text = lang === DEFAULT_CATALOG_LANG
|
|
128
125
|
? undefined
|
|
129
|
-
:
|
|
126
|
+
: getCatalogRegistry().lookup(lang, SERVER_NAMESPACE, coded.code);
|
|
130
127
|
return {
|
|
131
128
|
...shape,
|
|
132
|
-
...(text !== undefined ? { message:
|
|
129
|
+
...(text !== undefined ? { message: interpolate(text, coded.params) } : {}),
|
|
133
130
|
data: { ...shape.data, i18n: coded },
|
|
134
131
|
};
|
|
135
132
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Server-side glue for the runtime cap-router builder (BIG PLAN 2).
|
|
4
3
|
*
|
|
@@ -19,43 +18,33 @@
|
|
|
19
18
|
* supplies `server-provided` provider factories (incl. webrtc-session) via the
|
|
20
19
|
* `serverProviders` map — no hand-written cap-router override remains.
|
|
21
20
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
exports.pinnedCollectionCall = pinnedCollectionCall;
|
|
29
|
-
exports.createCapRouterPrimitives = createCapRouterPrimitives;
|
|
30
|
-
exports.createCapRouterServices = createCapRouterServices;
|
|
31
|
-
exports.buildRuntimeCapRouters = buildRuntimeCapRouters;
|
|
32
|
-
const system_1 = require("@camstack/system");
|
|
33
|
-
const types_1 = require("@camstack/types");
|
|
34
|
-
const server_1 = require("@trpc/server");
|
|
35
|
-
const cap_mount_helpers_js_1 = require("./cap-mount-helpers.js");
|
|
36
|
-
const device_collection_dispatch_js_1 = require("./device-collection-dispatch.js");
|
|
37
|
-
const trpc_middleware_js_1 = require("./trpc.middleware.js");
|
|
21
|
+
import { ALL_CAPABILITY_DEFINITIONS, buildCapRouters, isArrayOutputSchema, } from '@camstack/system';
|
|
22
|
+
import { PROVIDER_PIN_FIELD, resolveCapMount, } from '@camstack/types';
|
|
23
|
+
import { TRPCError } from '@trpc/server';
|
|
24
|
+
import { requireDeviceScoped } from './cap-mount-helpers.js';
|
|
25
|
+
import { requireDeviceCollection } from './device-collection-dispatch.js';
|
|
26
|
+
import { adminProcedure, iterableSubscription, protectedProcedure, publicProcedure, trpcRouter, } from './trpc.middleware.js';
|
|
38
27
|
/**
|
|
39
28
|
* Pre-computed set of capName → array-output method names for collection
|
|
40
29
|
* caps, derived once from the cap defs at module init. Mirrors
|
|
41
30
|
* `generate-cap-mounts.ts` `isArrayOutputSchema` so the runtime collection
|
|
42
31
|
* resolver fans the SAME methods the codegen used to.
|
|
43
32
|
*/
|
|
44
|
-
|
|
33
|
+
export const COLLECTION_ARRAY_METHODS = computeArrayMethods();
|
|
45
34
|
function computeArrayMethods() {
|
|
46
35
|
const out = new Map();
|
|
47
|
-
for (const def of
|
|
36
|
+
for (const def of ALL_CAPABILITY_DEFINITIONS) {
|
|
48
37
|
// The effective MOUNT, never `mode`: a device-scoped wrapper collection
|
|
49
38
|
// (`videoclips`, D554) fans over ONE DEVICE's sources through the
|
|
50
39
|
// per-device dispatcher, and must never be fanned globally here.
|
|
51
|
-
if (
|
|
40
|
+
if (resolveCapMount(def).kind !== 'collection')
|
|
52
41
|
continue;
|
|
53
42
|
const names = [];
|
|
54
43
|
for (const [name, schema] of Object.entries(def.methods)) {
|
|
55
44
|
const m = schema;
|
|
56
45
|
if (m.kind === 'subscription')
|
|
57
46
|
continue;
|
|
58
|
-
if (
|
|
47
|
+
if (isArrayOutputSchema(m.output))
|
|
59
48
|
names.push(name);
|
|
60
49
|
}
|
|
61
50
|
if (names.length > 0)
|
|
@@ -77,7 +66,7 @@ function computeArrayMethods() {
|
|
|
77
66
|
*/
|
|
78
67
|
function isGlobalCollection(reg, capName) {
|
|
79
68
|
const def = reg.getDefinition(capName);
|
|
80
|
-
return def !== undefined &&
|
|
69
|
+
return def !== undefined && resolveCapMount(def).kind === 'collection';
|
|
81
70
|
}
|
|
82
71
|
/**
|
|
83
72
|
* Resolve a collection cap's provider exactly as the codegen-emitted
|
|
@@ -103,7 +92,7 @@ function resolveCollectionProvider(reg, capName, addonId) {
|
|
|
103
92
|
const first = providers[0];
|
|
104
93
|
if (first === undefined)
|
|
105
94
|
return null;
|
|
106
|
-
const arrayMethods =
|
|
95
|
+
const arrayMethods = COLLECTION_ARRAY_METHODS.get(capName);
|
|
107
96
|
if (!arrayMethods || arrayMethods.length === 0)
|
|
108
97
|
return first;
|
|
109
98
|
const aggregate = { ...first };
|
|
@@ -128,12 +117,12 @@ function resolveCollectionProvider(reg, capName, addonId) {
|
|
|
128
117
|
* `null` on zero providers too: that is the empty-collection fast-path's job
|
|
129
118
|
* (it answers `[]` without routing), not this one's.
|
|
130
119
|
*/
|
|
131
|
-
async function aggregateCollectionCall(reg, capName, method, args) {
|
|
120
|
+
export async function aggregateCollectionCall(reg, capName, method, args) {
|
|
132
121
|
if (!reg)
|
|
133
122
|
return null;
|
|
134
123
|
if (!isGlobalCollection(reg, capName))
|
|
135
124
|
return null;
|
|
136
|
-
if (!
|
|
125
|
+
if (!COLLECTION_ARRAY_METHODS.get(capName)?.includes(method))
|
|
137
126
|
return null;
|
|
138
127
|
if (reg.getCollectionEntries(capName).length === 0)
|
|
139
128
|
return null;
|
|
@@ -157,7 +146,7 @@ function isDeviceCollection(reg, capName) {
|
|
|
157
146
|
const def = reg.getDefinition(capName);
|
|
158
147
|
if (def === undefined)
|
|
159
148
|
return false;
|
|
160
|
-
return def.mode === 'collection' &&
|
|
149
|
+
return def.mode === 'collection' && resolveCapMount(def).kind === 'device-scoped';
|
|
161
150
|
}
|
|
162
151
|
/**
|
|
163
152
|
* The `{ provider }` a DEVICE-collection call pins to, or `null`.
|
|
@@ -184,7 +173,7 @@ function isDeviceCollection(reg, capName) {
|
|
|
184
173
|
* is required on `listClips` too (D554), and the narrowing happens inside
|
|
185
174
|
* `requireDeviceCollection`, which then decides fan-out vs scalar itself.
|
|
186
175
|
*/
|
|
187
|
-
function devicePinOf(reg, capName, args) {
|
|
176
|
+
export function devicePinOf(reg, capName, args) {
|
|
188
177
|
if (!reg)
|
|
189
178
|
return null;
|
|
190
179
|
if (!isDeviceCollection(reg, capName))
|
|
@@ -194,7 +183,7 @@ function devicePinOf(reg, capName, args) {
|
|
|
194
183
|
const rec = args;
|
|
195
184
|
if (typeof rec['deviceId'] !== 'number')
|
|
196
185
|
return null;
|
|
197
|
-
const pin = rec[
|
|
186
|
+
const pin = rec[PROVIDER_PIN_FIELD];
|
|
198
187
|
return typeof pin === 'string' && pin.length > 0 ? pin : null;
|
|
199
188
|
}
|
|
200
189
|
/**
|
|
@@ -210,10 +199,10 @@ function devicePinOf(reg, capName, args) {
|
|
|
210
199
|
* legitimately answer `null`, which a bare return could not tell from "not
|
|
211
200
|
* handled".
|
|
212
201
|
*/
|
|
213
|
-
async function pinnedDeviceCollectionCall(reg, capName, method, args) {
|
|
202
|
+
export async function pinnedDeviceCollectionCall(reg, capName, method, args) {
|
|
214
203
|
if (devicePinOf(reg, capName, args) === null)
|
|
215
204
|
return null;
|
|
216
|
-
const dispatcher =
|
|
205
|
+
const dispatcher = requireDeviceCollection(reg, capName);
|
|
217
206
|
if (dispatcher === null)
|
|
218
207
|
return null;
|
|
219
208
|
const fn = dispatcher[method];
|
|
@@ -239,12 +228,12 @@ async function pinnedDeviceCollectionCall(reg, capName, method, args) {
|
|
|
239
228
|
* (there `addonId` is provider DATA: `addons.getLogs({addonId})` names the addon
|
|
240
229
|
* whose logs you want, it does not name a provider).
|
|
241
230
|
*/
|
|
242
|
-
function addonPinOf(reg, capName, method, args) {
|
|
231
|
+
export function addonPinOf(reg, capName, method, args) {
|
|
243
232
|
if (!reg)
|
|
244
233
|
return null;
|
|
245
234
|
if (!isGlobalCollection(reg, capName))
|
|
246
235
|
return null;
|
|
247
|
-
if (
|
|
236
|
+
if (COLLECTION_ARRAY_METHODS.get(capName)?.includes(method) === true)
|
|
248
237
|
return null;
|
|
249
238
|
if (args === null || typeof args !== 'object' || Array.isArray(args))
|
|
250
239
|
return null;
|
|
@@ -290,7 +279,7 @@ function addonPinOf(reg, capName, method, args) {
|
|
|
290
279
|
* Returns a `{ value }` box, never the bare result: `getBrokerConfig` answers
|
|
291
280
|
* `null` legitimately, so a bare `null` could not be told from "not handled".
|
|
292
281
|
*/
|
|
293
|
-
async function pinnedCollectionCall(reg, capName, method, args) {
|
|
282
|
+
export async function pinnedCollectionCall(reg, capName, method, args) {
|
|
294
283
|
const addonId = addonPinOf(reg, capName, method, args);
|
|
295
284
|
if (addonId === null)
|
|
296
285
|
return null;
|
|
@@ -327,11 +316,11 @@ function concatArrayMethod(providers, method) {
|
|
|
327
316
|
};
|
|
328
317
|
}
|
|
329
318
|
/** Build the `primitives` half of `buildCapRouters(primitives, services)`. */
|
|
330
|
-
function createCapRouterPrimitives() {
|
|
319
|
+
export function createCapRouterPrimitives() {
|
|
331
320
|
const procedures = {
|
|
332
|
-
public:
|
|
333
|
-
protected:
|
|
334
|
-
admin:
|
|
321
|
+
public: publicProcedure,
|
|
322
|
+
protected: protectedProcedure,
|
|
323
|
+
admin: adminProcedure,
|
|
335
324
|
};
|
|
336
325
|
return {
|
|
337
326
|
// Documented type boundary: the builder hands a record of REAL tRPC
|
|
@@ -340,13 +329,13 @@ function createCapRouterPrimitives() {
|
|
|
340
329
|
// `CreateRouterOptions`; the runtime values satisfy it. Narrow at this
|
|
341
330
|
// single seam so the rest of the builder stays free of `@trpc/server`
|
|
342
331
|
// internal types — mirrors the existing `remoteCapProxy` cast pattern.
|
|
343
|
-
router: (procs) =>
|
|
332
|
+
router: (procs) => trpcRouter(procs),
|
|
344
333
|
procedures,
|
|
345
|
-
iterableSubscription
|
|
334
|
+
iterableSubscription,
|
|
346
335
|
};
|
|
347
336
|
}
|
|
348
337
|
/** Build the `services` half of `buildCapRouters(primitives, services)`. */
|
|
349
|
-
function createCapRouterServices(deps) {
|
|
338
|
+
export function createCapRouterServices(deps) {
|
|
350
339
|
const reg = deps.capabilityRegistry;
|
|
351
340
|
const remoteProxy = (capName, nodeId) => deps.moleculer.createCapabilityProxy(capName, nodeId);
|
|
352
341
|
const getLocalProvider = (capName, mountKind, ctx, addonId) => {
|
|
@@ -375,9 +364,9 @@ function createCapRouterServices(deps) {
|
|
|
375
364
|
// collection twin fans the array methods over the device's sources and
|
|
376
365
|
// routes the scalar ones by the source inside the id.
|
|
377
366
|
if (reg?.getMode(capName) === 'collection') {
|
|
378
|
-
return
|
|
367
|
+
return requireDeviceCollection(reg, capName, deps.logger);
|
|
379
368
|
}
|
|
380
|
-
return
|
|
369
|
+
return requireDeviceScoped(reg, capName);
|
|
381
370
|
}
|
|
382
371
|
case 'collection':
|
|
383
372
|
return resolveCollectionProvider(reg, capName, addonId);
|
|
@@ -412,7 +401,7 @@ function createCapRouterServices(deps) {
|
|
|
412
401
|
tags: { addonId },
|
|
413
402
|
meta: { capability: capName, validAddonIds: [...known] },
|
|
414
403
|
});
|
|
415
|
-
throw new
|
|
404
|
+
throw new TRPCError({
|
|
416
405
|
code: 'BAD_REQUEST',
|
|
417
406
|
message: `Capability "${capName}" has no provider with addonId "${addonId}". ` +
|
|
418
407
|
`Valid addonId(s): ${known.join(', ')}. ` +
|
|
@@ -425,30 +414,30 @@ function createCapRouterServices(deps) {
|
|
|
425
414
|
rejectUnresolvedAddonPin,
|
|
426
415
|
noProvider: (capName, nodeId) => {
|
|
427
416
|
if (nodeId !== undefined && nodeId !== 'hub') {
|
|
428
|
-
throw new
|
|
417
|
+
throw new TRPCError({
|
|
429
418
|
code: 'PRECONDITION_FAILED',
|
|
430
419
|
message: `Capability "${capName}" not available on node "${nodeId}"`,
|
|
431
420
|
});
|
|
432
421
|
}
|
|
433
|
-
throw new
|
|
422
|
+
throw new TRPCError({
|
|
434
423
|
code: 'PRECONDITION_FAILED',
|
|
435
424
|
message: `Capability "${capName}" provider not available`,
|
|
436
425
|
});
|
|
437
426
|
},
|
|
438
427
|
noNodeRouting: (capName) => {
|
|
439
|
-
throw new
|
|
428
|
+
throw new TRPCError({
|
|
440
429
|
code: 'BAD_REQUEST',
|
|
441
430
|
message: `Node routing not available for "${capName}"`,
|
|
442
431
|
});
|
|
443
432
|
},
|
|
444
433
|
badRequest: (message) => {
|
|
445
|
-
throw new
|
|
434
|
+
throw new TRPCError({ code: 'BAD_REQUEST', message });
|
|
446
435
|
},
|
|
447
436
|
// D-1 caller-identity injection: a `caller: 'required'` method whose
|
|
448
437
|
// context carries no authenticated user fails closed — the builder
|
|
449
438
|
// never fabricates an identity.
|
|
450
439
|
unauthorized: (message) => {
|
|
451
|
-
throw new
|
|
440
|
+
throw new TRPCError({ code: 'UNAUTHORIZED', message });
|
|
452
441
|
},
|
|
453
442
|
// Task 7.5d: a resolved provider that does not implement `method` must
|
|
454
443
|
// fail, not answer `undefined` (200). NOT_IMPLEMENTED mirrors what
|
|
@@ -456,7 +445,7 @@ function createCapRouterServices(deps) {
|
|
|
456
445
|
// child plane — the hub previously answered silently where the child
|
|
457
446
|
// already throws.
|
|
458
447
|
methodNotFound: (capName, method) => {
|
|
459
|
-
throw new
|
|
448
|
+
throw new TRPCError({
|
|
460
449
|
code: 'NOT_IMPLEMENTED',
|
|
461
450
|
message: `Capability "${capName}" has no method "${method}"`,
|
|
462
451
|
});
|
|
@@ -470,6 +459,6 @@ function createCapRouterServices(deps) {
|
|
|
470
459
|
* boundary so the AppRouter TYPE stays codegen-derived while the VALUE is
|
|
471
460
|
* built at runtime from `ALL_CAPABILITY_DEFINITIONS`.
|
|
472
461
|
*/
|
|
473
|
-
function buildRuntimeCapRouters(deps) {
|
|
474
|
-
return
|
|
462
|
+
export function buildRuntimeCapRouters(deps) {
|
|
463
|
+
return buildCapRouters(createCapRouterPrimitives(), createCapRouterServices(deps));
|
|
475
464
|
}
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.extractClientIp = extractClientIp;
|
|
4
|
-
exports.extractCfConnectingIp = extractCfConnectingIp;
|
|
5
|
-
exports.extractPeerIp = extractPeerIp;
|
|
6
|
-
exports.extractUserAgent = extractUserAgent;
|
|
7
|
-
exports.ipClass = ipClass;
|
|
8
|
-
exports.classifyClient = classifyClient;
|
|
9
|
-
exports.classifyClientRequest = classifyClientRequest;
|
|
10
|
-
exports.deriveRelayOnly = deriveRelayOnly;
|
|
11
|
-
exports.isRemoteClientIp = isRemoteClientIp;
|
|
12
1
|
/**
|
|
13
2
|
* Best-effort extraction of the originating client IP from a tRPC
|
|
14
3
|
* request. Order of preference:
|
|
@@ -22,7 +11,7 @@ exports.isRemoteClientIp = isRemoteClientIp;
|
|
|
22
11
|
* calls that carry no HTTP request) — the caller treats `null` as "not
|
|
23
12
|
* remote" so the LAN/direct path stays the safe default.
|
|
24
13
|
*/
|
|
25
|
-
function extractClientIp(req) {
|
|
14
|
+
export function extractClientIp(req) {
|
|
26
15
|
if (!req)
|
|
27
16
|
return null;
|
|
28
17
|
// 1. X-Forwarded-For — comma-separated list, client is the FIRST entry.
|
|
@@ -58,7 +47,7 @@ function extractClientIp(req) {
|
|
|
58
47
|
* direct internet client that forges the header still classifies by its own
|
|
59
48
|
* (remote) peer address. Returns `null` when absent.
|
|
60
49
|
*/
|
|
61
|
-
function extractCfConnectingIp(req) {
|
|
50
|
+
export function extractCfConnectingIp(req) {
|
|
62
51
|
if (!req)
|
|
63
52
|
return null;
|
|
64
53
|
const raw = req.headers['cf-connecting-ip'];
|
|
@@ -74,7 +63,7 @@ function extractCfConnectingIp(req) {
|
|
|
74
63
|
* loopback/LAN peer (the local `cloudflared` connector). Returns `null` when
|
|
75
64
|
* no socket is present (mesh-originated calls).
|
|
76
65
|
*/
|
|
77
|
-
function extractPeerIp(req) {
|
|
66
|
+
export function extractPeerIp(req) {
|
|
78
67
|
if (!req)
|
|
79
68
|
return null;
|
|
80
69
|
const remote = req.socket?.remoteAddress;
|
|
@@ -91,7 +80,7 @@ function extractPeerIp(req) {
|
|
|
91
80
|
* subscriber's broker attribution with the viewer's UA — the SERVER reads
|
|
92
81
|
* it from the request context; any client-supplied value is ignored.
|
|
93
82
|
*/
|
|
94
|
-
function extractUserAgent(req) {
|
|
83
|
+
export function extractUserAgent(req) {
|
|
95
84
|
if (!req)
|
|
96
85
|
return null;
|
|
97
86
|
const ua = req.headers['user-agent'];
|
|
@@ -118,7 +107,7 @@ function normalizeIp(ip) {
|
|
|
118
107
|
* Classify a single already-normalised IP literal. Null / unparseable →
|
|
119
108
|
* `'lan'` (the safe default that keeps the low-latency direct path).
|
|
120
109
|
*/
|
|
121
|
-
function ipClass(ip) {
|
|
110
|
+
export function ipClass(ip) {
|
|
122
111
|
if (!ip)
|
|
123
112
|
return 'lan';
|
|
124
113
|
if (ip.includes(':')) {
|
|
@@ -149,7 +138,7 @@ function ipClass(ip) {
|
|
|
149
138
|
* header is ignored (a direct internet client could forge it) and we classify
|
|
150
139
|
* by the proxy-resolved `clientIp`.
|
|
151
140
|
*/
|
|
152
|
-
function classifyClient(args) {
|
|
141
|
+
export function classifyClient(args) {
|
|
153
142
|
if (args.peerIsLocal && args.cfConnectingIp)
|
|
154
143
|
return ipClass(args.cfConnectingIp);
|
|
155
144
|
return ipClass(args.clientIp);
|
|
@@ -160,7 +149,7 @@ function classifyClient(args) {
|
|
|
160
149
|
* than forcing a policy. Composes `extractClientIp` (proxy-aware), the
|
|
161
150
|
* `CF-Connecting-IP` header, and the immediate socket peer (CF trust gate).
|
|
162
151
|
*/
|
|
163
|
-
function classifyClientRequest(req) {
|
|
152
|
+
export function classifyClientRequest(req) {
|
|
164
153
|
if (!req)
|
|
165
154
|
return null;
|
|
166
155
|
const clientIp = extractClientIp(req);
|
|
@@ -178,7 +167,7 @@ function classifyClientRequest(req) {
|
|
|
178
167
|
* direct overlay host pair; forcing TURN would be worse).
|
|
179
168
|
* - `lan` → false (low-latency direct host/srflx path).
|
|
180
169
|
*/
|
|
181
|
-
function deriveRelayOnly(clientClass) {
|
|
170
|
+
export function deriveRelayOnly(clientClass) {
|
|
182
171
|
return clientClass === 'remote';
|
|
183
172
|
}
|
|
184
173
|
/**
|
|
@@ -188,7 +177,7 @@ function deriveRelayOnly(clientClass) {
|
|
|
188
177
|
* (`'vpn'`) is NOT remote (kept on the direct overlay path). Unparseable /
|
|
189
178
|
* null → false (safe LAN default).
|
|
190
179
|
*/
|
|
191
|
-
function isRemoteClientIp(ip) {
|
|
180
|
+
export function isRemoteClientIp(ip) {
|
|
192
181
|
return ipClass(ip) === 'remote';
|
|
193
182
|
}
|
|
194
183
|
function isIpv4(ip) {
|