@camstack/server 1.0.0 → 1.0.1
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/{src/agent-status-page.ts → dist/agent-status-page.js} +30 -45
- package/dist/api/addon-upload.js +441 -0
- package/dist/api/addons-custom.router.js +91 -0
- package/dist/api/auth-whoami.js +55 -0
- package/dist/api/bridge-addons.router.js +109 -0
- package/dist/api/capabilities.router.js +229 -0
- package/dist/api/core/addon-settings.router.js +117 -0
- package/dist/api/core/agents.router.js +73 -0
- package/dist/api/core/auth.router.js +286 -0
- package/dist/api/core/bulk-update-coordinator.js +229 -0
- package/dist/api/core/cap-providers.js +1124 -0
- package/dist/api/core/capabilities.router.js +138 -0
- package/dist/api/core/collection-preference.js +17 -0
- package/dist/api/core/event-bus-proxy.router.js +45 -0
- package/dist/api/core/hwaccel.router.js +91 -0
- package/dist/api/core/live-events.router.js +61 -0
- package/dist/api/core/logs.router.js +172 -0
- package/dist/api/core/notifications.router.js +67 -0
- package/dist/api/core/repl.router.js +35 -0
- package/dist/api/core/settings-backend.router.js +121 -0
- package/dist/api/core/stream-probe.router.js +58 -0
- package/dist/api/core/system-events.router.js +100 -0
- package/dist/api/health/health.routes.js +68 -0
- package/{src/api/oauth2/consent-page.ts → dist/api/oauth2/consent-page.js} +11 -20
- package/dist/api/oauth2/oauth2-routes.js +219 -0
- package/dist/api/trpc/cap-mount-helpers.js +194 -0
- package/dist/api/trpc/cap-route-error-formatter.js +133 -0
- package/dist/api/trpc/client-ip.js +147 -0
- package/dist/api/trpc/core-cap-bridge.js +115 -0
- package/dist/api/trpc/generated-cap-mounts.js +388 -0
- package/dist/api/trpc/generated-cap-routers.js +7635 -0
- package/dist/api/trpc/scope-access.js +93 -0
- package/dist/api/trpc/trpc.context.js +184 -0
- package/dist/api/trpc/trpc.middleware.js +139 -0
- package/dist/api/trpc/trpc.router.js +188 -0
- package/dist/auth/session-cookie.js +47 -0
- package/dist/boot/boot-config.js +241 -0
- package/dist/boot/integration-id-backfill.js +76 -0
- package/dist/boot/post-boot.service.js +85 -0
- package/dist/core/addon/addon-call-gateway.js +99 -0
- package/dist/core/addon/addon-package.service.js +1560 -0
- package/dist/core/addon/addon-registry.service.js +2739 -0
- package/{src/core/addon/addon-row-manifest.ts → dist/core/addon/addon-row-manifest.js} +5 -5
- package/dist/core/addon/addon-search.service.js +62 -0
- package/dist/core/addon/addon-settings-provider.js +102 -0
- package/dist/core/addon/addon.tokens.js +5 -0
- package/dist/core/addon-bridge/addon-bridge.service.js +145 -0
- package/dist/core/addon-pages/addon-pages.service.js +107 -0
- package/dist/core/addon-widgets/addon-widgets.service.js +120 -0
- package/dist/core/agent/agent-registry.service.js +477 -0
- package/dist/core/auth/auth.service.js +10 -0
- package/dist/core/capability/capability.service.js +58 -0
- package/dist/core/config/config.schema.js +7 -0
- package/dist/core/config/config.service.js +10 -0
- package/dist/core/events/event-bus.service.js +83 -0
- package/dist/core/feature/feature.service.js +10 -0
- package/dist/core/lifecycle/lifecycle-state-machine.js +6 -0
- package/dist/core/logging/log-ring-buffer.js +6 -0
- package/dist/core/logging/logging.service.js +130 -0
- package/dist/core/logging/scoped-logger.js +6 -0
- package/dist/core/moleculer/cap-call-fn.js +50 -0
- package/dist/core/moleculer/cap-route-authority.js +122 -0
- package/dist/core/moleculer/moleculer.service.js +898 -0
- package/dist/core/network/network-quality.service.js +7 -0
- package/dist/core/notification/notification-wrapper.service.js +33 -0
- package/dist/core/notification/toast-wrapper.service.js +25 -0
- package/dist/core/provider/provider.tokens.js +4 -0
- package/dist/core/repl/repl-engine.service.js +140 -0
- package/dist/core/storage/fs-storage-backend.js +6 -0
- package/dist/core/storage/storage-location-manager.js +6 -0
- package/dist/core/storage/storage.service.js +7 -0
- package/dist/core/streaming/stream-probe.service.js +209 -0
- package/dist/core/topology/topology-emitter.service.js +106 -0
- package/dist/launcher.js +325 -0
- package/dist/main.js +1098 -0
- package/dist/manual-boot.js +227 -0
- package/package.json +5 -1
- package/src/__tests__/addon-install-e2e.test.ts +0 -74
- package/src/__tests__/addon-pages-e2e.test.ts +0 -200
- package/src/__tests__/addon-route-session.test.ts +0 -17
- package/src/__tests__/addon-settings-router.spec.ts +0 -67
- package/src/__tests__/addon-upload.spec.ts +0 -475
- package/src/__tests__/agent-registry.spec.ts +0 -179
- package/src/__tests__/agent-status-page.spec.ts +0 -82
- package/src/__tests__/auth-session-cookie.test.ts +0 -48
- package/src/__tests__/bulk-update-coordinator.spec.ts +0 -303
- package/src/__tests__/cap-ownership-authority.spec.ts +0 -431
- package/src/__tests__/cap-providers/cap-providers-location-import.spec.ts +0 -206
- package/src/__tests__/cap-providers/cap-usage-graph.spec.ts +0 -37
- package/src/__tests__/cap-providers/compute-topology-categories.spec.ts +0 -110
- package/src/__tests__/cap-providers/integrations-delete-cascade.spec.ts +0 -292
- package/src/__tests__/cap-providers-bulk-update.spec.ts +0 -408
- package/src/__tests__/cap-route-adapter.spec.ts +0 -302
- package/src/__tests__/cap-routers/_meta.spec.ts +0 -199
- package/src/__tests__/cap-routers/addon-settings.router.spec.ts +0 -115
- package/src/__tests__/cap-routers/broker-routing.router.spec.ts +0 -177
- package/src/__tests__/cap-routers/cap-route-error-formatter.spec.ts +0 -125
- package/src/__tests__/cap-routers/capabilities-node.spec.ts +0 -68
- package/src/__tests__/cap-routers/device-link-overlay.spec.ts +0 -137
- package/src/__tests__/cap-routers/device-manager-aggregate.router.spec.ts +0 -194
- package/src/__tests__/cap-routers/harness.ts +0 -163
- package/src/__tests__/cap-routers/metrics-provider.router.spec.ts +0 -133
- package/src/__tests__/cap-routers/null-provider-guard.spec.ts +0 -64
- package/src/__tests__/cap-routers/pipeline-executor.router.spec.ts +0 -159
- package/src/__tests__/cap-routers/settings-store.router.spec.ts +0 -291
- package/src/__tests__/capability-e2e.test.ts +0 -384
- package/src/__tests__/cli-e2e.test.ts +0 -150
- package/src/__tests__/core-cap-bridge.spec.ts +0 -91
- package/src/__tests__/dev-bootstrap-shm-ring.spec.ts +0 -40
- package/src/__tests__/device-settings-contribution-dispatch.spec.ts +0 -280
- package/src/__tests__/embedded-deps-e2e.test.ts +0 -125
- package/src/__tests__/event-bus-proxy-router.spec.ts +0 -75
- package/src/__tests__/fixtures/mock-analysis-addon-a.ts +0 -37
- package/src/__tests__/fixtures/mock-analysis-addon-b.ts +0 -37
- package/src/__tests__/fixtures/mock-log-addon.ts +0 -37
- package/src/__tests__/fixtures/mock-storage-addon.ts +0 -40
- package/src/__tests__/framework-allowlist.spec.ts +0 -96
- package/src/__tests__/framework-installer-defer-restart.spec.ts +0 -165
- package/src/__tests__/https-e2e.test.ts +0 -124
- package/src/__tests__/lifecycle-e2e.test.ts +0 -189
- package/src/__tests__/live-events-subscription.spec.ts +0 -149
- package/src/__tests__/moleculer/uds-readiness.spec.ts +0 -150
- package/src/__tests__/moleculer/uds-topology.spec.ts +0 -418
- package/src/__tests__/moleculer/uds-unowned-call.spec.ts +0 -383
- package/src/__tests__/moleculer-register-node-idempotency.spec.ts +0 -273
- package/src/__tests__/native-cap-route.spec.ts +0 -427
- package/src/__tests__/oauth2-account-linking.spec.ts +0 -867
- package/src/__tests__/post-boot-restart.spec.ts +0 -161
- package/src/__tests__/singleton-contention.test.ts +0 -499
- package/src/__tests__/streaming-diagnostic.test.ts +0 -615
- package/src/__tests__/streaming-scale.test.ts +0 -314
- package/src/__tests__/uds-addon-call-wiring.spec.ts +0 -242
- package/src/__tests__/uds-log-ingest.spec.ts +0 -183
- package/src/api/__tests__/addons-custom.spec.ts +0 -148
- package/src/api/__tests__/capabilities.router.test.ts +0 -56
- package/src/api/addon-upload.ts +0 -529
- package/src/api/addons-custom.router.ts +0 -101
- package/src/api/auth-whoami.ts +0 -101
- package/src/api/bridge-addons.router.ts +0 -122
- package/src/api/capabilities.router.ts +0 -265
- package/src/api/core/__tests__/auth-router-totp.spec.ts +0 -297
- package/src/api/core/__tests__/integration-markers.spec.ts +0 -10
- package/src/api/core/addon-settings.router.ts +0 -127
- package/src/api/core/agents.router.ts +0 -86
- package/src/api/core/auth.router.ts +0 -322
- package/src/api/core/bulk-update-coordinator.ts +0 -305
- package/src/api/core/cap-providers.ts +0 -1339
- package/src/api/core/capabilities.router.ts +0 -149
- package/src/api/core/collection-preference.ts +0 -40
- package/src/api/core/event-bus-proxy.router.ts +0 -45
- package/src/api/core/hwaccel.router.ts +0 -108
- package/src/api/core/live-events.router.ts +0 -67
- package/src/api/core/logs.router.ts +0 -195
- package/src/api/core/notifications.router.ts +0 -66
- package/src/api/core/repl.router.ts +0 -39
- package/src/api/core/settings-backend.router.ts +0 -140
- package/src/api/core/stream-probe.router.ts +0 -57
- package/src/api/core/system-events.router.ts +0 -125
- package/src/api/health/health.routes.ts +0 -117
- package/src/api/oauth2/__tests__/oauth2-routes.spec.ts +0 -62
- package/src/api/oauth2/oauth2-routes.ts +0 -281
- package/src/api/trpc/__tests__/client-ip.spec.ts +0 -146
- package/src/api/trpc/__tests__/scope-access-device.spec.ts +0 -268
- package/src/api/trpc/__tests__/scope-access.spec.ts +0 -102
- package/src/api/trpc/__tests__/webrtc-session-ua-enrich.spec.ts +0 -136
- package/src/api/trpc/cap-mount-helpers.ts +0 -245
- package/src/api/trpc/cap-route-error-formatter.ts +0 -171
- package/src/api/trpc/client-ip.ts +0 -147
- package/src/api/trpc/core-cap-bridge.ts +0 -154
- package/src/api/trpc/generated-cap-mounts.ts +0 -1240
- package/src/api/trpc/generated-cap-routers.ts +0 -11523
- package/src/api/trpc/scope-access.ts +0 -110
- package/src/api/trpc/trpc.context.ts +0 -258
- package/src/api/trpc/trpc.middleware.ts +0 -146
- package/src/api/trpc/trpc.router.ts +0 -389
- package/src/auth/session-cookie.ts +0 -54
- package/src/boot/__tests__/integration-id-backfill.spec.ts +0 -131
- package/src/boot/boot-config.ts +0 -259
- package/src/boot/integration-id-backfill.ts +0 -109
- package/src/boot/post-boot.service.ts +0 -105
- package/src/core/addon/__tests__/addon-registry-capability.test.ts +0 -62
- package/src/core/addon/__tests__/addon-row-manifest.spec.ts +0 -62
- package/src/core/addon/addon-call-gateway.ts +0 -171
- package/src/core/addon/addon-package.service.ts +0 -1787
- package/src/core/addon/addon-registry.service.ts +0 -3130
- package/src/core/addon/addon-search.service.ts +0 -91
- package/src/core/addon/addon-settings-provider.ts +0 -220
- package/src/core/addon/addon.tokens.ts +0 -2
- package/src/core/addon-bridge/addon-bridge.service.ts +0 -130
- package/src/core/addon-pages/addon-pages.service.spec.ts +0 -117
- package/src/core/addon-pages/addon-pages.service.ts +0 -82
- package/src/core/addon-widgets/addon-widgets.service.ts +0 -95
- package/src/core/agent/agent-registry.service.ts +0 -529
- package/src/core/auth/auth.service.spec.ts +0 -86
- package/src/core/auth/auth.service.ts +0 -8
- package/src/core/capability/capability.service.ts +0 -66
- package/src/core/config/config.schema.ts +0 -3
- package/src/core/config/config.service.spec.ts +0 -175
- package/src/core/config/config.service.ts +0 -7
- package/src/core/events/event-bus.service.spec.ts +0 -235
- package/src/core/events/event-bus.service.ts +0 -89
- package/src/core/feature/feature.service.spec.ts +0 -99
- package/src/core/feature/feature.service.ts +0 -8
- package/src/core/lifecycle/lifecycle-state-machine.spec.ts +0 -166
- package/src/core/lifecycle/lifecycle-state-machine.ts +0 -3
- package/src/core/logging/log-ring-buffer.ts +0 -3
- package/src/core/logging/logging.service.spec.ts +0 -287
- package/src/core/logging/logging.service.ts +0 -143
- package/src/core/logging/scoped-logger.ts +0 -3
- package/src/core/moleculer/cap-call-fn.spec.ts +0 -173
- package/src/core/moleculer/cap-call-fn.ts +0 -107
- package/src/core/moleculer/cap-route-authority.ts +0 -194
- package/src/core/moleculer/moleculer.service.ts +0 -1072
- package/src/core/network/network-quality.service.spec.ts +0 -53
- package/src/core/network/network-quality.service.ts +0 -5
- package/src/core/notification/notification-wrapper.service.ts +0 -34
- package/src/core/notification/toast-wrapper.service.ts +0 -27
- package/src/core/provider/provider.tokens.ts +0 -1
- package/src/core/repl/repl-engine.service.spec.ts +0 -444
- package/src/core/repl/repl-engine.service.ts +0 -155
- package/src/core/storage/fs-storage-backend.spec.ts +0 -70
- package/src/core/storage/fs-storage-backend.ts +0 -3
- package/src/core/storage/storage-location-manager.spec.ts +0 -130
- package/src/core/storage/storage-location-manager.ts +0 -3
- package/src/core/storage/storage.service.spec.ts +0 -73
- package/src/core/storage/storage.service.ts +0 -3
- package/src/core/streaming/stream-probe.service.ts +0 -221
- package/src/core/topology/topology-emitter.service.ts +0 -105
- package/src/launcher.ts +0 -314
- package/src/main.ts +0 -1245
- package/src/manual-boot.ts +0 -301
- package/tsconfig.build.json +0 -8
- package/tsconfig.json +0 -33
- package/vitest.config.ts +0 -26
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.requireSingleton = requireSingleton;
|
|
4
|
+
exports.requireDeviceScoped = requireDeviceScoped;
|
|
5
|
+
exports.concatCollection = concatCollection;
|
|
6
|
+
exports.firstSupported = firstSupported;
|
|
7
|
+
exports.anySupports = anySupports;
|
|
8
|
+
/**
|
|
9
|
+
* Small helpers for wiring capability routers to the `CapabilityRegistry`
|
|
10
|
+
* in `trpc.router.ts`. These functions don't generate code — they just
|
|
11
|
+
* remove boilerplate from the mount lambdas we pass to `createCapRouter_X`.
|
|
12
|
+
*
|
|
13
|
+
* When to use what:
|
|
14
|
+
* - `requireSingleton(registry, name)` — singleton caps with no custom
|
|
15
|
+
* composition. Returns the active provider or null (the codegen'd
|
|
16
|
+
* router itself throws PRECONDITION_FAILED when null).
|
|
17
|
+
* - `concatCollection(providers, method)` — collection caps whose
|
|
18
|
+
* methods return arrays and where the desired behaviour is "union of
|
|
19
|
+
* every provider's contribution" (e.g. `turn-provider.getTurnServers`).
|
|
20
|
+
* - `firstSupported(providers, probe, action)` — collection caps where
|
|
21
|
+
* exactly one provider should handle each request, selected by a
|
|
22
|
+
* probe method (e.g. `snapshot-provider.supportsDevice`).
|
|
23
|
+
*
|
|
24
|
+
* Collections that route by an input key (e.g. `webrtc` picking the
|
|
25
|
+
* provider responsible for a given `streamId`) are NOT covered here —
|
|
26
|
+
* they have app-specific routing logic that belongs in the mount.
|
|
27
|
+
*/
|
|
28
|
+
const server_1 = require("@trpc/server");
|
|
29
|
+
/**
|
|
30
|
+
* Fetch the currently active singleton provider for a capability.
|
|
31
|
+
* Returns null if no provider is registered; the downstream codegen'd
|
|
32
|
+
* router surfaces this as `PRECONDITION_FAILED` to the caller.
|
|
33
|
+
*/
|
|
34
|
+
function requireSingleton(registry, capName) {
|
|
35
|
+
return registry?.getSingleton(capName) ?? null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build a per-device dispatcher that satisfies the singleton-provider
|
|
39
|
+
* shape but resolves the actual implementation lazily via
|
|
40
|
+
* `registry.getNativeProvider(capName, deviceId)` on every method call.
|
|
41
|
+
*
|
|
42
|
+
* Use for device-scoped caps that have NO system-level wrapper (PTZ,
|
|
43
|
+
* reboot, doorbell, brightness, motion-trigger, switch, …) — drivers
|
|
44
|
+
* register per-device native providers via
|
|
45
|
+
* `DeviceContext.registerNativeCap`, and this helper bridges the cap-
|
|
46
|
+
* router's "fetch a singleton then call methods on it" flow into a
|
|
47
|
+
* "resolve native by deviceId per call" flow.
|
|
48
|
+
*
|
|
49
|
+
* Method input MUST carry `deviceId: number`. Methods without that
|
|
50
|
+
* field (auto-injected `getStatus({deviceId})` for caps with a status
|
|
51
|
+
* block, every business method that follows the cap-definition
|
|
52
|
+
* convention) work transparently.
|
|
53
|
+
*
|
|
54
|
+
* Throws PRECONDITION_FAILED with a device-specific message when no
|
|
55
|
+
* native provider exists for the requested deviceId — much friendlier
|
|
56
|
+
* than the singleton fallthrough's "no provider" generic error.
|
|
57
|
+
*/
|
|
58
|
+
function requireDeviceScoped(registry, capName) {
|
|
59
|
+
if (!registry)
|
|
60
|
+
return null;
|
|
61
|
+
// The Proxy is the singleton stand-in. Each property access returns
|
|
62
|
+
// a function that, on call, looks up the per-device native and
|
|
63
|
+
// forwards the call. No caching — the lookup is cheap (Map.get) and
|
|
64
|
+
// re-doing it per call lets devices come/go without stale refs.
|
|
65
|
+
const dispatcher = new Proxy({}, {
|
|
66
|
+
get(_target, prop) {
|
|
67
|
+
if (typeof prop !== 'string')
|
|
68
|
+
return undefined;
|
|
69
|
+
return async (input) => {
|
|
70
|
+
const deviceId = input?.deviceId;
|
|
71
|
+
if (typeof deviceId !== 'number') {
|
|
72
|
+
throw new server_1.TRPCError({
|
|
73
|
+
code: 'BAD_REQUEST',
|
|
74
|
+
message: `${String(capName)}.${prop}: input must carry numeric "deviceId"`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const native = registry.getNativeProvider(capName, deviceId);
|
|
78
|
+
if (!native) {
|
|
79
|
+
throw new server_1.TRPCError({
|
|
80
|
+
code: 'PRECONDITION_FAILED',
|
|
81
|
+
message: `Capability "${String(capName)}" not registered for device ${deviceId}`,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const fn = native[prop];
|
|
85
|
+
if (typeof fn !== 'function') {
|
|
86
|
+
throw new server_1.TRPCError({
|
|
87
|
+
code: 'NOT_IMPLEMENTED',
|
|
88
|
+
message: `Capability "${String(capName)}" provider for device ${deviceId} does not implement "${prop}"`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const result = await fn.call(native, input);
|
|
92
|
+
// Device-property-wiring overlay (read-time): only `getStatus`, and only
|
|
93
|
+
// when the device has links for this cap (resolveLinkedStatus returns
|
|
94
|
+
// null otherwise → base result untouched). One in-process singleton hop.
|
|
95
|
+
if (prop === 'getStatus') {
|
|
96
|
+
const deviceManager = registry.getSingleton('device-manager');
|
|
97
|
+
const overlaid = await deviceManager?.resolveLinkedStatus?.({
|
|
98
|
+
deviceId,
|
|
99
|
+
cap: String(capName),
|
|
100
|
+
baseStatus: result,
|
|
101
|
+
});
|
|
102
|
+
if (overlaid != null)
|
|
103
|
+
return overlaid;
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
return dispatcher;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Build a method that fan-outs a call to every provider in a collection
|
|
113
|
+
* and concatenates their array results. Useful for contribution-style
|
|
114
|
+
* caps where each provider adds to a shared pool.
|
|
115
|
+
*/
|
|
116
|
+
function concatCollection(providers, method) {
|
|
117
|
+
const wrapper = async (...args) => {
|
|
118
|
+
const results = await Promise.all(providers.map(async (p) => {
|
|
119
|
+
const member = Reflect.get(p, method);
|
|
120
|
+
if (typeof member !== 'function')
|
|
121
|
+
return [];
|
|
122
|
+
// `Reflect.apply` returns `any`; funnel through unknown.
|
|
123
|
+
const out = await Reflect.apply(member, p, args);
|
|
124
|
+
if (!Array.isArray(out))
|
|
125
|
+
return [];
|
|
126
|
+
const arr = out;
|
|
127
|
+
return arr;
|
|
128
|
+
}));
|
|
129
|
+
return results.flat();
|
|
130
|
+
};
|
|
131
|
+
// Type-level bridge: the runtime wrapper signature (unknown → Promise<unknown[]>)
|
|
132
|
+
// matches the declared generic conditional return; TypeScript's
|
|
133
|
+
// conditional types can't be narrowed inside a function body, so this
|
|
134
|
+
// boundary assertion is required.
|
|
135
|
+
return wrapper;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Iterate a collection asking each provider "do you handle this?" via a
|
|
139
|
+
* probe method, then call an action on the first one that answers yes.
|
|
140
|
+
* Each provider is tried in registration order; errors are swallowed and
|
|
141
|
+
* the next provider is attempted. Returns null if no provider matches or
|
|
142
|
+
* if every matching provider's action throws/returns null.
|
|
143
|
+
*/
|
|
144
|
+
function firstSupported(providers, probe, action) {
|
|
145
|
+
const wrapper = async (...args) => {
|
|
146
|
+
const [first] = args;
|
|
147
|
+
for (const p of providers) {
|
|
148
|
+
try {
|
|
149
|
+
const probeMember = Reflect.get(p, probe);
|
|
150
|
+
if (typeof probeMember !== 'function')
|
|
151
|
+
continue;
|
|
152
|
+
const supported = await Reflect.apply(probeMember, p, [first]);
|
|
153
|
+
if (supported !== true)
|
|
154
|
+
continue;
|
|
155
|
+
const actionMember = Reflect.get(p, action);
|
|
156
|
+
if (typeof actionMember !== 'function')
|
|
157
|
+
continue;
|
|
158
|
+
const result = await Reflect.apply(actionMember, p, args);
|
|
159
|
+
if (result !== null && result !== undefined)
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// try next provider
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
};
|
|
168
|
+
// Type-level bridge — see concatCollection for the same pattern.
|
|
169
|
+
return wrapper;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Convenience for collection caps that want a "logical OR of probes"
|
|
173
|
+
* (e.g. `supportsDevice` across every snapshot-provider).
|
|
174
|
+
*/
|
|
175
|
+
function anySupports(providers, probe) {
|
|
176
|
+
const wrapper = async (...args) => {
|
|
177
|
+
for (const p of providers) {
|
|
178
|
+
const member = Reflect.get(p, probe);
|
|
179
|
+
if (typeof member !== 'function')
|
|
180
|
+
continue;
|
|
181
|
+
try {
|
|
182
|
+
const result = await Reflect.apply(member, p, args);
|
|
183
|
+
if (result === true)
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
/* next */
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return false;
|
|
191
|
+
};
|
|
192
|
+
// Type-level bridge — see concatCollection for the same pattern.
|
|
193
|
+
return wrapper;
|
|
194
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatTrpcError = formatTrpcError;
|
|
4
|
+
/**
|
|
5
|
+
* tRPC error formatter that serializes CapRouteError diagnostic fields
|
|
6
|
+
* across the server→client boundary.
|
|
7
|
+
*
|
|
8
|
+
* tRPC only carries `error.message` by default. This formatter augments
|
|
9
|
+
* the default shape's `data` block with typed CapRouteError fields so the
|
|
10
|
+
* admin-UI can read `capRouteReason` instead of substring-matching message text.
|
|
11
|
+
*
|
|
12
|
+
* Fields added (all optional — absent when the error is not a CapRouteError):
|
|
13
|
+
* - `capRouteReason` — 'no-provider' | 'node-offline' | 'cap-unknown' | 'transport-failed'
|
|
14
|
+
* - `capRouteRejected` — array of `{ kind: string; why: string }` route-rejection descriptors
|
|
15
|
+
* - `capRouteNodeId` — the target node id, when known
|
|
16
|
+
*
|
|
17
|
+
* The formatter is EXPORTED for unit testing (no side-effects, pure function).
|
|
18
|
+
*/
|
|
19
|
+
const kernel_1 = require("@camstack/kernel");
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Type guards
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
/** Known CapRouteError reason values — used as a runtime safety rail. */
|
|
24
|
+
const KNOWN_REASONS = new Set([
|
|
25
|
+
'no-provider',
|
|
26
|
+
'node-offline',
|
|
27
|
+
'cap-unknown',
|
|
28
|
+
'transport-failed',
|
|
29
|
+
]);
|
|
30
|
+
/** Narrows a plain string to the `CapRouteError['reason']` union. */
|
|
31
|
+
function isCapRouteReason(r) {
|
|
32
|
+
return KNOWN_REASONS.has(r);
|
|
33
|
+
}
|
|
34
|
+
/** Narrows an `unknown` value to `RejectedRoute` by checking structural shape. */
|
|
35
|
+
function isRejectedRoute(r) {
|
|
36
|
+
if (typeof r !== 'object' || r === null)
|
|
37
|
+
return false;
|
|
38
|
+
const kind = Reflect.get(r, 'kind');
|
|
39
|
+
const why = Reflect.get(r, 'why');
|
|
40
|
+
return typeof kind === 'string' && typeof why === 'string';
|
|
41
|
+
}
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// CapRouteError extraction helpers
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
/**
|
|
46
|
+
* Walks the `.cause` chain of an error to find a CapRouteError.
|
|
47
|
+
* Returns the first one found, or null.
|
|
48
|
+
*
|
|
49
|
+
* Detection is dual-mode:
|
|
50
|
+
* 1. `instanceof CapRouteError` — works when the same module is loaded.
|
|
51
|
+
* 2. Duck-type: `name === 'CapRouteError'` + `typeof reason === 'string'`
|
|
52
|
+
* — robust against module-boundary issues (self-contained addons).
|
|
53
|
+
*/
|
|
54
|
+
function extractCapRouteError(err) {
|
|
55
|
+
let current = err;
|
|
56
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
57
|
+
if (current === null || current === undefined)
|
|
58
|
+
return null;
|
|
59
|
+
if (current instanceof kernel_1.CapRouteError) {
|
|
60
|
+
return current;
|
|
61
|
+
}
|
|
62
|
+
// Duck-type fallback: err.name + err.reason field present
|
|
63
|
+
if (typeof current === 'object' && Reflect.get(current, 'name') === 'CapRouteError') {
|
|
64
|
+
const rawReason = Reflect.get(current, 'reason');
|
|
65
|
+
if (typeof rawReason === 'string') {
|
|
66
|
+
// Runtime safety: reject unrecognised reason strings so the formatter
|
|
67
|
+
// only promotes values it knows are valid CapRouteError reasons.
|
|
68
|
+
if (!isCapRouteReason(rawReason)) {
|
|
69
|
+
// Unrecognised reason — treat as a non-CapRouteError and keep walking
|
|
70
|
+
const cause = Reflect.get(current, 'cause');
|
|
71
|
+
if (cause === current)
|
|
72
|
+
return null;
|
|
73
|
+
current = cause;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const reason = rawReason;
|
|
77
|
+
const rawRejected = Reflect.get(current, 'rejected');
|
|
78
|
+
const rejected = Array.isArray(rawRejected)
|
|
79
|
+
? rawRejected.filter(isRejectedRoute)
|
|
80
|
+
: [];
|
|
81
|
+
const nodeId = Reflect.get(current, 'nodeId');
|
|
82
|
+
const message = Reflect.get(current, 'message');
|
|
83
|
+
const rawCapName = Reflect.get(current, 'capName');
|
|
84
|
+
const capName = typeof rawCapName === 'string' ? rawCapName : '(unknown)';
|
|
85
|
+
// Build a minimal object with the same shape — enough for the formatter.
|
|
86
|
+
const synthetic = Object.assign(new kernel_1.CapRouteError(capName, undefined, {
|
|
87
|
+
reason,
|
|
88
|
+
rejected,
|
|
89
|
+
...(typeof nodeId === 'string' ? { nodeId } : {}),
|
|
90
|
+
}), {
|
|
91
|
+
// Override message from the original if available
|
|
92
|
+
message: typeof message === 'string' ? message : '(duck-typed CapRouteError)',
|
|
93
|
+
});
|
|
94
|
+
return synthetic;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Walk the cause chain
|
|
98
|
+
if (typeof current !== 'object')
|
|
99
|
+
return null;
|
|
100
|
+
const cause = Reflect.get(current, 'cause');
|
|
101
|
+
if (cause === current)
|
|
102
|
+
return null; // Guard against circular refs
|
|
103
|
+
current = cause;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Augments the default tRPC error shape with CapRouteError diagnostic fields
|
|
109
|
+
* when the thrown error (or any error in its `.cause` chain) is a CapRouteError.
|
|
110
|
+
* Returns the shape unchanged for all other errors.
|
|
111
|
+
*/
|
|
112
|
+
function formatTrpcError(opts) {
|
|
113
|
+
const { error, shape } = opts;
|
|
114
|
+
// extractCapRouteError already walks the full .cause chain, so a single call
|
|
115
|
+
// starting from `error` covers both `error instanceof CapRouteError` and
|
|
116
|
+
// `error.cause` (and deeper nesting). No second call needed.
|
|
117
|
+
const capRouteError = extractCapRouteError(error);
|
|
118
|
+
if (capRouteError === null) {
|
|
119
|
+
return { ...shape, data: { ...shape.data } };
|
|
120
|
+
}
|
|
121
|
+
const extraData = {
|
|
122
|
+
capRouteReason: capRouteError.reason,
|
|
123
|
+
capRouteRejected: capRouteError.rejected,
|
|
124
|
+
...(capRouteError.nodeId !== undefined ? { capRouteNodeId: capRouteError.nodeId } : {}),
|
|
125
|
+
};
|
|
126
|
+
return {
|
|
127
|
+
...shape,
|
|
128
|
+
data: {
|
|
129
|
+
...shape.data,
|
|
130
|
+
...extraData,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractClientIp = extractClientIp;
|
|
4
|
+
exports.extractUserAgent = extractUserAgent;
|
|
5
|
+
exports.isRemoteClientIp = isRemoteClientIp;
|
|
6
|
+
/**
|
|
7
|
+
* Best-effort extraction of the originating client IP from a tRPC
|
|
8
|
+
* request. Order of preference:
|
|
9
|
+
* 1. `X-Forwarded-For` first hop (when behind a reverse proxy — the
|
|
10
|
+
* hub is typically fronted by Caddy/nginx/Cloudflare for remote
|
|
11
|
+
* access, so the socket peer is the proxy, not the viewer).
|
|
12
|
+
* 2. Fastify's `req.ip` (already proxy-aware when `trustProxy` is on).
|
|
13
|
+
* 3. The raw socket remote address.
|
|
14
|
+
*
|
|
15
|
+
* Returns `null` when no address can be determined (e.g. mesh-originated
|
|
16
|
+
* calls that carry no HTTP request) — the caller treats `null` as "not
|
|
17
|
+
* remote" so the LAN/direct path stays the safe default.
|
|
18
|
+
*/
|
|
19
|
+
function extractClientIp(req) {
|
|
20
|
+
if (!req)
|
|
21
|
+
return null;
|
|
22
|
+
// 1. X-Forwarded-For — comma-separated list, client is the FIRST entry.
|
|
23
|
+
const xff = req.headers['x-forwarded-for'];
|
|
24
|
+
const xffValue = Array.isArray(xff) ? xff[0] : xff;
|
|
25
|
+
if (typeof xffValue === 'string' && xffValue.length > 0) {
|
|
26
|
+
const first = xffValue.split(',')[0]?.trim();
|
|
27
|
+
if (first)
|
|
28
|
+
return normalizeIp(first);
|
|
29
|
+
}
|
|
30
|
+
// 2. Fastify's parsed `req.ip` (honours `trustProxy` config).
|
|
31
|
+
if ('ip' in req && typeof req.ip === 'string' && req.ip.length > 0) {
|
|
32
|
+
return normalizeIp(req.ip);
|
|
33
|
+
}
|
|
34
|
+
// 3. Raw socket peer (WS / IncomingMessage path).
|
|
35
|
+
const remote = req.socket?.remoteAddress;
|
|
36
|
+
if (typeof remote === 'string' && remote.length > 0) {
|
|
37
|
+
return normalizeIp(remote);
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Best-effort read of the originating client's `User-Agent` header. Both
|
|
43
|
+
* request shapes in the union (`FastifyRequest` and the raw WS-transport
|
|
44
|
+
* `IncomingMessage`) expose `.headers['user-agent']`. Returns `null` when
|
|
45
|
+
* absent (mesh-originated calls carry no HTTP request, and some clients
|
|
46
|
+
* omit the header). Used by the `webrtc-session` mount to tag a browser
|
|
47
|
+
* subscriber's broker attribution with the viewer's UA — the SERVER reads
|
|
48
|
+
* it from the request context; any client-supplied value is ignored.
|
|
49
|
+
*/
|
|
50
|
+
function extractUserAgent(req) {
|
|
51
|
+
if (!req)
|
|
52
|
+
return null;
|
|
53
|
+
const ua = req.headers['user-agent'];
|
|
54
|
+
const value = Array.isArray(ua) ? ua[0] : ua;
|
|
55
|
+
if (typeof value === 'string' && value.length > 0)
|
|
56
|
+
return value;
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Strip an IPv4-mapped IPv6 prefix (`::ffff:192.168.1.5` → `192.168.1.5`)
|
|
61
|
+
* and any zone id (`fe80::1%en0` → `fe80::1`) so the range checks below
|
|
62
|
+
* see a clean address.
|
|
63
|
+
*/
|
|
64
|
+
function normalizeIp(ip) {
|
|
65
|
+
let out = ip.trim();
|
|
66
|
+
if (out.startsWith('::ffff:'))
|
|
67
|
+
out = out.slice('::ffff:'.length);
|
|
68
|
+
const pct = out.indexOf('%');
|
|
69
|
+
if (pct !== -1)
|
|
70
|
+
out = out.slice(0, pct);
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* True when the address is NOT in a private / loopback / link-local /
|
|
75
|
+
* Tailscale range — i.e. an internet (remote) viewer. Covers IPv4
|
|
76
|
+
* (10/8, 172.16/12, 192.168/16, 127/8, 100.64/10 Tailscale CGNAT) and
|
|
77
|
+
* IPv6 (::1, fc00::/7 unique-local, fe80::/10 link-local — fd7a::/16
|
|
78
|
+
* Tailscale ULA is a subset of fc00::/7 and is therefore already
|
|
79
|
+
* covered).
|
|
80
|
+
*
|
|
81
|
+
* Tailscale clients (the 100.64.0.0/10 CGNAT overlay or the fd7a::/16
|
|
82
|
+
* ULA overlay) are deliberately classified LOCAL: over the Tailscale
|
|
83
|
+
* mesh BOTH peers sit on the 100.x / fd7a:: overlay and are mutually
|
|
84
|
+
* reachable, so the broker offers ALL candidates (host/srflx/relay)
|
|
85
|
+
* — including the hub's Tailscale host candidate — and a direct
|
|
86
|
+
* host↔host pair wins ICE with native (non-re-encoded) media. Forcing
|
|
87
|
+
* relay-only for Tailscale would push them onto the broken relay path.
|
|
88
|
+
*
|
|
89
|
+
* Unparseable or null addresses return `false` (treated as LAN — the
|
|
90
|
+
* safe default that preserves the existing direct path).
|
|
91
|
+
*/
|
|
92
|
+
function isRemoteClientIp(ip) {
|
|
93
|
+
if (!ip)
|
|
94
|
+
return false;
|
|
95
|
+
if (ip.includes(':'))
|
|
96
|
+
return !isPrivateIpv6(ip);
|
|
97
|
+
if (isIpv4(ip))
|
|
98
|
+
return !isPrivateIpv4(ip);
|
|
99
|
+
// Not a recognisable IP literal — be conservative, treat as LAN.
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
function isIpv4(ip) {
|
|
103
|
+
const parts = ip.split('.');
|
|
104
|
+
if (parts.length !== 4)
|
|
105
|
+
return false;
|
|
106
|
+
return parts.every((p) => {
|
|
107
|
+
if (!/^\d{1,3}$/.test(p))
|
|
108
|
+
return false;
|
|
109
|
+
const n = Number.parseInt(p, 10);
|
|
110
|
+
return n >= 0 && n <= 255;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function isPrivateIpv4(ip) {
|
|
114
|
+
const parts = ip.split('.').map((p) => Number.parseInt(p, 10));
|
|
115
|
+
const [a, b] = parts;
|
|
116
|
+
if (a === undefined || b === undefined)
|
|
117
|
+
return false;
|
|
118
|
+
if (a === 10)
|
|
119
|
+
return true; // 10.0.0.0/8
|
|
120
|
+
if (a === 127)
|
|
121
|
+
return true; // 127.0.0.0/8 loopback
|
|
122
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
123
|
+
return true; // 172.16.0.0/12
|
|
124
|
+
if (a === 192 && b === 168)
|
|
125
|
+
return true; // 192.168.0.0/16
|
|
126
|
+
if (a === 169 && b === 254)
|
|
127
|
+
return true; // 169.254.0.0/16 link-local
|
|
128
|
+
// 100.64.0.0/10 — Tailscale CGNAT overlay (100.64.0.0 – 100.127.255.255).
|
|
129
|
+
// Both Tailscale peers are mutually reachable on this overlay, so treat
|
|
130
|
+
// it as local (direct host↔host pair, no relay).
|
|
131
|
+
if (a === 100 && b >= 64 && b <= 127)
|
|
132
|
+
return true;
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
function isPrivateIpv6(ip) {
|
|
136
|
+
const lower = ip.toLowerCase();
|
|
137
|
+
if (lower === '::1')
|
|
138
|
+
return true; // loopback
|
|
139
|
+
if (lower === '::')
|
|
140
|
+
return true; // unspecified
|
|
141
|
+
if (lower.startsWith('fe80'))
|
|
142
|
+
return true; // fe80::/10 link-local
|
|
143
|
+
// fc00::/7 unique-local — covers fc.. and fd..
|
|
144
|
+
if (lower.startsWith('fc') || lower.startsWith('fd'))
|
|
145
|
+
return true;
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildCoreCapService = buildCoreCapService;
|
|
4
|
+
const kernel_1 = require("@camstack/kernel");
|
|
5
|
+
const trpc_middleware_js_1 = require("./trpc.middleware.js");
|
|
6
|
+
const trpc_context_js_1 = require("./trpc.context.js");
|
|
7
|
+
/**
|
|
8
|
+
* appRouter namespaces that back the CORE API surface and must be
|
|
9
|
+
* reachable cross-process. This is the core-router list from
|
|
10
|
+
* `trpc.router.ts` (`buildCapabilityRouters`) minus the deliberate
|
|
11
|
+
* exclusions below.
|
|
12
|
+
*
|
|
13
|
+
* Excluded on purpose:
|
|
14
|
+
* - `auth` — issuing service / scoped tokens over the trusted mesh
|
|
15
|
+
* would let any forked addon mint admin credentials. Addons must
|
|
16
|
+
* not perform authentication operations; this stays hub-local.
|
|
17
|
+
* - `live`, `systemEvents` — listed in `NEVER_BRIDGED_CAPS`
|
|
18
|
+
* (`trpc-links.ts`). They are hub-only push streams, not
|
|
19
|
+
* request/reply, and the worker side fast-fails on them by design.
|
|
20
|
+
*/
|
|
21
|
+
const CORE_NAMESPACES = new Set([
|
|
22
|
+
// Service-backed cap routers (no addon provider).
|
|
23
|
+
'system',
|
|
24
|
+
'toast',
|
|
25
|
+
'integrations',
|
|
26
|
+
'nodes',
|
|
27
|
+
'addons',
|
|
28
|
+
// Hand-written single-impl core routers.
|
|
29
|
+
'capabilities',
|
|
30
|
+
'notifications',
|
|
31
|
+
'logs',
|
|
32
|
+
'hwaccel',
|
|
33
|
+
'streamProbe',
|
|
34
|
+
'settingsBackend',
|
|
35
|
+
'eventBusProxy',
|
|
36
|
+
'repl',
|
|
37
|
+
'addonSettingsRaw',
|
|
38
|
+
]);
|
|
39
|
+
/**
|
|
40
|
+
* camelCase → kebab-case. Mirrors `toKebab` in `trpc-links.ts` so the
|
|
41
|
+
* action name matches what `brokerTransportLink` derives from `op.path`.
|
|
42
|
+
*/
|
|
43
|
+
function toKebab(name) {
|
|
44
|
+
return name.replace(/[A-Z]/g, (m, i) => (i > 0 ? '-' : '') + m.toLowerCase());
|
|
45
|
+
}
|
|
46
|
+
function isProcedureNode(value) {
|
|
47
|
+
// A built tRPC procedure is a callable object — `_def.procedures`
|
|
48
|
+
// stores the procedure function directly, not a wrapper object.
|
|
49
|
+
if (value === null || (typeof value !== 'object' && typeof value !== 'function'))
|
|
50
|
+
return false;
|
|
51
|
+
const def = value._def;
|
|
52
|
+
return (def !== null && typeof def === 'object' && def.procedure === true);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Recursively flatten a tRPC router record to dotted procedure paths.
|
|
56
|
+
* Robust to both layouts tRPC v11 may use for `_def.procedures`: a
|
|
57
|
+
* nested record of sub-routers, or a flat record already keyed by
|
|
58
|
+
* dotted path (a flat key simply yields its key verbatim).
|
|
59
|
+
*/
|
|
60
|
+
function collectProcedures(record, prefix, out) {
|
|
61
|
+
for (const [key, value] of Object.entries(record)) {
|
|
62
|
+
const path = prefix.length > 0 ? `${prefix}.${key}` : key;
|
|
63
|
+
if (isProcedureNode(value)) {
|
|
64
|
+
const type = value._def.type;
|
|
65
|
+
out.push({ path, type: typeof type === 'string' ? type : 'query' });
|
|
66
|
+
}
|
|
67
|
+
else if (value !== null && typeof value === 'object') {
|
|
68
|
+
collectProcedures(value, path, out);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Navigate the decorated caller record (a recursive proxy) to the
|
|
74
|
+
* procedure function at `path`. Every node on the proxy is callable,
|
|
75
|
+
* so navigation uses `Reflect.get` across both objects and functions.
|
|
76
|
+
*/
|
|
77
|
+
function resolveInvoker(caller, path) {
|
|
78
|
+
let node = caller;
|
|
79
|
+
for (const segment of path.split('.')) {
|
|
80
|
+
if (node === null || (typeof node !== 'object' && typeof node !== 'function'))
|
|
81
|
+
return null;
|
|
82
|
+
// Documented boundary: `node` is an object or function past the
|
|
83
|
+
// guard above; `Reflect.get` is typed for `object` targets.
|
|
84
|
+
node = Reflect.get(node, segment);
|
|
85
|
+
}
|
|
86
|
+
return typeof node === 'function' ? node : null;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Build the `$core-caps` Moleculer service schema from the hub
|
|
90
|
+
* appRouter. Query + mutation procedures in {@link CORE_NAMESPACES} are
|
|
91
|
+
* exposed; subscriptions are skipped (the broker transport is
|
|
92
|
+
* request/reply only).
|
|
93
|
+
*/
|
|
94
|
+
function buildCoreCapService(appRouter) {
|
|
95
|
+
const meshCaller = (0, trpc_middleware_js_1.createCallerFactory)(appRouter)((0, trpc_context_js_1.createMeshTrpcContext)());
|
|
96
|
+
const discovered = [];
|
|
97
|
+
collectProcedures(appRouter._def.procedures, '', discovered);
|
|
98
|
+
const actions = [];
|
|
99
|
+
for (const { path, type } of discovered) {
|
|
100
|
+
const dot = path.indexOf('.');
|
|
101
|
+
if (dot < 0)
|
|
102
|
+
continue;
|
|
103
|
+
const namespace = path.slice(0, dot);
|
|
104
|
+
if (!CORE_NAMESPACES.has(namespace))
|
|
105
|
+
continue;
|
|
106
|
+
if (type === 'subscription')
|
|
107
|
+
continue;
|
|
108
|
+
const invoke = resolveInvoker(meshCaller, path);
|
|
109
|
+
if (invoke === null)
|
|
110
|
+
continue;
|
|
111
|
+
const method = path.slice(dot + 1);
|
|
112
|
+
actions.push({ actionName: `${toKebab(namespace)}.${method}`, invoke });
|
|
113
|
+
}
|
|
114
|
+
return (0, kernel_1.createCoreCapService)({ actions });
|
|
115
|
+
}
|