@camstack/server 0.2.2 → 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
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* UDS child log ingest — unit test for Task B2.
|
|
3
|
-
*
|
|
4
|
-
* Verifies that wiring `LocalChildRegistry.onChildLog` to
|
|
5
|
-
* `LoggingService.writeFromWorker` correctly maps a `ChildLogMessage`
|
|
6
|
-
* produced over a UDS channel to the `writeFromWorker` entry shape.
|
|
7
|
-
*
|
|
8
|
-
* We test the helper `udsChildLogToWorkerEntry` (extracted from the
|
|
9
|
-
* hub/agent wiring) directly, plus the full registry+handler pairing so
|
|
10
|
-
* the glue code exercises the real `onChildLog` callback path.
|
|
11
|
-
*/
|
|
12
|
-
import { describe, it, expect, vi } from 'vitest'
|
|
13
|
-
import type { ChildLogMessage } from '@camstack/kernel'
|
|
14
|
-
import { udsChildLogToWorkerEntry } from '@camstack/kernel'
|
|
15
|
-
|
|
16
|
-
// --------------------------------------------------------------------------
|
|
17
|
-
// Minimal `WriteFromWorkerEntry` shape mirrored from LoggingService signature
|
|
18
|
-
// --------------------------------------------------------------------------
|
|
19
|
-
interface WriteFromWorkerEntry {
|
|
20
|
-
addonId: string
|
|
21
|
-
nodeId?: string
|
|
22
|
-
level: string
|
|
23
|
-
message: string
|
|
24
|
-
scope?: string
|
|
25
|
-
tags?: Record<string, string | number | undefined>
|
|
26
|
-
meta?: Record<string, unknown>
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// --------------------------------------------------------------------------
|
|
30
|
-
// Helper: build a minimal ChildLogMessage
|
|
31
|
-
// --------------------------------------------------------------------------
|
|
32
|
-
function makeLogMessage(overrides?: Partial<ChildLogMessage>): ChildLogMessage {
|
|
33
|
-
return {
|
|
34
|
-
kind: 'log',
|
|
35
|
-
level: 'info',
|
|
36
|
-
message: 'hello from child',
|
|
37
|
-
addonId: 'stream-broker',
|
|
38
|
-
...overrides,
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// --------------------------------------------------------------------------
|
|
43
|
-
// Tests for udsChildLogToWorkerEntry
|
|
44
|
-
// --------------------------------------------------------------------------
|
|
45
|
-
|
|
46
|
-
describe('udsChildLogToWorkerEntry', () => {
|
|
47
|
-
it('maps the required fields — addonId, level, message', () => {
|
|
48
|
-
const entry = makeLogMessage()
|
|
49
|
-
const result = udsChildLogToWorkerEntry('stream-broker', entry)
|
|
50
|
-
|
|
51
|
-
expect(result.addonId).toBe('stream-broker')
|
|
52
|
-
expect(result.level).toBe('info')
|
|
53
|
-
expect(result.message).toBe('hello from child')
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('uses entry.nodeId when present', () => {
|
|
57
|
-
const entry = makeLogMessage({ nodeId: 'hub/stream-broker' })
|
|
58
|
-
const result = udsChildLogToWorkerEntry('stream-broker', entry)
|
|
59
|
-
|
|
60
|
-
expect(result.nodeId).toBe('hub/stream-broker')
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
it('falls back to childId when nodeId is absent', () => {
|
|
64
|
-
const entry = makeLogMessage()
|
|
65
|
-
const result = udsChildLogToWorkerEntry('stream-broker', entry)
|
|
66
|
-
|
|
67
|
-
expect(result.nodeId).toBe('stream-broker')
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it('omits scope when not present in entry', () => {
|
|
71
|
-
const entry = makeLogMessage()
|
|
72
|
-
const result = udsChildLogToWorkerEntry('stream-broker', entry)
|
|
73
|
-
|
|
74
|
-
expect(Object.prototype.hasOwnProperty.call(result, 'scope')).toBe(false)
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('includes scope when present in entry', () => {
|
|
78
|
-
const entry = makeLogMessage({ scope: 'rtsp' })
|
|
79
|
-
const result = udsChildLogToWorkerEntry('stream-broker', entry)
|
|
80
|
-
|
|
81
|
-
expect(result.scope).toBe('rtsp')
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
it('omits tags when not present in entry', () => {
|
|
85
|
-
const entry = makeLogMessage()
|
|
86
|
-
const result = udsChildLogToWorkerEntry('stream-broker', entry)
|
|
87
|
-
|
|
88
|
-
expect(Object.prototype.hasOwnProperty.call(result, 'tags')).toBe(false)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
it('includes tags when present in entry', () => {
|
|
92
|
-
const entry = makeLogMessage({ tags: { deviceId: 5, streamId: '5/main' } })
|
|
93
|
-
const result = udsChildLogToWorkerEntry('stream-broker', entry)
|
|
94
|
-
|
|
95
|
-
expect(result.tags).toEqual({ deviceId: 5, streamId: '5/main' })
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
it('omits meta when not present in entry', () => {
|
|
99
|
-
const entry = makeLogMessage()
|
|
100
|
-
const result = udsChildLogToWorkerEntry('stream-broker', entry)
|
|
101
|
-
|
|
102
|
-
expect(Object.prototype.hasOwnProperty.call(result, 'meta')).toBe(false)
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
it('includes meta when present in entry', () => {
|
|
106
|
-
const entry = makeLogMessage({ meta: { rtt: 42 } })
|
|
107
|
-
const result = udsChildLogToWorkerEntry('stream-broker', entry)
|
|
108
|
-
|
|
109
|
-
expect(result.meta).toEqual({ rtt: 42 })
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
it('produces the same shape that $hub.log onLog produces', () => {
|
|
113
|
-
// The existing onLog wiring in moleculer.service.ts maps:
|
|
114
|
-
// { addonId, nodeId, level, message, scope?, tags?, meta? }
|
|
115
|
-
// Verify we produce an identical structure for a fully-populated entry.
|
|
116
|
-
const entry = makeLogMessage({
|
|
117
|
-
addonId: 'ptz-provider',
|
|
118
|
-
nodeId: 'hub/ptz-provider',
|
|
119
|
-
level: 'warn',
|
|
120
|
-
message: 'PTZ timeout',
|
|
121
|
-
scope: 'ptz',
|
|
122
|
-
tags: { deviceId: 3 },
|
|
123
|
-
meta: { timeout: 5000 },
|
|
124
|
-
})
|
|
125
|
-
const result = udsChildLogToWorkerEntry('hub/ptz-provider', entry)
|
|
126
|
-
|
|
127
|
-
const expected: WriteFromWorkerEntry = {
|
|
128
|
-
addonId: 'ptz-provider',
|
|
129
|
-
nodeId: 'hub/ptz-provider',
|
|
130
|
-
level: 'warn',
|
|
131
|
-
message: 'PTZ timeout',
|
|
132
|
-
scope: 'ptz',
|
|
133
|
-
tags: { deviceId: 3 },
|
|
134
|
-
meta: { timeout: 5000 },
|
|
135
|
-
}
|
|
136
|
-
expect(result).toEqual(expected)
|
|
137
|
-
})
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
// --------------------------------------------------------------------------
|
|
141
|
-
// Tests for the registry+handler wiring (the onChildLog callback path)
|
|
142
|
-
// --------------------------------------------------------------------------
|
|
143
|
-
|
|
144
|
-
describe('onChildLog handler wiring', () => {
|
|
145
|
-
it('calls writeFromWorker when a ChildLogMessage arrives', () => {
|
|
146
|
-
// Fake logging service — typed minimal interface
|
|
147
|
-
const fakeLogging = {
|
|
148
|
-
writeFromWorker: vi.fn<[WriteFromWorkerEntry], void>(),
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// The actual wiring closure (mirrors hub & agent wiring)
|
|
152
|
-
const handler = (childId: string, entry: ChildLogMessage): void => {
|
|
153
|
-
fakeLogging.writeFromWorker(udsChildLogToWorkerEntry(childId, entry))
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const entry = makeLogMessage({ addonId: 'motion-detector', nodeId: 'hub/motion-detector' })
|
|
157
|
-
handler('hub/motion-detector', entry)
|
|
158
|
-
|
|
159
|
-
expect(fakeLogging.writeFromWorker).toHaveBeenCalledOnce()
|
|
160
|
-
const called = fakeLogging.writeFromWorker.mock.calls[0]![0]
|
|
161
|
-
expect(called.addonId).toBe('motion-detector')
|
|
162
|
-
expect(called.nodeId).toBe('hub/motion-detector')
|
|
163
|
-
expect(called.level).toBe('info')
|
|
164
|
-
expect(called.message).toBe('hello from child')
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
it('invokes writeFromWorker once per log entry', () => {
|
|
168
|
-
const fakeLogging = {
|
|
169
|
-
writeFromWorker: vi.fn<[WriteFromWorkerEntry], void>(),
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const handler = (childId: string, entry: ChildLogMessage): void => {
|
|
173
|
-
fakeLogging.writeFromWorker(udsChildLogToWorkerEntry(childId, entry))
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
handler('child-a', makeLogMessage({ addonId: 'child-a', level: 'debug', message: 'first' }))
|
|
177
|
-
handler('child-b', makeLogMessage({ addonId: 'child-b', level: 'error', message: 'second' }))
|
|
178
|
-
|
|
179
|
-
expect(fakeLogging.writeFromWorker).toHaveBeenCalledTimes(2)
|
|
180
|
-
expect(fakeLogging.writeFromWorker.mock.calls[0]![0].addonId).toBe('child-a')
|
|
181
|
-
expect(fakeLogging.writeFromWorker.mock.calls[1]![0].addonId).toBe('child-b')
|
|
182
|
-
})
|
|
183
|
-
})
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for `api.addons.custom` — the generic addon custom-action dispatcher
|
|
3
|
-
* built in Task 7.2 of the device-proxy redesign.
|
|
4
|
-
*
|
|
5
|
-
* Verifies:
|
|
6
|
-
* - dispatch to a registered action returns the addon's value
|
|
7
|
-
* - input is round-tripped through the action's Zod schema
|
|
8
|
-
* - unknown (addonId, action) → NOT_FOUND
|
|
9
|
-
* - unauthenticated caller → UNAUTHORIZED
|
|
10
|
-
* - per-action `auth: 'admin'` is enforced (viewer rejected, admin allowed)
|
|
11
|
-
* - per-action `auth: 'public'` allows anonymous callers
|
|
12
|
-
* - addon output that violates its own schema → BAD_REQUEST (Zod parse)
|
|
13
|
-
*/
|
|
14
|
-
import { describe, it, expect, beforeEach } from 'vitest'
|
|
15
|
-
import { z } from 'zod'
|
|
16
|
-
import { TRPCError } from '@trpc/server'
|
|
17
|
-
import { customAction, defineCustomActions } from '@camstack/types'
|
|
18
|
-
import { CustomActionRegistry } from '@camstack/kernel'
|
|
19
|
-
import { trpcRouter } from '../trpc/trpc.middleware.js'
|
|
20
|
-
import { createAddonsCustomProcedures } from '../addons-custom.router.js'
|
|
21
|
-
import { makeCtx } from '../../__tests__/cap-routers/harness.js'
|
|
22
|
-
|
|
23
|
-
const catalog = defineCustomActions({
|
|
24
|
-
ping: customAction(z.void(), z.literal('pong')),
|
|
25
|
-
echo: customAction(z.object({ msg: z.string() }), z.object({ msg: z.string() })),
|
|
26
|
-
adminOnly: customAction(z.void(), z.literal('ok'), { kind: 'mutation', auth: 'admin' }),
|
|
27
|
-
open: customAction(z.void(), z.literal('open'), { auth: 'public' }),
|
|
28
|
-
badOutput: customAction(z.void(), z.literal('expected')),
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
function buildRouter(registry: CustomActionRegistry) {
|
|
32
|
-
return trpcRouter({
|
|
33
|
-
...createAddonsCustomProcedures({ getCustomActionRegistry: () => registry }),
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
describe('api.addons.custom', () => {
|
|
38
|
-
let registry: CustomActionRegistry
|
|
39
|
-
let router: ReturnType<typeof buildRouter>
|
|
40
|
-
|
|
41
|
-
beforeEach(() => {
|
|
42
|
-
registry = new CustomActionRegistry()
|
|
43
|
-
registry.registerAddon('benchmark', catalog, async (action, input) => {
|
|
44
|
-
switch (action) {
|
|
45
|
-
case 'ping':
|
|
46
|
-
return 'pong'
|
|
47
|
-
case 'echo':
|
|
48
|
-
return { msg: (input as { msg: string }).msg }
|
|
49
|
-
case 'adminOnly':
|
|
50
|
-
return 'ok'
|
|
51
|
-
case 'open':
|
|
52
|
-
return 'open'
|
|
53
|
-
case 'badOutput':
|
|
54
|
-
return 'WRONG' // will fail output validation
|
|
55
|
-
default:
|
|
56
|
-
throw new Error(`unknown action ${action}`)
|
|
57
|
-
}
|
|
58
|
-
})
|
|
59
|
-
router = buildRouter(registry)
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
it('dispatches a void/literal action and returns the addon value', async () => {
|
|
63
|
-
const caller = router.createCaller(makeCtx('admin'))
|
|
64
|
-
const result = await caller.custom({ addonId: 'benchmark', action: 'ping', input: undefined })
|
|
65
|
-
expect(result).toBe('pong')
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('round-trips structured input through the action schema', async () => {
|
|
69
|
-
const caller = router.createCaller(makeCtx('admin'))
|
|
70
|
-
const result = await caller.custom({
|
|
71
|
-
addonId: 'benchmark',
|
|
72
|
-
action: 'echo',
|
|
73
|
-
input: { msg: 'hi' },
|
|
74
|
-
})
|
|
75
|
-
expect(result).toEqual({ msg: 'hi' })
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
it('rejects unknown (addonId, action) with NOT_FOUND', async () => {
|
|
79
|
-
const caller = router.createCaller(makeCtx('admin'))
|
|
80
|
-
await expect(
|
|
81
|
-
caller.custom({ addonId: 'benchmark', action: 'missing', input: {} }),
|
|
82
|
-
).rejects.toMatchObject({ code: 'NOT_FOUND' })
|
|
83
|
-
|
|
84
|
-
await expect(
|
|
85
|
-
caller.custom({ addonId: 'unknown-addon', action: 'ping', input: undefined }),
|
|
86
|
-
).rejects.toMatchObject({ code: 'NOT_FOUND' })
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('rejects unauthenticated callers with UNAUTHORIZED', async () => {
|
|
90
|
-
const caller = router.createCaller(makeCtx('anonymous'))
|
|
91
|
-
await expect(
|
|
92
|
-
caller.custom({ addonId: 'benchmark', action: 'ping', input: undefined }),
|
|
93
|
-
).rejects.toMatchObject({ code: 'UNAUTHORIZED' })
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it('enforces per-action auth: admin-only action rejects viewer', async () => {
|
|
97
|
-
const caller = router.createCaller(makeCtx('viewer'))
|
|
98
|
-
await expect(
|
|
99
|
-
caller.custom({ addonId: 'benchmark', action: 'adminOnly', input: undefined }),
|
|
100
|
-
).rejects.toMatchObject({ code: 'FORBIDDEN' })
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
it('enforces per-action auth: admin-only action allows admin', async () => {
|
|
104
|
-
const caller = router.createCaller(makeCtx('admin'))
|
|
105
|
-
const result = await caller.custom({
|
|
106
|
-
addonId: 'benchmark',
|
|
107
|
-
action: 'adminOnly',
|
|
108
|
-
input: undefined,
|
|
109
|
-
})
|
|
110
|
-
expect(result).toBe('ok')
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('rejects bad input against the action schema', async () => {
|
|
114
|
-
const caller = router.createCaller(makeCtx('admin'))
|
|
115
|
-
await expect(
|
|
116
|
-
caller.custom({ addonId: 'benchmark', action: 'echo', input: { msg: 123 } }),
|
|
117
|
-
).rejects.toBeInstanceOf(Error)
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
it('rejects bad addon output against the action schema (crash-early)', async () => {
|
|
121
|
-
const caller = router.createCaller(makeCtx('admin'))
|
|
122
|
-
await expect(
|
|
123
|
-
caller.custom({ addonId: 'benchmark', action: 'badOutput', input: undefined }),
|
|
124
|
-
).rejects.toBeInstanceOf(Error)
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
// The outer `protectedProcedure` runs before the per-action auth check, so
|
|
128
|
-
// even a `public` action requires authentication today. This documents the
|
|
129
|
-
// intentional behavior: addons cannot expose anonymous endpoints through
|
|
130
|
-
// the generic dispatcher.
|
|
131
|
-
it('the outer protectedProcedure short-circuits even for public-auth actions', async () => {
|
|
132
|
-
const caller = router.createCaller(makeCtx('anonymous'))
|
|
133
|
-
await expect(
|
|
134
|
-
caller.custom({ addonId: 'benchmark', action: 'open', input: undefined }),
|
|
135
|
-
).rejects.toMatchObject({ code: 'UNAUTHORIZED' })
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it('TRPCError carries a descriptive message for unknown actions', async () => {
|
|
139
|
-
const caller = router.createCaller(makeCtx('admin'))
|
|
140
|
-
try {
|
|
141
|
-
await caller.custom({ addonId: 'benchmark', action: 'missing', input: {} })
|
|
142
|
-
expect.fail('should have thrown')
|
|
143
|
-
} catch (err) {
|
|
144
|
-
expect(err).toBeInstanceOf(TRPCError)
|
|
145
|
-
expect((err as TRPCError).message).toMatch(/no custom action 'missing'/)
|
|
146
|
-
}
|
|
147
|
-
})
|
|
148
|
-
})
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// server/backend/src/api/__tests__/capabilities.router.test.ts
|
|
2
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
3
|
-
import { CapabilityRegistry } from '@camstack/kernel'
|
|
4
|
-
import type { IScopedLogger } from '@camstack/types'
|
|
5
|
-
|
|
6
|
-
function createMockLogger(): IScopedLogger {
|
|
7
|
-
return {
|
|
8
|
-
error: vi.fn(),
|
|
9
|
-
warn: vi.fn(),
|
|
10
|
-
info: vi.fn(),
|
|
11
|
-
debug: vi.fn(),
|
|
12
|
-
child: vi.fn().mockReturnThis(),
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
describe('capabilities tRPC router logic', () => {
|
|
17
|
-
let registry: CapabilityRegistry
|
|
18
|
-
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
registry = new CapabilityRegistry(createMockLogger())
|
|
21
|
-
registry.ready()
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('listCapabilities returns all declared capabilities', () => {
|
|
25
|
-
registry.declareCapability({ name: 'storage', scope: 'system', mode: 'singleton', methods: {} })
|
|
26
|
-
registry.declareCapability({
|
|
27
|
-
name: 'log-destination',
|
|
28
|
-
scope: 'system',
|
|
29
|
-
mode: 'collection',
|
|
30
|
-
methods: {},
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
const list = registry.listCapabilities()
|
|
34
|
-
expect(list).toHaveLength(2)
|
|
35
|
-
expect(list.map((c) => c.name)).toContain('storage')
|
|
36
|
-
expect(list.map((c) => c.name)).toContain('log-destination')
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it('setActiveSingleton throws for unknown capability', async () => {
|
|
40
|
-
await expect(registry.setActiveSingleton('nonexistent', 'some-addon', true)).rejects.toThrow(
|
|
41
|
-
/[Uu]nknown/,
|
|
42
|
-
)
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
it('setActiveSingleton throws for collection capability', async () => {
|
|
46
|
-
registry.declareCapability({
|
|
47
|
-
name: 'log-destination',
|
|
48
|
-
scope: 'system',
|
|
49
|
-
mode: 'collection',
|
|
50
|
-
methods: {},
|
|
51
|
-
})
|
|
52
|
-
await expect(registry.setActiveSingleton('log-destination', 'winston', true)).rejects.toThrow(
|
|
53
|
-
/singleton/,
|
|
54
|
-
)
|
|
55
|
-
})
|
|
56
|
-
})
|