@camstack/server 0.1.6 → 0.1.7
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/package.json +1 -1
- package/src/__tests__/addon-upload.spec.ts +58 -0
- package/src/__tests__/bulk-update-coordinator.spec.ts +286 -0
- package/src/__tests__/cap-ownership-authority.spec.ts +400 -0
- package/src/__tests__/cap-providers-bulk-update.spec.ts +388 -0
- package/src/__tests__/cap-route-adapter.spec.ts +289 -0
- package/src/__tests__/cap-routers/cap-route-error-formatter.spec.ts +123 -0
- package/src/__tests__/cap-routers/capabilities-node.spec.ts +55 -0
- package/src/__tests__/dev-bootstrap-shm-ring.spec.ts +30 -0
- package/src/__tests__/device-settings-contribution-dispatch.spec.ts +249 -0
- package/src/__tests__/framework-installer-defer-restart.spec.ts +165 -0
- package/src/__tests__/moleculer/uds-readiness.spec.ts +143 -0
- package/src/__tests__/moleculer/uds-topology.spec.ts +390 -0
- package/src/__tests__/moleculer/uds-unowned-call.spec.ts +123 -0
- package/src/__tests__/moleculer-register-node-idempotency.spec.ts +39 -4
- package/src/__tests__/native-cap-route.spec.ts +404 -0
- package/src/__tests__/oauth2-account-linking.spec.ts +85 -0
- package/src/__tests__/uds-addon-call-wiring.spec.ts +237 -0
- package/src/__tests__/uds-log-ingest.spec.ts +183 -0
- package/src/api/addon-upload.ts +27 -1
- package/src/api/capabilities.router.ts +1 -1
- package/src/api/core/bulk-update-coordinator.ts +302 -0
- package/src/api/core/cap-providers.ts +59 -6
- package/src/api/core/capabilities.router.ts +26 -3
- package/src/api/oauth2/oauth2-routes.ts +5 -1
- package/src/api/trpc/__tests__/client-ip.spec.ts +120 -0
- package/src/api/trpc/cap-route-error-formatter.ts +163 -0
- package/src/api/trpc/client-ip.ts +130 -0
- package/src/api/trpc/generated-cap-mounts.ts +19 -1
- package/src/api/trpc/generated-cap-routers.ts +180 -1
- package/src/api/trpc/trpc.middleware.ts +5 -1
- package/src/api/trpc/trpc.router.ts +45 -0
- package/src/core/addon/addon-call-gateway.ts +157 -0
- package/src/core/addon/addon-package.service.ts +9 -0
- package/src/core/addon/addon-registry.service.ts +364 -105
- package/src/core/addon/addon-settings-provider.ts +40 -116
- package/src/core/capability/capability.service.ts +9 -0
- package/src/core/moleculer/cap-call-fn.spec.ts +166 -0
- package/src/core/moleculer/cap-call-fn.ts +103 -0
- package/src/core/moleculer/cap-route-authority.ts +182 -0
- package/src/core/moleculer/moleculer.service.ts +380 -36
- package/src/main.ts +45 -12
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tRPC error formatter that serializes CapRouteError diagnostic fields
|
|
3
|
+
* across the server→client boundary.
|
|
4
|
+
*
|
|
5
|
+
* tRPC only carries `error.message` by default. This formatter augments
|
|
6
|
+
* the default shape's `data` block with typed CapRouteError fields so the
|
|
7
|
+
* admin-UI can read `capRouteReason` instead of substring-matching message text.
|
|
8
|
+
*
|
|
9
|
+
* Fields added (all optional — absent when the error is not a CapRouteError):
|
|
10
|
+
* - `capRouteReason` — 'no-provider' | 'node-offline' | 'cap-unknown' | 'transport-failed'
|
|
11
|
+
* - `capRouteRejected` — array of `{ kind: string; why: string }` route-rejection descriptors
|
|
12
|
+
* - `capRouteNodeId` — the target node id, when known
|
|
13
|
+
*
|
|
14
|
+
* The formatter is EXPORTED for unit testing (no side-effects, pure function).
|
|
15
|
+
*/
|
|
16
|
+
import { CapRouteError } from '@camstack/kernel'
|
|
17
|
+
import type { RejectedRoute } from '@camstack/kernel'
|
|
18
|
+
import type { TRPCError } from '@trpc/server'
|
|
19
|
+
import type { DefaultErrorShape } from '@trpc/server/unstable-core-do-not-import'
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Types
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
/** The augmented data block we attach when a CapRouteError is present. */
|
|
26
|
+
export interface CapRouteErrorData {
|
|
27
|
+
readonly capRouteReason: string
|
|
28
|
+
readonly capRouteRejected: readonly RejectedRoute[]
|
|
29
|
+
readonly capRouteNodeId?: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface AugmentedErrorShape extends DefaultErrorShape {
|
|
33
|
+
readonly data: DefaultErrorShape['data'] & Partial<CapRouteErrorData>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Type guards
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
/** Known CapRouteError reason values — used as a runtime safety rail. */
|
|
41
|
+
const KNOWN_REASONS = new Set<string>(['no-provider', 'node-offline', 'cap-unknown', 'transport-failed'])
|
|
42
|
+
|
|
43
|
+
/** Narrows a plain string to the `CapRouteError['reason']` union. */
|
|
44
|
+
function isCapRouteReason(r: string): r is CapRouteError['reason'] {
|
|
45
|
+
return KNOWN_REASONS.has(r)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Narrows an `unknown` value to `RejectedRoute` by checking structural shape. */
|
|
49
|
+
function isRejectedRoute(r: unknown): r is RejectedRoute {
|
|
50
|
+
if (typeof r !== 'object' || r === null) return false
|
|
51
|
+
const kind: unknown = Reflect.get(r, 'kind')
|
|
52
|
+
const why: unknown = Reflect.get(r, 'why')
|
|
53
|
+
return typeof kind === 'string' && typeof why === 'string'
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// CapRouteError extraction helpers
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Walks the `.cause` chain of an error to find a CapRouteError.
|
|
62
|
+
* Returns the first one found, or null.
|
|
63
|
+
*
|
|
64
|
+
* Detection is dual-mode:
|
|
65
|
+
* 1. `instanceof CapRouteError` — works when the same module is loaded.
|
|
66
|
+
* 2. Duck-type: `name === 'CapRouteError'` + `typeof reason === 'string'`
|
|
67
|
+
* — robust against module-boundary issues (self-contained addons).
|
|
68
|
+
*/
|
|
69
|
+
function extractCapRouteError(err: unknown): CapRouteError | null {
|
|
70
|
+
let current: unknown = err
|
|
71
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
72
|
+
if (current === null || current === undefined) return null
|
|
73
|
+
|
|
74
|
+
if (current instanceof CapRouteError) {
|
|
75
|
+
return current
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Duck-type fallback: err.name + err.reason field present
|
|
79
|
+
if (typeof current === 'object' && Reflect.get(current, 'name') === 'CapRouteError') {
|
|
80
|
+
const rawReason: unknown = Reflect.get(current, 'reason')
|
|
81
|
+
if (typeof rawReason === 'string') {
|
|
82
|
+
// Runtime safety: reject unrecognised reason strings so the formatter
|
|
83
|
+
// only promotes values it knows are valid CapRouteError reasons.
|
|
84
|
+
if (!isCapRouteReason(rawReason)) {
|
|
85
|
+
// Unrecognised reason — treat as a non-CapRouteError and keep walking
|
|
86
|
+
const cause: unknown = Reflect.get(current, 'cause')
|
|
87
|
+
if (cause === current) return null
|
|
88
|
+
current = cause
|
|
89
|
+
continue
|
|
90
|
+
}
|
|
91
|
+
const reason: CapRouteError['reason'] = rawReason
|
|
92
|
+
|
|
93
|
+
const rawRejected: unknown = Reflect.get(current, 'rejected')
|
|
94
|
+
const rejected: readonly RejectedRoute[] = Array.isArray(rawRejected)
|
|
95
|
+
? rawRejected.filter(isRejectedRoute)
|
|
96
|
+
: []
|
|
97
|
+
|
|
98
|
+
const nodeId: unknown = Reflect.get(current, 'nodeId')
|
|
99
|
+
const message: unknown = Reflect.get(current, 'message')
|
|
100
|
+
const rawCapName: unknown = Reflect.get(current, 'capName')
|
|
101
|
+
const capName: string = typeof rawCapName === 'string' ? rawCapName : '(unknown)'
|
|
102
|
+
|
|
103
|
+
// Build a minimal object with the same shape — enough for the formatter.
|
|
104
|
+
const synthetic = Object.assign(new CapRouteError(capName, undefined, {
|
|
105
|
+
reason,
|
|
106
|
+
rejected,
|
|
107
|
+
...(typeof nodeId === 'string' ? { nodeId } : {}),
|
|
108
|
+
}), {
|
|
109
|
+
// Override message from the original if available
|
|
110
|
+
message: typeof message === 'string' ? message : '(duck-typed CapRouteError)',
|
|
111
|
+
})
|
|
112
|
+
return synthetic
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Walk the cause chain
|
|
117
|
+
if (typeof current !== 'object') return null
|
|
118
|
+
const cause: unknown = Reflect.get(current, 'cause')
|
|
119
|
+
if (cause === current) return null // Guard against circular refs
|
|
120
|
+
current = cause
|
|
121
|
+
}
|
|
122
|
+
return null
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Formatter — exported for unit tests
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
|
|
129
|
+
export interface FormatTrpcErrorOpts {
|
|
130
|
+
readonly error: TRPCError
|
|
131
|
+
readonly shape: DefaultErrorShape
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Augments the default tRPC error shape with CapRouteError diagnostic fields
|
|
136
|
+
* when the thrown error (or any error in its `.cause` chain) is a CapRouteError.
|
|
137
|
+
* Returns the shape unchanged for all other errors.
|
|
138
|
+
*/
|
|
139
|
+
export function formatTrpcError(opts: FormatTrpcErrorOpts): AugmentedErrorShape {
|
|
140
|
+
const { error, shape } = opts
|
|
141
|
+
|
|
142
|
+
// extractCapRouteError already walks the full .cause chain, so a single call
|
|
143
|
+
// starting from `error` covers both `error instanceof CapRouteError` and
|
|
144
|
+
// `error.cause` (and deeper nesting). No second call needed.
|
|
145
|
+
const capRouteError = extractCapRouteError(error)
|
|
146
|
+
if (capRouteError === null) {
|
|
147
|
+
return { ...shape, data: { ...shape.data } }
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const extraData: CapRouteErrorData = {
|
|
151
|
+
capRouteReason: capRouteError.reason,
|
|
152
|
+
capRouteRejected: capRouteError.rejected,
|
|
153
|
+
...(capRouteError.nodeId !== undefined ? { capRouteNodeId: capRouteError.nodeId } : {}),
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
...shape,
|
|
158
|
+
data: {
|
|
159
|
+
...shape.data,
|
|
160
|
+
...extraData,
|
|
161
|
+
},
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-IP extraction + LAN/remote classification for the tRPC layer.
|
|
3
|
+
*
|
|
4
|
+
* Used by the `webrtcSession.createSession` override to decide whether a
|
|
5
|
+
* live-view session should force TURN-relay-only ICE: a viewer behind
|
|
6
|
+
* CGNAT/4G (a non-LAN source IP) only ever offers a relay candidate, so
|
|
7
|
+
* the broker must offer a genuinely relay-only SDP (the patched werift
|
|
8
|
+
* emits one under `iceTransportPolicy:'relay'`) to get a clean
|
|
9
|
+
* relay↔relay media path. LAN viewers (private/loopback source IP) keep
|
|
10
|
+
* the low-latency direct host/srflx path. The SERVER computes this — the
|
|
11
|
+
* client never sends a relay-only flag.
|
|
12
|
+
*/
|
|
13
|
+
import type { FastifyRequest } from 'fastify'
|
|
14
|
+
import type { IncomingMessage } from 'node:http'
|
|
15
|
+
|
|
16
|
+
export type ClientRequest = FastifyRequest | IncomingMessage
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Best-effort extraction of the originating client IP from a tRPC
|
|
20
|
+
* request. Order of preference:
|
|
21
|
+
* 1. `X-Forwarded-For` first hop (when behind a reverse proxy — the
|
|
22
|
+
* hub is typically fronted by Caddy/nginx/Cloudflare for remote
|
|
23
|
+
* access, so the socket peer is the proxy, not the viewer).
|
|
24
|
+
* 2. Fastify's `req.ip` (already proxy-aware when `trustProxy` is on).
|
|
25
|
+
* 3. The raw socket remote address.
|
|
26
|
+
*
|
|
27
|
+
* Returns `null` when no address can be determined (e.g. mesh-originated
|
|
28
|
+
* calls that carry no HTTP request) — the caller treats `null` as "not
|
|
29
|
+
* remote" so the LAN/direct path stays the safe default.
|
|
30
|
+
*/
|
|
31
|
+
export function extractClientIp(req: ClientRequest | undefined): string | null {
|
|
32
|
+
if (!req) return null
|
|
33
|
+
|
|
34
|
+
// 1. X-Forwarded-For — comma-separated list, client is the FIRST entry.
|
|
35
|
+
const xff = req.headers['x-forwarded-for']
|
|
36
|
+
const xffValue = Array.isArray(xff) ? xff[0] : xff
|
|
37
|
+
if (typeof xffValue === 'string' && xffValue.length > 0) {
|
|
38
|
+
const first = xffValue.split(',')[0]?.trim()
|
|
39
|
+
if (first) return normalizeIp(first)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 2. Fastify's parsed `req.ip` (honours `trustProxy` config).
|
|
43
|
+
if ('ip' in req && typeof req.ip === 'string' && req.ip.length > 0) {
|
|
44
|
+
return normalizeIp(req.ip)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 3. Raw socket peer (WS / IncomingMessage path).
|
|
48
|
+
const remote = req.socket?.remoteAddress
|
|
49
|
+
if (typeof remote === 'string' && remote.length > 0) {
|
|
50
|
+
return normalizeIp(remote)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Strip an IPv4-mapped IPv6 prefix (`::ffff:192.168.1.5` → `192.168.1.5`)
|
|
58
|
+
* and any zone id (`fe80::1%en0` → `fe80::1`) so the range checks below
|
|
59
|
+
* see a clean address.
|
|
60
|
+
*/
|
|
61
|
+
function normalizeIp(ip: string): string {
|
|
62
|
+
let out = ip.trim()
|
|
63
|
+
if (out.startsWith('::ffff:')) out = out.slice('::ffff:'.length)
|
|
64
|
+
const pct = out.indexOf('%')
|
|
65
|
+
if (pct !== -1) out = out.slice(0, pct)
|
|
66
|
+
return out
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* True when the address is NOT in a private / loopback / link-local /
|
|
71
|
+
* Tailscale range — i.e. an internet (remote) viewer. Covers IPv4
|
|
72
|
+
* (10/8, 172.16/12, 192.168/16, 127/8, 100.64/10 Tailscale CGNAT) and
|
|
73
|
+
* IPv6 (::1, fc00::/7 unique-local, fe80::/10 link-local — fd7a::/16
|
|
74
|
+
* Tailscale ULA is a subset of fc00::/7 and is therefore already
|
|
75
|
+
* covered).
|
|
76
|
+
*
|
|
77
|
+
* Tailscale clients (the 100.64.0.0/10 CGNAT overlay or the fd7a::/16
|
|
78
|
+
* ULA overlay) are deliberately classified LOCAL: over the Tailscale
|
|
79
|
+
* mesh BOTH peers sit on the 100.x / fd7a:: overlay and are mutually
|
|
80
|
+
* reachable, so the broker offers ALL candidates (host/srflx/relay)
|
|
81
|
+
* — including the hub's Tailscale host candidate — and a direct
|
|
82
|
+
* host↔host pair wins ICE with native (non-re-encoded) media. Forcing
|
|
83
|
+
* relay-only for Tailscale would push them onto the broken relay path.
|
|
84
|
+
*
|
|
85
|
+
* Unparseable or null addresses return `false` (treated as LAN — the
|
|
86
|
+
* safe default that preserves the existing direct path).
|
|
87
|
+
*/
|
|
88
|
+
export function isRemoteClientIp(ip: string | null): boolean {
|
|
89
|
+
if (!ip) return false
|
|
90
|
+
if (ip.includes(':')) return !isPrivateIpv6(ip)
|
|
91
|
+
if (isIpv4(ip)) return !isPrivateIpv4(ip)
|
|
92
|
+
// Not a recognisable IP literal — be conservative, treat as LAN.
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function isIpv4(ip: string): boolean {
|
|
97
|
+
const parts = ip.split('.')
|
|
98
|
+
if (parts.length !== 4) return false
|
|
99
|
+
return parts.every((p) => {
|
|
100
|
+
if (!/^\d{1,3}$/.test(p)) return false
|
|
101
|
+
const n = Number.parseInt(p, 10)
|
|
102
|
+
return n >= 0 && n <= 255
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isPrivateIpv4(ip: string): boolean {
|
|
107
|
+
const parts = ip.split('.').map((p) => Number.parseInt(p, 10))
|
|
108
|
+
const [a, b] = parts
|
|
109
|
+
if (a === undefined || b === undefined) return false
|
|
110
|
+
if (a === 10) return true // 10.0.0.0/8
|
|
111
|
+
if (a === 127) return true // 127.0.0.0/8 loopback
|
|
112
|
+
if (a === 172 && b >= 16 && b <= 31) return true // 172.16.0.0/12
|
|
113
|
+
if (a === 192 && b === 168) return true // 192.168.0.0/16
|
|
114
|
+
if (a === 169 && b === 254) return true // 169.254.0.0/16 link-local
|
|
115
|
+
// 100.64.0.0/10 — Tailscale CGNAT overlay (100.64.0.0 – 100.127.255.255).
|
|
116
|
+
// Both Tailscale peers are mutually reachable on this overlay, so treat
|
|
117
|
+
// it as local (direct host↔host pair, no relay).
|
|
118
|
+
if (a === 100 && b >= 64 && b <= 127) return true
|
|
119
|
+
return false
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function isPrivateIpv6(ip: string): boolean {
|
|
123
|
+
const lower = ip.toLowerCase()
|
|
124
|
+
if (lower === '::1') return true // loopback
|
|
125
|
+
if (lower === '::') return true // unspecified
|
|
126
|
+
if (lower.startsWith('fe80')) return true // fe80::/10 link-local
|
|
127
|
+
// fc00::/7 unique-local — covers fc.. and fd..
|
|
128
|
+
if (lower.startsWith('fc') || lower.startsWith('fd')) return true
|
|
129
|
+
return false
|
|
130
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// AUTO-GENERATED by scripts/generate-cap-mounts.ts — DO NOT EDIT
|
|
2
2
|
// Re-run: npx tsx scripts/generate-cap-mounts.ts
|
|
3
3
|
//
|
|
4
|
-
// Mounted:
|
|
4
|
+
// Mounted: 81 Skipped (legacy): 6
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Single auto-mount entrypoint for every codegen'd cap router.
|
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
batteryCapability,
|
|
49
49
|
brightnessCapability,
|
|
50
50
|
cameraCredentialsCapability,
|
|
51
|
+
cameraPipelineConfigCapability,
|
|
51
52
|
cameraStreamsCapability,
|
|
52
53
|
decoderCapability,
|
|
53
54
|
detectionPipelineCapability,
|
|
@@ -84,6 +85,7 @@ import {
|
|
|
84
85
|
pipelineOrchestratorCapability,
|
|
85
86
|
pipelineRunnerCapability,
|
|
86
87
|
platformProbeCapability,
|
|
88
|
+
privacyMaskCapability,
|
|
87
89
|
ptzAutotrackCapability,
|
|
88
90
|
ptzCapability,
|
|
89
91
|
rebootCapability,
|
|
@@ -97,6 +99,7 @@ import {
|
|
|
97
99
|
storageCapability,
|
|
98
100
|
storageProviderCapability,
|
|
99
101
|
streamBrokerCapability,
|
|
102
|
+
streamCatalogCapability,
|
|
100
103
|
streamParamsCapability,
|
|
101
104
|
switchCapability,
|
|
102
105
|
systemCapability,
|
|
@@ -130,6 +133,7 @@ import {
|
|
|
130
133
|
createCapRouter_battery,
|
|
131
134
|
createCapRouter_brightness,
|
|
132
135
|
createCapRouter_cameraCredentials,
|
|
136
|
+
createCapRouter_cameraPipelineConfig,
|
|
133
137
|
createCapRouter_cameraStreams,
|
|
134
138
|
createCapRouter_decoder,
|
|
135
139
|
createCapRouter_detectionPipeline,
|
|
@@ -166,6 +170,7 @@ import {
|
|
|
166
170
|
createCapRouter_pipelineOrchestrator,
|
|
167
171
|
createCapRouter_pipelineRunner,
|
|
168
172
|
createCapRouter_platformProbe,
|
|
173
|
+
createCapRouter_privacyMask,
|
|
169
174
|
createCapRouter_ptz,
|
|
170
175
|
createCapRouter_ptzAutotrack,
|
|
171
176
|
createCapRouter_reboot,
|
|
@@ -179,6 +184,7 @@ import {
|
|
|
179
184
|
createCapRouter_storage,
|
|
180
185
|
createCapRouter_storageProvider,
|
|
181
186
|
createCapRouter_streamBroker,
|
|
187
|
+
createCapRouter_streamCatalog,
|
|
182
188
|
createCapRouter_streamParams,
|
|
183
189
|
createCapRouter_switch,
|
|
184
190
|
createCapRouter_system,
|
|
@@ -328,6 +334,10 @@ export function mountAllCaps(services: MountAllCapsServices) {
|
|
|
328
334
|
(_ctx) => requireDeviceScoped(reg, 'camera-credentials') as InferProvider<typeof cameraCredentialsCapability> | null,
|
|
329
335
|
remoteCapProxy,
|
|
330
336
|
),
|
|
337
|
+
cameraPipelineConfig: createCapRouter_cameraPipelineConfig(
|
|
338
|
+
(_ctx) => reg?.getSingleton<InferProvider<typeof cameraPipelineConfigCapability>>('camera-pipeline-config') ?? null,
|
|
339
|
+
remoteCapProxy,
|
|
340
|
+
),
|
|
331
341
|
cameraStreams: createCapRouter_cameraStreams(
|
|
332
342
|
(_ctx) => reg?.getSingleton<InferProvider<typeof cameraStreamsCapability>>('camera-streams') ?? null,
|
|
333
343
|
remoteCapProxy,
|
|
@@ -554,6 +564,10 @@ export function mountAllCaps(services: MountAllCapsServices) {
|
|
|
554
564
|
(_ctx) => reg?.getSingleton<InferProvider<typeof platformProbeCapability>>('platform-probe') ?? null,
|
|
555
565
|
remoteCapProxy,
|
|
556
566
|
),
|
|
567
|
+
privacyMask: createCapRouter_privacyMask(
|
|
568
|
+
(_ctx) => requireDeviceScoped(reg, 'privacy-mask') as InferProvider<typeof privacyMaskCapability> | null,
|
|
569
|
+
remoteCapProxy,
|
|
570
|
+
),
|
|
557
571
|
ptz: createCapRouter_ptz(
|
|
558
572
|
(_ctx) => requireDeviceScoped(reg, 'ptz') as InferProvider<typeof ptzCapability> | null,
|
|
559
573
|
remoteCapProxy,
|
|
@@ -633,6 +647,10 @@ export function mountAllCaps(services: MountAllCapsServices) {
|
|
|
633
647
|
(_ctx) => reg?.getSingleton<InferProvider<typeof streamBrokerCapability>>('stream-broker') ?? null,
|
|
634
648
|
remoteCapProxy,
|
|
635
649
|
),
|
|
650
|
+
streamCatalog: createCapRouter_streamCatalog(
|
|
651
|
+
(_ctx) => requireDeviceScoped(reg, 'stream-catalog') as InferProvider<typeof streamCatalogCapability> | null,
|
|
652
|
+
remoteCapProxy,
|
|
653
|
+
),
|
|
636
654
|
streamParams: createCapRouter_streamParams(
|
|
637
655
|
(_ctx) => requireDeviceScoped(reg, 'stream-params') as InferProvider<typeof streamParamsCapability> | null,
|
|
638
656
|
remoteCapProxy,
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
// AUTO-GENERATED by scripts/generate-cap-routers.ts — DO NOT EDIT
|
|
2
2
|
// Re-run: npx tsx scripts/generate-cap-routers.ts
|
|
3
3
|
//
|
|
4
|
-
// Capabilities:
|
|
4
|
+
// Capabilities: 87
|
|
5
|
+
/* eslint-disable */
|
|
5
6
|
|
|
6
7
|
import { TRPCError } from '@trpc/server'
|
|
8
|
+
import { CapRouteError } from '@camstack/kernel'
|
|
7
9
|
import { z } from 'zod'
|
|
8
10
|
import { adminProcedure, protectedProcedure, iterableSubscription, trpcRouter } from './trpc.middleware.js'
|
|
9
11
|
import type { InferProvider } from '@camstack/types'
|
|
@@ -31,6 +33,7 @@ import { backupCapability } from '@camstack/types'
|
|
|
31
33
|
import { batteryCapability } from '@camstack/types'
|
|
32
34
|
import { brightnessCapability } from '@camstack/types'
|
|
33
35
|
import { cameraCredentialsCapability } from '@camstack/types'
|
|
36
|
+
import { cameraPipelineConfigCapability } from '@camstack/types'
|
|
34
37
|
import { cameraStreamsCapability } from '@camstack/types'
|
|
35
38
|
import { decoderCapability } from '@camstack/types'
|
|
36
39
|
import { detectionPipelineCapability } from '@camstack/types'
|
|
@@ -68,6 +71,7 @@ import { pipelineExecutorCapability } from '@camstack/types'
|
|
|
68
71
|
import { pipelineOrchestratorCapability } from '@camstack/types'
|
|
69
72
|
import { pipelineRunnerCapability } from '@camstack/types'
|
|
70
73
|
import { platformProbeCapability } from '@camstack/types'
|
|
74
|
+
import { privacyMaskCapability } from '@camstack/types'
|
|
71
75
|
import { ptzCapability } from '@camstack/types'
|
|
72
76
|
import { ptzAutotrackCapability } from '@camstack/types'
|
|
73
77
|
import { rebootCapability } from '@camstack/types'
|
|
@@ -82,6 +86,7 @@ import { ssoBridgeCapability } from '@camstack/types'
|
|
|
82
86
|
import { storageCapability } from '@camstack/types'
|
|
83
87
|
import { storageProviderCapability } from '@camstack/types'
|
|
84
88
|
import { streamBrokerCapability } from '@camstack/types'
|
|
89
|
+
import { streamCatalogCapability } from '@camstack/types'
|
|
85
90
|
import { streamParamsCapability } from '@camstack/types'
|
|
86
91
|
import { streamingEngineCapability } from '@camstack/types'
|
|
87
92
|
import { switchCapability } from '@camstack/types'
|
|
@@ -104,6 +109,10 @@ export function requireCapProvider<T>(name: string, getProvider: () => T | null)
|
|
|
104
109
|
throw new TRPCError({
|
|
105
110
|
code: 'PRECONDITION_FAILED',
|
|
106
111
|
message: `Capability "${name}" provider not available`,
|
|
112
|
+
cause: new CapRouteError(name, undefined, {
|
|
113
|
+
reason: 'no-provider',
|
|
114
|
+
rejected: [{ kind: 'hub-in-process', why: 'no provider bound for this cap' }],
|
|
115
|
+
}),
|
|
107
116
|
})
|
|
108
117
|
}
|
|
109
118
|
return p
|
|
@@ -134,6 +143,10 @@ function resolveProvider<T>(
|
|
|
134
143
|
throw new TRPCError({
|
|
135
144
|
code: 'PRECONDITION_FAILED',
|
|
136
145
|
message: `Capability "${capName}" provider not available`,
|
|
146
|
+
cause: new CapRouteError(capName, undefined, {
|
|
147
|
+
reason: 'no-provider',
|
|
148
|
+
rejected: [{ kind: 'hub-in-process', why: 'no provider bound for this cap/device' }],
|
|
149
|
+
}),
|
|
137
150
|
})
|
|
138
151
|
}
|
|
139
152
|
|
|
@@ -148,6 +161,11 @@ function resolveProvider<T>(
|
|
|
148
161
|
throw new TRPCError({
|
|
149
162
|
code: 'PRECONDITION_FAILED',
|
|
150
163
|
message: `Capability "${capName}" not available on node "${nodeId}"`,
|
|
164
|
+
cause: new CapRouteError(capName, undefined, {
|
|
165
|
+
reason: 'no-provider',
|
|
166
|
+
nodeId,
|
|
167
|
+
rejected: [{ kind: 'remote-moleculer', why: `cap not available on node "${nodeId}"` }],
|
|
168
|
+
}),
|
|
151
169
|
})
|
|
152
170
|
}
|
|
153
171
|
return proxy
|
|
@@ -493,6 +511,38 @@ export function createCapRouter_addons(
|
|
|
493
511
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
494
512
|
return p.updateFrameworkPackage(input as any)
|
|
495
513
|
}),
|
|
514
|
+
startBulkUpdate: adminProcedure
|
|
515
|
+
.input(addonsCapability.methods.startBulkUpdate.input.loose())
|
|
516
|
+
.output(addonsCapability.methods.startBulkUpdate.output)
|
|
517
|
+
.mutation(async ({ input, ctx }) => {
|
|
518
|
+
const p = requireCapProvider('addons', () => getProvider(ctx))
|
|
519
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
520
|
+
return p.startBulkUpdate(input as any)
|
|
521
|
+
}),
|
|
522
|
+
getBulkUpdateState: adminProcedure
|
|
523
|
+
.input(addonsCapability.methods.getBulkUpdateState.input.loose())
|
|
524
|
+
.output(addonsCapability.methods.getBulkUpdateState.output)
|
|
525
|
+
.query(async ({ input, ctx }) => {
|
|
526
|
+
const p = requireCapProvider('addons', () => getProvider(ctx))
|
|
527
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
528
|
+
return p.getBulkUpdateState(input as any)
|
|
529
|
+
}),
|
|
530
|
+
cancelBulkUpdate: adminProcedure
|
|
531
|
+
.input(addonsCapability.methods.cancelBulkUpdate.input.loose())
|
|
532
|
+
.output(addonsCapability.methods.cancelBulkUpdate.output)
|
|
533
|
+
.mutation(async ({ input, ctx }) => {
|
|
534
|
+
const p = requireCapProvider('addons', () => getProvider(ctx))
|
|
535
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
536
|
+
return p.cancelBulkUpdate(input as any)
|
|
537
|
+
}),
|
|
538
|
+
listActiveBulkUpdates: adminProcedure
|
|
539
|
+
.input(addonsCapability.methods.listActiveBulkUpdates.input.loose())
|
|
540
|
+
.output(addonsCapability.methods.listActiveBulkUpdates.output)
|
|
541
|
+
.query(async ({ input, ctx }) => {
|
|
542
|
+
const p = requireCapProvider('addons', () => getProvider(ctx))
|
|
543
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
544
|
+
return p.listActiveBulkUpdates(input as any)
|
|
545
|
+
}),
|
|
496
546
|
getVersions: protectedProcedure
|
|
497
547
|
.input(addonsCapability.methods.getVersions.input.loose())
|
|
498
548
|
.output(addonsCapability.methods.getVersions.output)
|
|
@@ -1183,6 +1233,45 @@ export function createCapRouter_cameraCredentials(
|
|
|
1183
1233
|
})
|
|
1184
1234
|
}
|
|
1185
1235
|
|
|
1236
|
+
// ── camera-pipeline-config (singleton) ──────────────────────────────
|
|
1237
|
+
|
|
1238
|
+
type CameraPipelineConfigProvider = InferProvider<typeof cameraPipelineConfigCapability>
|
|
1239
|
+
|
|
1240
|
+
export function createCapRouter_cameraPipelineConfig(
|
|
1241
|
+
getProvider: (ctx: TrpcContext) => CameraPipelineConfigProvider | null,
|
|
1242
|
+
createRemoteProxy?: (capName: string, nodeId: string) => CameraPipelineConfigProvider | null,
|
|
1243
|
+
) {
|
|
1244
|
+
return trpcRouter({
|
|
1245
|
+
getDeviceSettingsContribution: protectedProcedure
|
|
1246
|
+
.input(DEVICE_SETTINGS_CONTRIBUTION_METHODS.getDeviceSettingsContribution.input.loose())
|
|
1247
|
+
.output(DEVICE_SETTINGS_CONTRIBUTION_METHODS.getDeviceSettingsContribution.output)
|
|
1248
|
+
.query(async ({ input, ctx }) => {
|
|
1249
|
+
const { nodeId, ...methodInput } = input as { nodeId?: string } & Record<string, unknown>
|
|
1250
|
+
const p = resolveProvider('camera-pipeline-config', nodeId, () => getProvider(ctx), createRemoteProxy)
|
|
1251
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
1252
|
+
return p.getDeviceSettingsContribution(methodInput as any)
|
|
1253
|
+
}),
|
|
1254
|
+
getDeviceLiveContribution: protectedProcedure
|
|
1255
|
+
.input(DEVICE_SETTINGS_CONTRIBUTION_METHODS.getDeviceLiveContribution.input.loose())
|
|
1256
|
+
.output(DEVICE_SETTINGS_CONTRIBUTION_METHODS.getDeviceLiveContribution.output)
|
|
1257
|
+
.query(async ({ input, ctx }) => {
|
|
1258
|
+
const { nodeId, ...methodInput } = input as { nodeId?: string } & Record<string, unknown>
|
|
1259
|
+
const p = resolveProvider('camera-pipeline-config', nodeId, () => getProvider(ctx), createRemoteProxy)
|
|
1260
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
1261
|
+
return p.getDeviceLiveContribution(methodInput as any)
|
|
1262
|
+
}),
|
|
1263
|
+
applyDeviceSettingsPatch: adminProcedure
|
|
1264
|
+
.input(DEVICE_SETTINGS_CONTRIBUTION_METHODS.applyDeviceSettingsPatch.input.loose())
|
|
1265
|
+
.output(DEVICE_SETTINGS_CONTRIBUTION_METHODS.applyDeviceSettingsPatch.output)
|
|
1266
|
+
.mutation(async ({ input, ctx }) => {
|
|
1267
|
+
const { nodeId, ...methodInput } = input as { nodeId?: string } & Record<string, unknown>
|
|
1268
|
+
const p = resolveProvider('camera-pipeline-config', nodeId, () => getProvider(ctx), createRemoteProxy)
|
|
1269
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
1270
|
+
return p.applyDeviceSettingsPatch(methodInput as any)
|
|
1271
|
+
}),
|
|
1272
|
+
})
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1186
1275
|
// ── camera-streams (singleton) ──────────────────────────────────────
|
|
1187
1276
|
|
|
1188
1277
|
type CameraStreamsProvider = InferProvider<typeof cameraStreamsCapability>
|
|
@@ -2976,6 +3065,15 @@ export function createCapRouter_nativeObjectDetection(
|
|
|
2976
3065
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
2977
3066
|
return p.getStatus(methodInput as any)
|
|
2978
3067
|
}),
|
|
3068
|
+
setEnabled: adminProcedure
|
|
3069
|
+
.input(nativeObjectDetectionCapability.methods.setEnabled.input.loose())
|
|
3070
|
+
.output(nativeObjectDetectionCapability.methods.setEnabled.output)
|
|
3071
|
+
.mutation(async ({ input, ctx }) => {
|
|
3072
|
+
const { nodeId, ...methodInput } = input as { nodeId?: string } & Record<string, unknown>
|
|
3073
|
+
const p = resolveProvider('native-object-detection', nodeId, () => getProvider(ctx), createRemoteProxy)
|
|
3074
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
3075
|
+
return p.setEnabled(methodInput as any)
|
|
3076
|
+
}),
|
|
2979
3077
|
})
|
|
2980
3078
|
}
|
|
2981
3079
|
|
|
@@ -4123,6 +4221,45 @@ export function createCapRouter_platformProbe(
|
|
|
4123
4221
|
})
|
|
4124
4222
|
}
|
|
4125
4223
|
|
|
4224
|
+
// ── privacy-mask (singleton) ────────────────────────────────────────
|
|
4225
|
+
|
|
4226
|
+
type PrivacyMaskProvider = InferProvider<typeof privacyMaskCapability>
|
|
4227
|
+
|
|
4228
|
+
export function createCapRouter_privacyMask(
|
|
4229
|
+
getProvider: (ctx: TrpcContext) => PrivacyMaskProvider | null,
|
|
4230
|
+
createRemoteProxy?: (capName: string, nodeId: string) => PrivacyMaskProvider | null,
|
|
4231
|
+
) {
|
|
4232
|
+
return trpcRouter({
|
|
4233
|
+
getStatus: protectedProcedure
|
|
4234
|
+
.input(DEVICE_STATUS_METHOD.getStatus.input.loose())
|
|
4235
|
+
.output(DEVICE_STATUS_METHOD.getStatus.output)
|
|
4236
|
+
.query(async ({ input, ctx }) => {
|
|
4237
|
+
const { nodeId, ...methodInput } = input as { nodeId?: string } & Record<string, unknown>
|
|
4238
|
+
const p = resolveProvider('privacy-mask', nodeId, () => getProvider(ctx), createRemoteProxy)
|
|
4239
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4240
|
+
return p.getStatus(methodInput as any)
|
|
4241
|
+
}),
|
|
4242
|
+
getOptions: protectedProcedure
|
|
4243
|
+
.input(privacyMaskCapability.methods.getOptions.input.loose())
|
|
4244
|
+
.output(privacyMaskCapability.methods.getOptions.output)
|
|
4245
|
+
.query(async ({ input, ctx }) => {
|
|
4246
|
+
const { nodeId, ...methodInput } = input as { nodeId?: string } & Record<string, unknown>
|
|
4247
|
+
const p = resolveProvider('privacy-mask', nodeId, () => getProvider(ctx), createRemoteProxy)
|
|
4248
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4249
|
+
return p.getOptions(methodInput as any)
|
|
4250
|
+
}),
|
|
4251
|
+
setMask: adminProcedure
|
|
4252
|
+
.input(privacyMaskCapability.methods.setMask.input.loose())
|
|
4253
|
+
.output(privacyMaskCapability.methods.setMask.output)
|
|
4254
|
+
.mutation(async ({ input, ctx }) => {
|
|
4255
|
+
const { nodeId, ...methodInput } = input as { nodeId?: string } & Record<string, unknown>
|
|
4256
|
+
const p = resolveProvider('privacy-mask', nodeId, () => getProvider(ctx), createRemoteProxy)
|
|
4257
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4258
|
+
return p.setMask(methodInput as any)
|
|
4259
|
+
}),
|
|
4260
|
+
})
|
|
4261
|
+
}
|
|
4262
|
+
|
|
4126
4263
|
// ── ptz (singleton) ─────────────────────────────────────────────────
|
|
4127
4264
|
|
|
4128
4265
|
type PtzProvider = InferProvider<typeof ptzCapability>
|
|
@@ -5443,6 +5580,27 @@ export function createCapRouter_streamBroker(
|
|
|
5443
5580
|
})
|
|
5444
5581
|
}
|
|
5445
5582
|
|
|
5583
|
+
// ── stream-catalog (singleton) ──────────────────────────────────────
|
|
5584
|
+
|
|
5585
|
+
type StreamCatalogProvider = InferProvider<typeof streamCatalogCapability>
|
|
5586
|
+
|
|
5587
|
+
export function createCapRouter_streamCatalog(
|
|
5588
|
+
getProvider: (ctx: TrpcContext) => StreamCatalogProvider | null,
|
|
5589
|
+
createRemoteProxy?: (capName: string, nodeId: string) => StreamCatalogProvider | null,
|
|
5590
|
+
) {
|
|
5591
|
+
return trpcRouter({
|
|
5592
|
+
getCatalog: protectedProcedure
|
|
5593
|
+
.input(streamCatalogCapability.methods.getCatalog.input.loose())
|
|
5594
|
+
.output(streamCatalogCapability.methods.getCatalog.output)
|
|
5595
|
+
.query(async ({ input, ctx }) => {
|
|
5596
|
+
const { nodeId, ...methodInput } = input as { nodeId?: string } & Record<string, unknown>
|
|
5597
|
+
const p = resolveProvider('stream-catalog', nodeId, () => getProvider(ctx), createRemoteProxy)
|
|
5598
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
5599
|
+
return p.getCatalog(methodInput as any)
|
|
5600
|
+
}),
|
|
5601
|
+
})
|
|
5602
|
+
}
|
|
5603
|
+
|
|
5446
5604
|
// ── stream-params (singleton) ───────────────────────────────────────
|
|
5447
5605
|
|
|
5448
5606
|
type StreamParamsProvider = InferProvider<typeof streamParamsCapability>
|
|
@@ -6102,6 +6260,24 @@ export function createCapRouter_webrtcSession(
|
|
|
6102
6260
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
6103
6261
|
return p.handleAnswer(methodInput as any)
|
|
6104
6262
|
}),
|
|
6263
|
+
addIceCandidate: protectedProcedure
|
|
6264
|
+
.input(webrtcSessionCapability.methods.addIceCandidate.input.loose())
|
|
6265
|
+
.output(webrtcSessionCapability.methods.addIceCandidate.output)
|
|
6266
|
+
.mutation(async ({ input, ctx }) => {
|
|
6267
|
+
const { nodeId, ...methodInput } = input as { nodeId?: string } & Record<string, unknown>
|
|
6268
|
+
const p = resolveProvider('webrtc-session', nodeId, () => getProvider(ctx), createRemoteProxy)
|
|
6269
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
6270
|
+
return p.addIceCandidate(methodInput as any)
|
|
6271
|
+
}),
|
|
6272
|
+
getIceCandidates: protectedProcedure
|
|
6273
|
+
.input(webrtcSessionCapability.methods.getIceCandidates.input.loose())
|
|
6274
|
+
.output(webrtcSessionCapability.methods.getIceCandidates.output)
|
|
6275
|
+
.query(async ({ input, ctx }) => {
|
|
6276
|
+
const { nodeId, ...methodInput } = input as { nodeId?: string } & Record<string, unknown>
|
|
6277
|
+
const p = resolveProvider('webrtc-session', nodeId, () => getProvider(ctx), createRemoteProxy)
|
|
6278
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
6279
|
+
return p.getIceCandidates(methodInput as any)
|
|
6280
|
+
}),
|
|
6105
6281
|
closeSession: protectedProcedure
|
|
6106
6282
|
.input(webrtcSessionCapability.methods.closeSession.input.loose())
|
|
6107
6283
|
.output(webrtcSessionCapability.methods.closeSession.output)
|
|
@@ -6273,6 +6449,7 @@ export interface GeneratedCapabilityRouterMap {
|
|
|
6273
6449
|
readonly battery: ReturnType<typeof createCapRouter_battery>
|
|
6274
6450
|
readonly brightness: ReturnType<typeof createCapRouter_brightness>
|
|
6275
6451
|
readonly cameraCredentials: ReturnType<typeof createCapRouter_cameraCredentials>
|
|
6452
|
+
readonly cameraPipelineConfig: ReturnType<typeof createCapRouter_cameraPipelineConfig>
|
|
6276
6453
|
readonly cameraStreams: ReturnType<typeof createCapRouter_cameraStreams>
|
|
6277
6454
|
readonly decoder: ReturnType<typeof createCapRouter_decoder>
|
|
6278
6455
|
readonly detectionPipeline: ReturnType<typeof createCapRouter_detectionPipeline>
|
|
@@ -6310,6 +6487,7 @@ export interface GeneratedCapabilityRouterMap {
|
|
|
6310
6487
|
readonly pipelineOrchestrator: ReturnType<typeof createCapRouter_pipelineOrchestrator>
|
|
6311
6488
|
readonly pipelineRunner: ReturnType<typeof createCapRouter_pipelineRunner>
|
|
6312
6489
|
readonly platformProbe: ReturnType<typeof createCapRouter_platformProbe>
|
|
6490
|
+
readonly privacyMask: ReturnType<typeof createCapRouter_privacyMask>
|
|
6313
6491
|
readonly ptz: ReturnType<typeof createCapRouter_ptz>
|
|
6314
6492
|
readonly ptzAutotrack: ReturnType<typeof createCapRouter_ptzAutotrack>
|
|
6315
6493
|
readonly reboot: ReturnType<typeof createCapRouter_reboot>
|
|
@@ -6324,6 +6502,7 @@ export interface GeneratedCapabilityRouterMap {
|
|
|
6324
6502
|
readonly storage: ReturnType<typeof createCapRouter_storage>
|
|
6325
6503
|
readonly storageProvider: ReturnType<typeof createCapRouter_storageProvider>
|
|
6326
6504
|
readonly streamBroker: ReturnType<typeof createCapRouter_streamBroker>
|
|
6505
|
+
readonly streamCatalog: ReturnType<typeof createCapRouter_streamCatalog>
|
|
6327
6506
|
readonly streamParams: ReturnType<typeof createCapRouter_streamParams>
|
|
6328
6507
|
readonly streamingEngine: ReturnType<typeof createCapRouter_streamingEngine>
|
|
6329
6508
|
readonly switch: ReturnType<typeof createCapRouter_switch>
|