@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,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createCapabilitiesRouter = createCapabilitiesRouter;
|
|
4
|
+
/**
|
|
5
|
+
* Capability admin router — fixed core API (not a capability).
|
|
6
|
+
*
|
|
7
|
+
* Lets admins inspect the capability registry and set system/device
|
|
8
|
+
* overrides. Wraps `CapabilityRegistry` directly (kernel primitive).
|
|
9
|
+
*/
|
|
10
|
+
const zod_1 = require("zod");
|
|
11
|
+
const trpc_middleware_js_1 = require("../trpc/trpc.middleware.js");
|
|
12
|
+
function createCapabilitiesRouter(registry, config) {
|
|
13
|
+
return (0, trpc_middleware_js_1.trpcRouter)({
|
|
14
|
+
listCapabilities: trpc_middleware_js_1.adminProcedure
|
|
15
|
+
.input(zod_1.z.void())
|
|
16
|
+
.query(() => registry?.listCapabilities() ?? []),
|
|
17
|
+
getCapability: trpc_middleware_js_1.adminProcedure.input(zod_1.z.object({ name: zod_1.z.string() })).query(({ input }) => {
|
|
18
|
+
if (!registry)
|
|
19
|
+
return null;
|
|
20
|
+
return (registry.listCapabilities().find((c) => c.name === input.name) ?? null);
|
|
21
|
+
}),
|
|
22
|
+
setActiveSingleton: trpc_middleware_js_1.adminProcedure
|
|
23
|
+
.input(zod_1.z.object({
|
|
24
|
+
capability: zod_1.z.string(),
|
|
25
|
+
addonId: zod_1.z.string(),
|
|
26
|
+
nodeId: zod_1.z.string().optional(),
|
|
27
|
+
}))
|
|
28
|
+
.output(zod_1.z.void())
|
|
29
|
+
.mutation(async ({ input }) => {
|
|
30
|
+
if (!registry)
|
|
31
|
+
throw new Error('Capability registry unavailable');
|
|
32
|
+
await registry.setActiveSingleton(input.capability, input.addonId, input.nodeId);
|
|
33
|
+
if (input.nodeId !== undefined) {
|
|
34
|
+
// Per-node override: persist under the node-qualified key so the boot
|
|
35
|
+
// restorer (`setNodeConfigReader`) replays it on restart.
|
|
36
|
+
config.set(`capabilities.singletonNode.${input.capability}.${input.nodeId}`, input.addonId);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// Cluster-global default: persist to the SAME key the boot restorer reads
|
|
40
|
+
// (addon-registry `setConfigReader` → `capabilities.singleton.<cap>`).
|
|
41
|
+
config.set(`capabilities.singleton.${input.capability}`, input.addonId);
|
|
42
|
+
}
|
|
43
|
+
}),
|
|
44
|
+
clearSingletonNodeOverride: trpc_middleware_js_1.adminProcedure
|
|
45
|
+
.input(zod_1.z.object({ capability: zod_1.z.string(), nodeId: zod_1.z.string() }))
|
|
46
|
+
.output(zod_1.z.void())
|
|
47
|
+
.mutation(({ input }) => {
|
|
48
|
+
if (!registry)
|
|
49
|
+
throw new Error('Capability registry unavailable');
|
|
50
|
+
registry.clearSingletonNodeOverride(input.capability, input.nodeId);
|
|
51
|
+
// Persist the cleared state as null so the boot restorer doesn't re-apply
|
|
52
|
+
// a stale override on restart.
|
|
53
|
+
config.set(`capabilities.singletonNode.${input.capability}.${input.nodeId}`, null);
|
|
54
|
+
}),
|
|
55
|
+
/**
|
|
56
|
+
* Set the enabled set of providers for a collection capability in
|
|
57
|
+
* one shot. Providers already registered on the capability that are
|
|
58
|
+
* NOT in `enabledAddonIds` get disabled; the ones in the list are
|
|
59
|
+
* re-enabled. Other collections are untouched. Intended as the
|
|
60
|
+
* save endpoint for a bulk multi-select UI.
|
|
61
|
+
*/
|
|
62
|
+
setCollectionEnabledProviders: trpc_middleware_js_1.adminProcedure
|
|
63
|
+
.input(zod_1.z.object({
|
|
64
|
+
capability: zod_1.z.string(),
|
|
65
|
+
enabledAddonIds: zod_1.z.array(zod_1.z.string()),
|
|
66
|
+
}))
|
|
67
|
+
.output(zod_1.z.void())
|
|
68
|
+
.mutation(({ input }) => {
|
|
69
|
+
if (!registry)
|
|
70
|
+
throw new Error('Capability registry unavailable');
|
|
71
|
+
const caps = registry.listCapabilities();
|
|
72
|
+
const entry = caps.find((c) => c.name === input.capability);
|
|
73
|
+
if (!entry)
|
|
74
|
+
throw new Error(`Capability "${input.capability}" not declared`);
|
|
75
|
+
if (entry.mode !== 'collection') {
|
|
76
|
+
throw new Error(`Capability "${input.capability}" is not a collection`);
|
|
77
|
+
}
|
|
78
|
+
const wanted = new Set(input.enabledAddonIds);
|
|
79
|
+
for (const providerId of entry.providers) {
|
|
80
|
+
if (wanted.has(providerId)) {
|
|
81
|
+
registry.enableCollectionProvider(input.capability, providerId);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
registry.disableCollectionProvider(input.capability, providerId);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}),
|
|
88
|
+
setDeviceCapability: trpc_middleware_js_1.adminProcedure
|
|
89
|
+
.input(zod_1.z.object({ deviceId: zod_1.z.string(), capability: zod_1.z.string(), addonId: zod_1.z.string() }))
|
|
90
|
+
.output(zod_1.z.void())
|
|
91
|
+
.mutation(({ input }) => {
|
|
92
|
+
if (!registry)
|
|
93
|
+
throw new Error('Capability registry unavailable');
|
|
94
|
+
registry.setDeviceOverride(input.deviceId, input.capability, input.addonId);
|
|
95
|
+
}),
|
|
96
|
+
clearDeviceCapability: trpc_middleware_js_1.adminProcedure
|
|
97
|
+
.input(zod_1.z.object({ deviceId: zod_1.z.string(), capability: zod_1.z.string() }))
|
|
98
|
+
.output(zod_1.z.void())
|
|
99
|
+
.mutation(({ input }) => {
|
|
100
|
+
if (!registry)
|
|
101
|
+
throw new Error('Capability registry unavailable');
|
|
102
|
+
registry.clearDeviceOverride(input.deviceId, input.capability);
|
|
103
|
+
}),
|
|
104
|
+
getDeviceCapabilities: trpc_middleware_js_1.adminProcedure
|
|
105
|
+
.input(zod_1.z.object({ deviceId: zod_1.z.string() }))
|
|
106
|
+
.output(zod_1.z.record(zod_1.z.string(), zod_1.z.string()))
|
|
107
|
+
.query(({ input }) => {
|
|
108
|
+
if (!registry)
|
|
109
|
+
return {};
|
|
110
|
+
const overrides = registry.getDeviceOverrides(input.deviceId);
|
|
111
|
+
const result = {};
|
|
112
|
+
for (const [cap, addonId] of overrides) {
|
|
113
|
+
result[cap] = addonId;
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}),
|
|
117
|
+
setDeviceCollectionFilter: trpc_middleware_js_1.adminProcedure
|
|
118
|
+
.input(zod_1.z.object({
|
|
119
|
+
deviceId: zod_1.z.string(),
|
|
120
|
+
capability: zod_1.z.string(),
|
|
121
|
+
addonIds: zod_1.z.array(zod_1.z.string()),
|
|
122
|
+
}))
|
|
123
|
+
.output(zod_1.z.void())
|
|
124
|
+
.mutation(({ input }) => {
|
|
125
|
+
if (!registry)
|
|
126
|
+
throw new Error('Capability registry unavailable');
|
|
127
|
+
registry.setDeviceCollectionFilter(input.deviceId, input.capability, input.addonIds);
|
|
128
|
+
}),
|
|
129
|
+
clearDeviceCollectionFilter: trpc_middleware_js_1.adminProcedure
|
|
130
|
+
.input(zod_1.z.object({ deviceId: zod_1.z.string(), capability: zod_1.z.string() }))
|
|
131
|
+
.output(zod_1.z.void())
|
|
132
|
+
.mutation(({ input }) => {
|
|
133
|
+
if (!registry)
|
|
134
|
+
throw new Error('Capability registry unavailable');
|
|
135
|
+
registry.clearDeviceCollectionFilter(input.deviceId, input.capability);
|
|
136
|
+
}),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.collectionPreferenceKey = collectionPreferenceKey;
|
|
4
|
+
exports.persistCollectionDisabled = persistCollectionDisabled;
|
|
5
|
+
/** ConfigService key holding the persisted disabled-set for a collection cap. */
|
|
6
|
+
function collectionPreferenceKey(capability) {
|
|
7
|
+
return `capabilities.collection.${capability}`;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Persist the disabled-addonId set for a collection capability. Pass the
|
|
11
|
+
* authoritative set straight from `registry.listCapabilities()` after the
|
|
12
|
+
* enable/disable mutation so the stored value always mirrors the live
|
|
13
|
+
* registry state.
|
|
14
|
+
*/
|
|
15
|
+
function persistCollectionDisabled(configService, capability, disabled) {
|
|
16
|
+
configService.set(collectionPreferenceKey(capability), JSON.stringify({ disabled: [...disabled] }));
|
|
17
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createEventBusProxyRouter = createEventBusProxyRouter;
|
|
4
|
+
/**
|
|
5
|
+
* EventBus proxy router — allows forked workers to emit events to the
|
|
6
|
+
* hub's EventBus via tRPC.
|
|
7
|
+
*
|
|
8
|
+
* Workers call `trpc.eventBusProxy.emit.mutate(event)` from their
|
|
9
|
+
* `context.eventBus.emit()` implementation. The hub-side router
|
|
10
|
+
* deserializes the event and emits it on the real EventBus.
|
|
11
|
+
*
|
|
12
|
+
* Subscribe/getRecent are routed through the existing `live.onEvent`
|
|
13
|
+
* subscription and `events` query routers — no duplication needed here.
|
|
14
|
+
*
|
|
15
|
+
* Introduced in session 7 (EventBus wiring for forked addons).
|
|
16
|
+
*/
|
|
17
|
+
const zod_1 = require("zod");
|
|
18
|
+
const trpc_middleware_js_1 = require("../trpc/trpc.middleware.js");
|
|
19
|
+
const SystemEventInputSchema = zod_1.z.object({
|
|
20
|
+
id: zod_1.z.string(),
|
|
21
|
+
timestamp: zod_1.z.string(), // ISO 8601 — converted to Date on emit
|
|
22
|
+
source: zod_1.z.object({
|
|
23
|
+
type: zod_1.z.string(),
|
|
24
|
+
id: zod_1.z.string(),
|
|
25
|
+
}),
|
|
26
|
+
category: zod_1.z.string(),
|
|
27
|
+
data: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()),
|
|
28
|
+
});
|
|
29
|
+
function createEventBusProxyRouter(eventBus) {
|
|
30
|
+
return (0, trpc_middleware_js_1.trpcRouter)({
|
|
31
|
+
emit: trpc_middleware_js_1.protectedProcedure
|
|
32
|
+
.input(SystemEventInputSchema)
|
|
33
|
+
.output(zod_1.z.object({ ok: zod_1.z.literal(true) }))
|
|
34
|
+
.mutation(({ input }) => {
|
|
35
|
+
eventBus.emit({
|
|
36
|
+
id: input.id,
|
|
37
|
+
timestamp: new Date(input.timestamp),
|
|
38
|
+
source: { type: input.source.type, id: input.source.id },
|
|
39
|
+
category: input.category,
|
|
40
|
+
data: input.data,
|
|
41
|
+
});
|
|
42
|
+
return { ok: true };
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createHwAccelRouter = createHwAccelRouter;
|
|
4
|
+
/**
|
|
5
|
+
* Hwaccel router — fixed core API (not a capability).
|
|
6
|
+
*
|
|
7
|
+
* Thin wrapper around the per-node `$hwaccel.resolve` Moleculer
|
|
8
|
+
* service. The hub-local instance (same process) serves the default
|
|
9
|
+
* `resolve` call; the per-node `resolveForNode` action targets any
|
|
10
|
+
* node in the cluster — used by the admin UI pipeline / NodeDetail
|
|
11
|
+
* pages to show the hwaccel backends available on each agent.
|
|
12
|
+
*
|
|
13
|
+
* Cross-node behaviour: `resolveForNode({ nodeId })` forwards via
|
|
14
|
+
* `broker.call('$hwaccel.resolve', params, { nodeID })`. Every node
|
|
15
|
+
* (hub + forked worker + remote agent) registers `$hwaccel` at
|
|
16
|
+
* bootstrap, so any reachable nodeId works.
|
|
17
|
+
*/
|
|
18
|
+
const zod_1 = require("zod");
|
|
19
|
+
const trpc_middleware_js_1 = require("../trpc/trpc.middleware.js");
|
|
20
|
+
const HwAccelBackendSchema = zod_1.z.enum([
|
|
21
|
+
'videotoolbox',
|
|
22
|
+
'cuda',
|
|
23
|
+
'nvdec',
|
|
24
|
+
'vaapi',
|
|
25
|
+
'qsv',
|
|
26
|
+
'd3d11va',
|
|
27
|
+
'dxva2',
|
|
28
|
+
'amf',
|
|
29
|
+
'vdpau',
|
|
30
|
+
'drm',
|
|
31
|
+
]);
|
|
32
|
+
const HwAccelPreferSchema = zod_1.z
|
|
33
|
+
.union([HwAccelBackendSchema, zod_1.z.literal('none')])
|
|
34
|
+
.nullable()
|
|
35
|
+
.optional();
|
|
36
|
+
const HwAccelResolutionSchema = zod_1.z.object({
|
|
37
|
+
preferred: zod_1.z.array(HwAccelBackendSchema).readonly(),
|
|
38
|
+
rationale: zod_1.z.string(),
|
|
39
|
+
});
|
|
40
|
+
function createHwAccelRouter(broker) {
|
|
41
|
+
return (0, trpc_middleware_js_1.trpcRouter)({
|
|
42
|
+
/** Probe the current hub process. */
|
|
43
|
+
resolve: trpc_middleware_js_1.adminProcedure
|
|
44
|
+
.input(zod_1.z.object({ prefer: HwAccelPreferSchema }).optional())
|
|
45
|
+
.output(HwAccelResolutionSchema)
|
|
46
|
+
.query(async ({ input }) => {
|
|
47
|
+
if (!broker)
|
|
48
|
+
throw new Error('Moleculer broker not available');
|
|
49
|
+
const params = { prefer: input?.prefer ?? null };
|
|
50
|
+
return broker.call('$hwaccel.resolve', params);
|
|
51
|
+
}),
|
|
52
|
+
/** Probe a specific node in the cluster — used by per-agent UI cards. */
|
|
53
|
+
resolveForNode: trpc_middleware_js_1.adminProcedure
|
|
54
|
+
.input(zod_1.z.object({ nodeId: zod_1.z.string(), prefer: HwAccelPreferSchema }))
|
|
55
|
+
.output(HwAccelResolutionSchema)
|
|
56
|
+
.query(async ({ input }) => {
|
|
57
|
+
if (!broker)
|
|
58
|
+
throw new Error('Moleculer broker not available');
|
|
59
|
+
const params = { prefer: input.prefer ?? null };
|
|
60
|
+
return broker.call('$hwaccel.resolve', params, {
|
|
61
|
+
nodeID: input.nodeId,
|
|
62
|
+
});
|
|
63
|
+
}),
|
|
64
|
+
/** List every node currently reachable and the hwaccel each resolves to. */
|
|
65
|
+
resolveAll: trpc_middleware_js_1.adminProcedure
|
|
66
|
+
.output(zod_1.z.array(zod_1.z.object({
|
|
67
|
+
nodeId: zod_1.z.string(),
|
|
68
|
+
resolution: HwAccelResolutionSchema,
|
|
69
|
+
})))
|
|
70
|
+
.query(async () => {
|
|
71
|
+
if (!broker)
|
|
72
|
+
throw new Error('Moleculer broker not available');
|
|
73
|
+
const registry = broker.registry;
|
|
74
|
+
const nodes = registry.getNodeList({ onlyAvailable: true });
|
|
75
|
+
const results = await Promise.all(nodes.map(async (n) => {
|
|
76
|
+
try {
|
|
77
|
+
const resolution = (await broker.call('$hwaccel.resolve', { prefer: null }, { nodeID: n.id }));
|
|
78
|
+
return { nodeId: n.id, resolution };
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
82
|
+
return {
|
|
83
|
+
nodeId: n.id,
|
|
84
|
+
resolution: { preferred: [], rationale: `resolve failed: ${msg}` },
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}));
|
|
88
|
+
return results;
|
|
89
|
+
}),
|
|
90
|
+
});
|
|
91
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createLiveEventsRouter = createLiveEventsRouter;
|
|
4
|
+
/**
|
|
5
|
+
* Live events router — fixed core API (not a capability).
|
|
6
|
+
*
|
|
7
|
+
* Higher-level live-subscription API consumed by the admin UI dashboard.
|
|
8
|
+
* Wraps `EventBusService` with per-device permission enforcement.
|
|
9
|
+
*/
|
|
10
|
+
const zod_1 = require("zod");
|
|
11
|
+
const trpc_middleware_js_1 = require("../trpc/trpc.middleware.js");
|
|
12
|
+
function createLiveEventsRouter(eb, ar) {
|
|
13
|
+
return (0, trpc_middleware_js_1.trpcRouter)({
|
|
14
|
+
recentSystemEvents: trpc_middleware_js_1.protectedProcedure
|
|
15
|
+
.input(zod_1.z
|
|
16
|
+
.object({
|
|
17
|
+
category: zod_1.z.string().optional(),
|
|
18
|
+
limit: zod_1.z.number().optional(),
|
|
19
|
+
})
|
|
20
|
+
.optional())
|
|
21
|
+
.query(({ input }) => eb.getRecent(input ?? {}, input?.limit ?? 50)),
|
|
22
|
+
onEvent: trpc_middleware_js_1.protectedProcedure
|
|
23
|
+
.input(zod_1.z.object({ category: zod_1.z.string().optional() }))
|
|
24
|
+
.subscription(({ input }) => {
|
|
25
|
+
return (0, trpc_middleware_js_1.iterableSubscription)((push) => {
|
|
26
|
+
const filter = {};
|
|
27
|
+
if (input.category)
|
|
28
|
+
filter.category = input.category;
|
|
29
|
+
return eb.subscribe(filter, push);
|
|
30
|
+
});
|
|
31
|
+
}),
|
|
32
|
+
onDeviceEvent: trpc_middleware_js_1.protectedProcedure
|
|
33
|
+
.input(zod_1.z.object({ deviceId: zod_1.z.number() }))
|
|
34
|
+
.subscription(({ input, ctx }) => {
|
|
35
|
+
return (0, trpc_middleware_js_1.iterableSubscription)((push) => {
|
|
36
|
+
const deviceRegistry = ar.getDeviceRegistry();
|
|
37
|
+
const device = deviceRegistry.getById(input.deviceId);
|
|
38
|
+
if (!device)
|
|
39
|
+
throw new Error(`Device id=${input.deviceId} not found`);
|
|
40
|
+
// Permission check — new IDevice has no providerId; admin bypass only
|
|
41
|
+
if (!ctx.user.isAdmin) {
|
|
42
|
+
const ad = ctx.user.permissions?.allowedDevices;
|
|
43
|
+
if (!ad)
|
|
44
|
+
throw new Error('Access denied');
|
|
45
|
+
// Find which addon owns this device to determine the provider key
|
|
46
|
+
const ownerAddonId = deviceRegistry.getAddonId(input.deviceId);
|
|
47
|
+
if (!ownerAddonId)
|
|
48
|
+
throw new Error('Access denied');
|
|
49
|
+
const pd = ad[ownerAddonId];
|
|
50
|
+
// Permission lists are still keyed by stableId — that's the
|
|
51
|
+
// external admin-facing identifier. Resolve the device's
|
|
52
|
+
// stableId for the membership check.
|
|
53
|
+
if (!pd || (pd !== '*' && !pd.includes(device.stableId))) {
|
|
54
|
+
throw new Error('Access denied');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return eb.subscribe({ source: { type: 'device', id: input.deviceId } }, push);
|
|
58
|
+
});
|
|
59
|
+
}),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createLogsRouter = createLogsRouter;
|
|
4
|
+
/**
|
|
5
|
+
* Logs router — fixed core API (not a capability).
|
|
6
|
+
*
|
|
7
|
+
* Queries and streams log entries via `LoggingService` (thin NestJS DI
|
|
8
|
+
* wrapper over `LogManager` from `@camstack/core`). Admin can read
|
|
9
|
+
* everything; viewers/protected users only see entries matching their
|
|
10
|
+
* allowed providers scope (filtered in `query`).
|
|
11
|
+
*/
|
|
12
|
+
const zod_1 = require("zod");
|
|
13
|
+
const trpc_middleware_js_1 = require("../trpc/trpc.middleware.js");
|
|
14
|
+
const LogLevelSchema = zod_1.z.enum(['debug', 'info', 'warn', 'error']);
|
|
15
|
+
const LogTagsSchema = zod_1.z.object({
|
|
16
|
+
agentId: zod_1.z.string().optional(),
|
|
17
|
+
nodeId: zod_1.z.string().optional(),
|
|
18
|
+
/** Numeric progressive id (or its string form for legacy callers). */
|
|
19
|
+
deviceId: zod_1.z.union([zod_1.z.string(), zod_1.z.number()]).optional(),
|
|
20
|
+
/** Parent container id — set on every accessory child's logs (and on the
|
|
21
|
+
* container's own logs). Filtering by it returns the whole container subtree
|
|
22
|
+
* (container + all children) in one query. */
|
|
23
|
+
containerDeviceId: zod_1.z.union([zod_1.z.string(), zod_1.z.number()]).optional(),
|
|
24
|
+
deviceName: zod_1.z.string().optional(),
|
|
25
|
+
integrationId: zod_1.z.string().optional(),
|
|
26
|
+
addonId: zod_1.z.string().optional(),
|
|
27
|
+
streamId: zod_1.z.string().optional(),
|
|
28
|
+
streamName: zod_1.z.string().optional(),
|
|
29
|
+
sessionId: zod_1.z.string().optional(),
|
|
30
|
+
/**
|
|
31
|
+
* Correlation id used to scope a single short-lived operation
|
|
32
|
+
* (e.g. a `testCreationField` probe). The Add-Device modal generates
|
|
33
|
+
* one per dialog open and providers tag their loggers with it so the
|
|
34
|
+
* modal can stream test logs without a deviceId (the device doesn't
|
|
35
|
+
* exist yet).
|
|
36
|
+
*/
|
|
37
|
+
requestId: zod_1.z.string().optional(),
|
|
38
|
+
});
|
|
39
|
+
/** Wire shape of a log entry — timestamp is serialised to ISO string by tRPC. */
|
|
40
|
+
const LogEntrySchema = zod_1.z.object({
|
|
41
|
+
timestamp: zod_1.z.string(),
|
|
42
|
+
level: zod_1.z.string(),
|
|
43
|
+
scope: zod_1.z.string().optional(),
|
|
44
|
+
message: zod_1.z.string(),
|
|
45
|
+
tags: zod_1.z.record(zod_1.z.string(), zod_1.z.string().optional()).optional(),
|
|
46
|
+
/**
|
|
47
|
+
* Ad-hoc structured payload attached to the log call (e.g.
|
|
48
|
+
* `{error, brokerId, sourceType, url}` for stream-broker errors).
|
|
49
|
+
* Tags are filterable structural fields; meta is the per-call
|
|
50
|
+
* payload operators read in the expanded LogStream row.
|
|
51
|
+
*/
|
|
52
|
+
meta: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
|
|
53
|
+
});
|
|
54
|
+
const LogEntryArraySchema = zod_1.z.array(LogEntrySchema);
|
|
55
|
+
function createLogsRouter(logging) {
|
|
56
|
+
return (0, trpc_middleware_js_1.trpcRouter)({
|
|
57
|
+
query: trpc_middleware_js_1.adminProcedure
|
|
58
|
+
.input(zod_1.z.object({
|
|
59
|
+
level: LogLevelSchema.optional(),
|
|
60
|
+
since: zod_1.z.number().optional(),
|
|
61
|
+
until: zod_1.z.number().optional(),
|
|
62
|
+
limit: zod_1.z.number().optional(),
|
|
63
|
+
tags: LogTagsSchema.optional(),
|
|
64
|
+
}))
|
|
65
|
+
.output(LogEntryArraySchema)
|
|
66
|
+
.query(({ input, ctx }) => {
|
|
67
|
+
const filter = { limit: input.limit ?? 100 };
|
|
68
|
+
if (input.level)
|
|
69
|
+
filter.level = input.level;
|
|
70
|
+
if (input.since !== undefined)
|
|
71
|
+
filter.since = new Date(input.since);
|
|
72
|
+
if (input.until !== undefined)
|
|
73
|
+
filter.until = new Date(input.until);
|
|
74
|
+
if (input.tags)
|
|
75
|
+
filter.tags = input.tags;
|
|
76
|
+
const entries = logging.query(filter);
|
|
77
|
+
const filtered = (() => {
|
|
78
|
+
if (!ctx.user.isAdmin) {
|
|
79
|
+
const ap = ctx.user.permissions?.allowedProviders;
|
|
80
|
+
if (ap && ap !== '*') {
|
|
81
|
+
const allowed = ap;
|
|
82
|
+
return entries.filter((e) => {
|
|
83
|
+
const addonId = e.tags?.addonId;
|
|
84
|
+
if (typeof addonId !== 'string')
|
|
85
|
+
return false;
|
|
86
|
+
return allowed.some((p) => {
|
|
87
|
+
const bare = p.startsWith('addon:') ? p.slice('addon:'.length) : p;
|
|
88
|
+
return addonId === bare || addonId.startsWith(bare);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return entries;
|
|
94
|
+
})();
|
|
95
|
+
return filtered.map((e) => ({
|
|
96
|
+
timestamp: e.timestamp instanceof Date ? e.timestamp.toISOString() : String(e.timestamp),
|
|
97
|
+
level: e.level,
|
|
98
|
+
...(e.scope !== undefined ? { scope: e.scope } : {}),
|
|
99
|
+
message: e.message,
|
|
100
|
+
// Tags carry mixed primitive types (numeric deviceId is common —
|
|
101
|
+
// see kernel/capability-registry.ts logging calls). The wire
|
|
102
|
+
// schema is Record<string,string>, so stringify here. Mirrors
|
|
103
|
+
// the same normalisation applied in `subscribe` below.
|
|
104
|
+
tags: e.tags
|
|
105
|
+
? Object.fromEntries(Object.entries(e.tags).map(([k, v]) => [
|
|
106
|
+
k,
|
|
107
|
+
v === undefined ? undefined : String(v),
|
|
108
|
+
]))
|
|
109
|
+
: undefined,
|
|
110
|
+
...(e.meta !== undefined ? { meta: e.meta } : {}),
|
|
111
|
+
}));
|
|
112
|
+
}),
|
|
113
|
+
/**
|
|
114
|
+
* Drop matching entries from the in-memory ring buffer. Powers
|
|
115
|
+
* the UI's "Clear logs" button — without server-side purge, the
|
|
116
|
+
* cleared rows reappear on the next page open from the historical
|
|
117
|
+
* `query`. Admin-only so a viewer can't wipe context other ops
|
|
118
|
+
* are reading.
|
|
119
|
+
*/
|
|
120
|
+
clear: trpc_middleware_js_1.adminProcedure
|
|
121
|
+
.input(zod_1.z.object({
|
|
122
|
+
level: LogLevelSchema.optional(),
|
|
123
|
+
since: zod_1.z.number().optional(),
|
|
124
|
+
until: zod_1.z.number().optional(),
|
|
125
|
+
tags: LogTagsSchema.optional(),
|
|
126
|
+
}))
|
|
127
|
+
.output(zod_1.z.object({ removed: zod_1.z.number().int().nonnegative() }))
|
|
128
|
+
.mutation(({ input }) => {
|
|
129
|
+
const filter = {};
|
|
130
|
+
if (input.level)
|
|
131
|
+
filter.level = input.level;
|
|
132
|
+
if (input.since !== undefined)
|
|
133
|
+
filter.since = new Date(input.since);
|
|
134
|
+
if (input.until !== undefined)
|
|
135
|
+
filter.until = new Date(input.until);
|
|
136
|
+
if (input.tags)
|
|
137
|
+
filter.tags = input.tags;
|
|
138
|
+
const removed = logging.clear(filter);
|
|
139
|
+
return { removed };
|
|
140
|
+
}),
|
|
141
|
+
subscribe: trpc_middleware_js_1.protectedProcedure
|
|
142
|
+
.input(zod_1.z.object({
|
|
143
|
+
level: LogLevelSchema.optional(),
|
|
144
|
+
tags: LogTagsSchema.optional(),
|
|
145
|
+
}))
|
|
146
|
+
.subscription(({ input }) => {
|
|
147
|
+
return (0, trpc_middleware_js_1.iterableSubscription)((push) => {
|
|
148
|
+
return logging.subscribe({
|
|
149
|
+
level: input.level,
|
|
150
|
+
tags: input.tags,
|
|
151
|
+
}, (entry) => {
|
|
152
|
+
const stringifiedTags = entry.tags
|
|
153
|
+
? Object.fromEntries(Object.entries(entry.tags).map(([k, v]) => [
|
|
154
|
+
k,
|
|
155
|
+
v === undefined ? undefined : String(v),
|
|
156
|
+
]))
|
|
157
|
+
: undefined;
|
|
158
|
+
push({
|
|
159
|
+
timestamp: entry.timestamp instanceof Date
|
|
160
|
+
? entry.timestamp.toISOString()
|
|
161
|
+
: String(entry.timestamp),
|
|
162
|
+
level: entry.level,
|
|
163
|
+
message: entry.message,
|
|
164
|
+
scope: entry.scope,
|
|
165
|
+
tags: stringifiedTags,
|
|
166
|
+
meta: entry.meta,
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createNotificationsRouter = createNotificationsRouter;
|
|
4
|
+
/**
|
|
5
|
+
* Notifications router — fixed core API (not a capability).
|
|
6
|
+
*
|
|
7
|
+
* Routes events by category to registered outputs. The NotificationService
|
|
8
|
+
* is a singleton from @camstack/core; individual outputs are still provided
|
|
9
|
+
* by addons via the `notification-output` capability collection.
|
|
10
|
+
*/
|
|
11
|
+
const zod_1 = require("zod");
|
|
12
|
+
const trpc_middleware_js_1 = require("../trpc/trpc.middleware.js");
|
|
13
|
+
const NotificationOutputSchema = zod_1.z.object({
|
|
14
|
+
id: zod_1.z.string(),
|
|
15
|
+
name: zod_1.z.string(),
|
|
16
|
+
icon: zod_1.z.string(),
|
|
17
|
+
});
|
|
18
|
+
const SendTestResultSchema = zod_1.z.object({
|
|
19
|
+
success: zod_1.z.boolean(),
|
|
20
|
+
error: zod_1.z.string().optional(),
|
|
21
|
+
});
|
|
22
|
+
function createNotificationsRouter(ns) {
|
|
23
|
+
return (0, trpc_middleware_js_1.trpcRouter)({
|
|
24
|
+
listOutputs: trpc_middleware_js_1.protectedProcedure
|
|
25
|
+
.input(zod_1.z.void())
|
|
26
|
+
.output(zod_1.z.array(NotificationOutputSchema).readonly())
|
|
27
|
+
.query(() => {
|
|
28
|
+
if (!ns)
|
|
29
|
+
return [];
|
|
30
|
+
return ns.getOutputs();
|
|
31
|
+
}),
|
|
32
|
+
getRouting: trpc_middleware_js_1.protectedProcedure
|
|
33
|
+
.input(zod_1.z.void())
|
|
34
|
+
.output(zod_1.z.record(zod_1.z.string(), zod_1.z.array(zod_1.z.string())))
|
|
35
|
+
.query(() => {
|
|
36
|
+
if (!ns)
|
|
37
|
+
return {};
|
|
38
|
+
const routing = ns.getRouting();
|
|
39
|
+
const result = {};
|
|
40
|
+
for (const [category, outputIds] of routing) {
|
|
41
|
+
result[category] = [...outputIds];
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}),
|
|
45
|
+
setRouting: trpc_middleware_js_1.adminProcedure
|
|
46
|
+
.input(zod_1.z.object({ category: zod_1.z.string(), outputIds: zod_1.z.array(zod_1.z.string()) }))
|
|
47
|
+
.output(zod_1.z.void())
|
|
48
|
+
.mutation(({ input }) => {
|
|
49
|
+
if (!ns)
|
|
50
|
+
throw new Error('Notification service unavailable');
|
|
51
|
+
ns.setRouting(input.category, input.outputIds);
|
|
52
|
+
}),
|
|
53
|
+
sendTest: trpc_middleware_js_1.adminProcedure
|
|
54
|
+
.input(zod_1.z.object({ outputId: zod_1.z.string() }))
|
|
55
|
+
.output(SendTestResultSchema)
|
|
56
|
+
.mutation(async ({ input }) => {
|
|
57
|
+
if (!ns)
|
|
58
|
+
return { success: false, error: 'Notification service unavailable' };
|
|
59
|
+
const output = ns.getOutput(input.outputId);
|
|
60
|
+
if (!output)
|
|
61
|
+
return { success: false, error: `Output "${input.outputId}" not found` };
|
|
62
|
+
if (!output.sendTest)
|
|
63
|
+
return { success: false, error: 'Output does not support test notifications' };
|
|
64
|
+
return output.sendTest();
|
|
65
|
+
}),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createReplRouter = createReplRouter;
|
|
4
|
+
/**
|
|
5
|
+
* REPL router — fixed core API (not a capability).
|
|
6
|
+
*
|
|
7
|
+
* The REPL engine is a single NestJS-backed service in the backend
|
|
8
|
+
* (`ReplEngineService` extends `ReplEngine` from `@camstack/core`).
|
|
9
|
+
* Only super_admin can execute code.
|
|
10
|
+
*/
|
|
11
|
+
const zod_1 = require("zod");
|
|
12
|
+
const trpc_middleware_js_1 = require("../trpc/trpc.middleware.js");
|
|
13
|
+
const ReplScopeSchema = zod_1.z.discriminatedUnion('type', [
|
|
14
|
+
zod_1.z.object({ type: zod_1.z.literal('system') }),
|
|
15
|
+
zod_1.z.object({ type: zod_1.z.literal('device'), deviceId: zod_1.z.number() }),
|
|
16
|
+
zod_1.z.object({ type: zod_1.z.literal('provider'), providerId: zod_1.z.string() }),
|
|
17
|
+
zod_1.z.object({ type: zod_1.z.literal('addon'), addonId: zod_1.z.string() }),
|
|
18
|
+
]);
|
|
19
|
+
const ReplResultSchema = zod_1.z.object({
|
|
20
|
+
output: zod_1.z.string(),
|
|
21
|
+
error: zod_1.z.string().optional(),
|
|
22
|
+
duration: zod_1.z.number().optional(),
|
|
23
|
+
});
|
|
24
|
+
function createReplRouter(repl) {
|
|
25
|
+
return (0, trpc_middleware_js_1.trpcRouter)({
|
|
26
|
+
execute: trpc_middleware_js_1.adminProcedure
|
|
27
|
+
.input(zod_1.z.object({ code: zod_1.z.string().max(10000), scope: ReplScopeSchema }))
|
|
28
|
+
.output(ReplResultSchema)
|
|
29
|
+
.mutation(({ input }) => repl.execute(input.code, { scope: input.scope, variables: {} })),
|
|
30
|
+
completions: trpc_middleware_js_1.adminProcedure
|
|
31
|
+
.input(zod_1.z.object({ partial: zod_1.z.string(), scope: ReplScopeSchema }))
|
|
32
|
+
.output(zod_1.z.array(zod_1.z.string()).readonly())
|
|
33
|
+
.query(({ input }) => repl.getCompletions(input.partial, { scope: input.scope, variables: {} })),
|
|
34
|
+
});
|
|
35
|
+
}
|