@tx5dr/contracts 1.7.12 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/schema/__tests__/android-operator-audio.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/android-operator-audio.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/android-operator-audio.schema.test.js +27 -0
- package/dist/schema/__tests__/android-operator-audio.schema.test.js.map +1 -0
- package/dist/schema/__tests__/assisted-queue.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/assisted-queue.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/assisted-queue.schema.test.js +114 -0
- package/dist/schema/__tests__/assisted-queue.schema.test.js.map +1 -0
- package/dist/schema/__tests__/audio-sidecar.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/audio-sidecar.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/audio-sidecar.schema.test.js +42 -0
- package/dist/schema/__tests__/audio-sidecar.schema.test.js.map +1 -0
- package/dist/schema/__tests__/audio.schema.test.js +92 -1
- package/dist/schema/__tests__/audio.schema.test.js.map +1 -1
- package/dist/schema/__tests__/diagnostics.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/diagnostics.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/diagnostics.schema.test.js +31 -0
- package/dist/schema/__tests__/diagnostics.schema.test.js.map +1 -0
- package/dist/schema/__tests__/logbook-health.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/logbook-health.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/logbook-health.schema.test.js +104 -0
- package/dist/schema/__tests__/logbook-health.schema.test.js.map +1 -0
- package/dist/schema/__tests__/meter.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/meter.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/meter.schema.test.js +27 -0
- package/dist/schema/__tests__/meter.schema.test.js.map +1 -0
- package/dist/schema/__tests__/observability.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/observability.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/observability.schema.test.js +12 -0
- package/dist/schema/__tests__/observability.schema.test.js.map +1 -0
- package/dist/schema/__tests__/operator-context-report.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/operator-context-report.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/operator-context-report.schema.test.js +70 -0
- package/dist/schema/__tests__/operator-context-report.schema.test.js.map +1 -0
- package/dist/schema/__tests__/operator.schema.test.js +9 -3
- package/dist/schema/__tests__/operator.schema.test.js.map +1 -1
- package/dist/schema/__tests__/plugin-market.schema.test.js +149 -3
- package/dist/schema/__tests__/plugin-market.schema.test.js.map +1 -1
- package/dist/schema/__tests__/qso.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/qso.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/qso.schema.test.js +70 -0
- package/dist/schema/__tests__/qso.schema.test.js.map +1 -0
- package/dist/schema/__tests__/radio-power-support.test.js +15 -0
- package/dist/schema/__tests__/radio-power-support.test.js.map +1 -1
- package/dist/schema/__tests__/radio-profile.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/radio-profile.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/radio-profile.schema.test.js +36 -0
- package/dist/schema/__tests__/radio-profile.schema.test.js.map +1 -0
- package/dist/schema/__tests__/radio.schema.test.js +92 -1
- package/dist/schema/__tests__/radio.schema.test.js.map +1 -1
- package/dist/schema/__tests__/realtime-settings.schema.test.js +2 -1
- package/dist/schema/__tests__/realtime-settings.schema.test.js.map +1 -1
- package/dist/schema/__tests__/remote-access.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/remote-access.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/remote-access.schema.test.js +18 -0
- package/dist/schema/__tests__/remote-access.schema.test.js.map +1 -0
- package/dist/schema/__tests__/spectrum.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/spectrum.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/spectrum.schema.test.js +107 -0
- package/dist/schema/__tests__/spectrum.schema.test.js.map +1 -0
- package/dist/schema/__tests__/strategy-transmission.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/strategy-transmission.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/strategy-transmission.schema.test.js +95 -0
- package/dist/schema/__tests__/strategy-transmission.schema.test.js.map +1 -0
- package/dist/schema/android-operator-audio.schema.d.ts +174 -0
- package/dist/schema/android-operator-audio.schema.d.ts.map +1 -0
- package/dist/schema/android-operator-audio.schema.js +38 -0
- package/dist/schema/android-operator-audio.schema.js.map +1 -0
- package/dist/schema/api-response.schema.d.ts +503 -44
- package/dist/schema/api-response.schema.d.ts.map +1 -1
- package/dist/schema/api-response.schema.js +9 -0
- package/dist/schema/api-response.schema.js.map +1 -1
- package/dist/schema/audio-sidecar.schema.d.ts +75 -0
- package/dist/schema/audio-sidecar.schema.d.ts.map +1 -1
- package/dist/schema/audio-sidecar.schema.js +32 -0
- package/dist/schema/audio-sidecar.schema.js.map +1 -1
- package/dist/schema/audio.schema.d.ts +4749 -3
- package/dist/schema/audio.schema.d.ts.map +1 -1
- package/dist/schema/audio.schema.js +101 -2
- package/dist/schema/audio.schema.js.map +1 -1
- package/dist/schema/auth.schema.d.ts +173 -14
- package/dist/schema/auth.schema.d.ts.map +1 -1
- package/dist/schema/auth.schema.js +65 -1
- package/dist/schema/auth.schema.js.map +1 -1
- package/dist/schema/cpu-profile.schema.d.ts +2 -2
- package/dist/schema/cw-decoder.schema.d.ts +74 -74
- package/dist/schema/cw-keyer.schema.d.ts +20 -14
- package/dist/schema/cw-keyer.schema.d.ts.map +1 -1
- package/dist/schema/cw-keyer.schema.js +3 -0
- package/dist/schema/cw-keyer.schema.js.map +1 -1
- package/dist/schema/desktop-https.schema.d.ts +6 -6
- package/dist/schema/device-ui.schema.d.ts +16 -16
- package/dist/schema/diagnostics.schema.d.ts +163 -0
- package/dist/schema/diagnostics.schema.d.ts.map +1 -0
- package/dist/schema/diagnostics.schema.js +46 -0
- package/dist/schema/diagnostics.schema.js.map +1 -0
- package/dist/schema/ft8.schema.d.ts +12 -2
- package/dist/schema/ft8.schema.d.ts.map +1 -1
- package/dist/schema/ft8.schema.js +8 -0
- package/dist/schema/ft8.schema.js.map +1 -1
- package/dist/schema/image-radio.schema.d.ts +2597 -0
- package/dist/schema/image-radio.schema.d.ts.map +1 -0
- package/dist/schema/image-radio.schema.js +283 -0
- package/dist/schema/image-radio.schema.js.map +1 -0
- package/dist/schema/logbook.schema.d.ts +2128 -18
- package/dist/schema/logbook.schema.d.ts.map +1 -1
- package/dist/schema/logbook.schema.js +159 -1
- package/dist/schema/logbook.schema.js.map +1 -1
- package/dist/schema/mode.schema.d.ts +4 -6
- package/dist/schema/mode.schema.d.ts.map +1 -1
- package/dist/schema/mode.schema.js +18 -6
- package/dist/schema/mode.schema.js.map +1 -1
- package/dist/schema/observability.schema.d.ts +66 -0
- package/dist/schema/observability.schema.d.ts.map +1 -0
- package/dist/schema/observability.schema.js +20 -0
- package/dist/schema/observability.schema.js.map +1 -0
- package/dist/schema/openwebrx.schema.d.ts +2 -2
- package/dist/schema/operator.schema.d.ts +2682 -6
- package/dist/schema/operator.schema.d.ts.map +1 -1
- package/dist/schema/operator.schema.js +10 -20
- package/dist/schema/operator.schema.js.map +1 -1
- package/dist/schema/plugin.schema.d.ts +1977 -492
- package/dist/schema/plugin.schema.d.ts.map +1 -1
- package/dist/schema/plugin.schema.js +165 -14
- package/dist/schema/plugin.schema.js.map +1 -1
- package/dist/schema/process-monitor.schema.d.ts +132 -132
- package/dist/schema/pskreporter.schema.d.ts +1 -3
- package/dist/schema/pskreporter.schema.d.ts.map +1 -1
- package/dist/schema/pskreporter.schema.js +1 -3
- package/dist/schema/pskreporter.schema.js.map +1 -1
- package/dist/schema/qso.schema.d.ts +246 -1
- package/dist/schema/qso.schema.d.ts.map +1 -1
- package/dist/schema/qso.schema.js +68 -0
- package/dist/schema/qso.schema.js.map +1 -1
- package/dist/schema/radio-capability.schema.d.ts +31 -40
- package/dist/schema/radio-capability.schema.d.ts.map +1 -1
- package/dist/schema/radio-capability.schema.js +8 -15
- package/dist/schema/radio-capability.schema.js.map +1 -1
- package/dist/schema/radio-power-support.d.ts.map +1 -1
- package/dist/schema/radio-power-support.js +3 -0
- package/dist/schema/radio-power-support.js.map +1 -1
- package/dist/schema/radio-power.schema.d.ts +102 -13
- package/dist/schema/radio-power.schema.d.ts.map +1 -1
- package/dist/schema/radio-power.schema.js +15 -8
- package/dist/schema/radio-power.schema.js.map +1 -1
- package/dist/schema/radio-profile.schema.d.ts +1491 -97
- package/dist/schema/radio-profile.schema.d.ts.map +1 -1
- package/dist/schema/radio-profile.schema.js +7 -0
- package/dist/schema/radio-profile.schema.js.map +1 -1
- package/dist/schema/radio.schema.d.ts +442 -48
- package/dist/schema/radio.schema.d.ts.map +1 -1
- package/dist/schema/radio.schema.js +75 -7
- package/dist/schema/radio.schema.js.map +1 -1
- package/dist/schema/realtime.schema.d.ts +60 -52
- package/dist/schema/realtime.schema.d.ts.map +1 -1
- package/dist/schema/realtime.schema.js +9 -1
- package/dist/schema/realtime.schema.js.map +1 -1
- package/dist/schema/rigctld.schema.d.ts +6 -6
- package/dist/schema/slot-info.schema.d.ts +28 -9
- package/dist/schema/slot-info.schema.d.ts.map +1 -1
- package/dist/schema/slot-info.schema.js +17 -10
- package/dist/schema/slot-info.schema.js.map +1 -1
- package/dist/schema/spectrum-config.schema.d.ts +638 -0
- package/dist/schema/spectrum-config.schema.d.ts.map +1 -0
- package/dist/schema/spectrum-config.schema.js +129 -0
- package/dist/schema/spectrum-config.schema.js.map +1 -0
- package/dist/schema/spectrum.schema.d.ts +1323 -30
- package/dist/schema/spectrum.schema.d.ts.map +1 -1
- package/dist/schema/spectrum.schema.js +72 -0
- package/dist/schema/spectrum.schema.js.map +1 -1
- package/dist/schema/station-info.schema.d.ts +5 -0
- package/dist/schema/station-info.schema.d.ts.map +1 -1
- package/dist/schema/station-info.schema.js +5 -0
- package/dist/schema/station-info.schema.js.map +1 -1
- package/dist/schema/system.schema.d.ts +56 -6
- package/dist/schema/system.schema.d.ts.map +1 -1
- package/dist/schema/system.schema.js +22 -0
- package/dist/schema/system.schema.js.map +1 -1
- package/dist/schema/transmission.schema.d.ts +8 -7
- package/dist/schema/transmission.schema.d.ts.map +1 -1
- package/dist/schema/transmission.schema.js +2 -7
- package/dist/schema/transmission.schema.js.map +1 -1
- package/dist/schema/tx-audio-input.schema.d.ts +8 -0
- package/dist/schema/tx-audio-input.schema.d.ts.map +1 -0
- package/dist/schema/tx-audio-input.schema.js +19 -0
- package/dist/schema/tx-audio-input.schema.js.map +1 -0
- package/dist/schema/voice-keyer.schema.d.ts +16 -16
- package/dist/schema/voice.schema.d.ts +1 -1
- package/dist/schema/voice.schema.d.ts.map +1 -1
- package/dist/schema/voice.schema.js +1 -1
- package/dist/schema/voice.schema.js.map +1 -1
- package/dist/schema/websocket.schema.d.ts +35811 -7829
- package/dist/schema/websocket.schema.d.ts.map +1 -1
- package/dist/schema/websocket.schema.js +453 -9
- package/dist/schema/websocket.schema.js.map +1 -1
- package/package.json +6 -1
- package/src/index.ts +7 -0
- package/src/schema/__tests__/android-operator-audio.schema.test.ts +31 -0
- package/src/schema/__tests__/assisted-queue.schema.test.ts +122 -0
- package/src/schema/__tests__/audio-sidecar.schema.test.ts +48 -0
- package/src/schema/__tests__/audio.schema.test.ts +102 -0
- package/src/schema/__tests__/diagnostics.schema.test.ts +32 -0
- package/src/schema/__tests__/logbook-health.schema.test.ts +117 -0
- package/src/schema/__tests__/meter.schema.test.ts +28 -0
- package/src/schema/__tests__/observability.schema.test.ts +15 -0
- package/src/schema/__tests__/operator-context-report.schema.test.ts +77 -0
- package/src/schema/__tests__/operator.schema.test.ts +11 -3
- package/src/schema/__tests__/plugin-market.schema.test.ts +165 -2
- package/src/schema/__tests__/qso.schema.test.ts +91 -0
- package/src/schema/__tests__/radio-power-support.test.ts +17 -0
- package/src/schema/__tests__/radio-profile.schema.test.ts +44 -0
- package/src/schema/__tests__/radio.schema.test.ts +108 -1
- package/src/schema/__tests__/realtime-settings.schema.test.ts +2 -1
- package/src/schema/__tests__/remote-access.schema.test.ts +22 -0
- package/src/schema/__tests__/spectrum.schema.test.ts +119 -0
- package/src/schema/__tests__/strategy-transmission.schema.test.ts +106 -0
- package/src/schema/android-operator-audio.schema.ts +49 -0
- package/src/schema/api-response.schema.ts +11 -0
- package/src/schema/audio-sidecar.schema.ts +35 -0
- package/src/schema/audio.schema.ts +115 -2
- package/src/schema/auth.schema.ts +79 -1
- package/src/schema/cw-keyer.schema.ts +5 -0
- package/src/schema/diagnostics.schema.ts +55 -0
- package/src/schema/ft8.schema.ts +8 -0
- package/src/schema/image-radio.schema.ts +342 -0
- package/src/schema/logbook.schema.ts +205 -1
- package/src/schema/mode.schema.ts +18 -6
- package/src/schema/observability.schema.ts +26 -0
- package/src/schema/operator.schema.ts +11 -20
- package/src/schema/plugin.schema.ts +186 -15
- package/src/schema/pskreporter.schema.ts +1 -3
- package/src/schema/qso.schema.ts +78 -0
- package/src/schema/radio-capability.schema.ts +8 -15
- package/src/schema/radio-power-support.ts +3 -0
- package/src/schema/radio-power.schema.ts +15 -8
- package/src/schema/radio-profile.schema.ts +7 -0
- package/src/schema/radio.schema.ts +90 -7
- package/src/schema/realtime.schema.ts +9 -1
- package/src/schema/slot-info.schema.ts +18 -11
- package/src/schema/spectrum-config.schema.ts +156 -0
- package/src/schema/spectrum.schema.ts +89 -0
- package/src/schema/station-info.schema.ts +5 -0
- package/src/schema/system.schema.ts +29 -0
- package/src/schema/transmission.schema.ts +2 -7
- package/src/schema/tx-audio-input.schema.ts +22 -0
- package/src/schema/voice.schema.ts +1 -1
- package/src/schema/websocket.schema.ts +601 -13
- package/test/image-radio-schema.test.ts +107 -0
- package/test/plugin-slot-schema.test.ts +31 -0
- package/test/radio-capability-schema.test.ts +44 -0
- package/CLAUDE.md +0 -41
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
EngineModeSchema,
|
|
5
|
+
ImageRadioCapabilitySchema,
|
|
6
|
+
ImageHistoryRecordSchema,
|
|
7
|
+
ImageComposerBackgroundSchema,
|
|
8
|
+
ImagePaperBoundarySchema,
|
|
9
|
+
ImageFaxCalibrationSchema,
|
|
10
|
+
FaxCalibrationSetCommandSchema,
|
|
11
|
+
ImageReceiveProfileSchema,
|
|
12
|
+
ImageTemplateSchema,
|
|
13
|
+
SstvTxStartCommandSchema,
|
|
14
|
+
} from '../src/index.js';
|
|
15
|
+
|
|
16
|
+
describe('image radio contracts', () => {
|
|
17
|
+
it('adds image as an engine mode', () => {
|
|
18
|
+
expect(EngineModeSchema.parse('image')).toBe('image');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('keeps fax receive-only at the schema boundary', () => {
|
|
22
|
+
const base = { available: true, sstv: { rx: true, tx: true }, fax: { rx: true, tx: false } };
|
|
23
|
+
expect(ImageRadioCapabilitySchema.parse(base).fax.tx).toBe(false);
|
|
24
|
+
expect(() => ImageRadioCapabilitySchema.parse({ ...base, fax: { rx: true, tx: true } })).toThrow();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('separates automatic SSTV from fixed immediate receive profiles', () => {
|
|
28
|
+
expect(ImageReceiveProfileSchema.parse({ family: 'sstv', strategy: 'auto' })).toEqual({ family: 'sstv', strategy: 'auto' });
|
|
29
|
+
expect(ImageReceiveProfileSchema.parse({ family: 'sstv', strategy: 'manual', mode: 'robot36' }).mode).toBe('robot36');
|
|
30
|
+
expect(() => ImageReceiveProfileSchema.parse({ family: 'sstv', strategy: 'manual' })).toThrow();
|
|
31
|
+
expect(ImageReceiveProfileSchema.parse({ family: 'fax', strategy: 'auto' })).toEqual({ family: 'fax', strategy: 'auto' });
|
|
32
|
+
expect(ImageReceiveProfileSchema.parse({
|
|
33
|
+
family: 'fax', strategy: 'manual', ioc: 'ioc576', lpm: 120,
|
|
34
|
+
modulation: 'am', centerHz: 1900, deviationHz: 400,
|
|
35
|
+
}).family).toBe('fax');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('bounds templates and validates idempotent TX requests', () => {
|
|
39
|
+
const layer = { id: 'line', text: '{MYCALL}', x: 0, y: 0, width: 1, height: 0.2, fontSize: 0.1, color: '#ffffff', align: 'center' };
|
|
40
|
+
const parsedTemplate = ImageTemplateSchema.parse({ id: 'legacy', name: 'Legacy', layers: [layer], createdAt: 1, updatedAt: 1 });
|
|
41
|
+
expect(parsedTemplate.layers[0]).toMatchObject({ align: 'center', rotation: 0, strokeWidth: 0.12 });
|
|
42
|
+
expect(ImageTemplateSchema.parse({ ...parsedTemplate, layers: [{ ...parsedTemplate.layers[0], rotation: 45 }] }).layers[0].rotation).toBe(45);
|
|
43
|
+
expect(ImageTemplateSchema.parse({ ...parsedTemplate, layers: [{ ...parsedTemplate.layers[0], x: -0.5, width: 2 }] }).layers[0]).toMatchObject({ x: -0.5, width: 2 });
|
|
44
|
+
expect(() => ImageTemplateSchema.parse({ ...parsedTemplate, layers: [{ ...parsedTemplate.layers[0], rotation: 181 }] })).toThrow();
|
|
45
|
+
expect(() => ImageTemplateSchema.parse({ ...parsedTemplate, layers: [{ ...parsedTemplate.layers[0], strokeWidth: 0.51 }] })).toThrow();
|
|
46
|
+
expect(() => ImageTemplateSchema.parse({ ...parsedTemplate, layers: [{ ...parsedTemplate.layers[0], x: -2.1 }] })).toThrow();
|
|
47
|
+
expect(() => ImageTemplateSchema.parse({ id: 't', name: 'T', layers: Array.from({ length: 17 }, (_, index) => ({ ...layer, id: String(index) })), createdAt: 1, updatedAt: 1 })).toThrow();
|
|
48
|
+
expect(SstvTxStartCommandSchema.parse({ requestId: 'request-1', operatorId: 'op', artifactId: 'a', mode: 'robot36', expectedFrequency: 14_230_000 })).toMatchObject({
|
|
49
|
+
requestId: 'request-1', envelope: { enhancedPreamble: true, stationIdMode: 'fsk' },
|
|
50
|
+
});
|
|
51
|
+
expect(SstvTxStartCommandSchema.parse({ requestId: 'request-2', operatorId: 'op', artifactId: 'a', mode: 'robot36', expectedFrequency: 14_230_000, interruptActiveCapture: true }).interruptActiveCapture).toBe(true);
|
|
52
|
+
expect(SstvTxStartCommandSchema.parse({
|
|
53
|
+
requestId: 'request-3', operatorId: 'op', artifactId: 'a', mode: 'robot36', expectedFrequency: 14_230_000,
|
|
54
|
+
envelope: { enhancedPreamble: true, stationIdMode: 'cw' },
|
|
55
|
+
}).envelope).toEqual({ enhancedPreamble: true, stationIdMode: 'cw' });
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('separates received captures from real transmit history', () => {
|
|
59
|
+
expect(ImageHistoryRecordSchema.parse({
|
|
60
|
+
id: 'rx', artifactId: 'image', family: 'sstv', direction: 'rx', occurredAt: 1,
|
|
61
|
+
saveReason: 'manual', complete: false, truncated: false,
|
|
62
|
+
}).direction).toBe('rx');
|
|
63
|
+
expect(ImageHistoryRecordSchema.parse({
|
|
64
|
+
id: 'tx', artifactId: 'image', family: 'sstv', direction: 'tx', operatorId: 'op',
|
|
65
|
+
sessionId: 'session', occurredAt: 1, startedAt: 1, outcome: 'completed',
|
|
66
|
+
}).direction).toBe('tx');
|
|
67
|
+
expect(() => ImageHistoryRecordSchema.parse({
|
|
68
|
+
id: 'tx', artifactId: 'image', family: 'sstv', direction: 'tx',
|
|
69
|
+
sessionId: 'session', occurredAt: 1, startedAt: 1, outcome: 'completed',
|
|
70
|
+
})).toThrow();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('distinguishes local transmit paper segments from received content', () => {
|
|
74
|
+
const boundary = ImagePaperBoundarySchema.parse({
|
|
75
|
+
boundaryId: 'tx:start', lineIndex: 12, kind: 'localTxStart', trusted: false,
|
|
76
|
+
codecMode: 'robot36', width: 320, pixelFormat: 'rgb8', timestamp: 1,
|
|
77
|
+
source: 'localTx', txSessionId: 'tx-1',
|
|
78
|
+
});
|
|
79
|
+
expect(boundary).toMatchObject({ kind: 'localTxStart', source: 'localTx', txSessionId: 'tx-1' });
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('validates per-operator composer background metadata', () => {
|
|
83
|
+
expect(ImageComposerBackgroundSchema.parse({
|
|
84
|
+
operatorId: 'op', width: 1024, height: 512, updatedAt: 1, imageUrl: '/background.png',
|
|
85
|
+
}).operatorId).toBe('op');
|
|
86
|
+
expect(() => ImageComposerBackgroundSchema.parse({
|
|
87
|
+
operatorId: '', width: 1024, height: 512, updatedAt: 1, imageUrl: '/background.png',
|
|
88
|
+
})).toThrow();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('bounds FAX calibration commands and control points', () => {
|
|
92
|
+
const calibration = ImageFaxCalibrationSchema.parse({
|
|
93
|
+
boundaryId: 'fax:1', revision: 2, autoEnabled: true,
|
|
94
|
+
autoPoints: [{ revision: 1, referenceLine: 10, phasePixels: 2, clockPpm: 25, confidence: 0.8, source: 'phasing', status: 'locked' }],
|
|
95
|
+
manualPhasePixels: 0, manualClockPpm: 0, updatedAt: 1,
|
|
96
|
+
});
|
|
97
|
+
expect(calibration.autoPoints[0].clockPpm).toBe(25);
|
|
98
|
+
expect(FaxCalibrationSetCommandSchema.parse({
|
|
99
|
+
requestId: 'r', operatorId: 'op', sessionId: 's', boundaryId: 'fax:1', expectedRevision: 2,
|
|
100
|
+
autoEnabled: true, phasePixels: 10, clockPpm: 5000,
|
|
101
|
+
}).clockPpm).toBe(5000);
|
|
102
|
+
expect(() => FaxCalibrationSetCommandSchema.parse({
|
|
103
|
+
requestId: 'r', operatorId: 'op', sessionId: 's', boundaryId: 'fax:1', expectedRevision: 2,
|
|
104
|
+
autoEnabled: true, phasePixels: 10, clockPpm: 5001,
|
|
105
|
+
})).toThrow();
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -5,6 +5,7 @@ describe('PluginPanelSlotSchema', () => {
|
|
|
5
5
|
it('accepts every supported plugin panel slot', () => {
|
|
6
6
|
expect(PluginPanelSlotSchema.parse('operator')).toBe('operator');
|
|
7
7
|
expect(PluginPanelSlotSchema.parse('automation')).toBe('automation');
|
|
8
|
+
expect(PluginPanelSlotSchema.parse('operator-action')).toBe('operator-action');
|
|
8
9
|
expect(PluginPanelSlotSchema.parse('main-right')).toBe('main-right');
|
|
9
10
|
expect(PluginPanelSlotSchema.parse('voice-left-top')).toBe('voice-left-top');
|
|
10
11
|
expect(PluginPanelSlotSchema.parse('voice-right-top')).toBe('voice-right-top');
|
|
@@ -13,6 +14,27 @@ describe('PluginPanelSlotSchema', () => {
|
|
|
13
14
|
expect(PluginPanelSlotSchema.parse('radio-control-toolbar')).toBe('radio-control-toolbar');
|
|
14
15
|
});
|
|
15
16
|
|
|
17
|
+
it('requires operator action entries to open an iframe page', () => {
|
|
18
|
+
expect(PluginPanelDescriptorSchema.parse({
|
|
19
|
+
id: 'contest-log',
|
|
20
|
+
title: 'Contest log',
|
|
21
|
+
component: 'iframe',
|
|
22
|
+
pageId: 'contest-log',
|
|
23
|
+
slot: 'operator-action',
|
|
24
|
+
openMode: 'page',
|
|
25
|
+
icon: 'file-lines',
|
|
26
|
+
})).toMatchObject({ slot: 'operator-action', openMode: 'page' });
|
|
27
|
+
|
|
28
|
+
expect(() => PluginPanelDescriptorSchema.parse({
|
|
29
|
+
id: 'embedded-action',
|
|
30
|
+
title: 'Embedded',
|
|
31
|
+
component: 'iframe',
|
|
32
|
+
pageId: 'embedded',
|
|
33
|
+
slot: 'operator-action',
|
|
34
|
+
openMode: 'modal',
|
|
35
|
+
})).toThrow('operator-action panels must use page openMode');
|
|
36
|
+
});
|
|
37
|
+
|
|
16
38
|
it('validates iframe panels declared in the new host slots', () => {
|
|
17
39
|
expect(() => PluginPanelDescriptorSchema.parse({
|
|
18
40
|
id: 'main-pane',
|
|
@@ -56,6 +78,15 @@ describe('PluginPanelSlotSchema', () => {
|
|
|
56
78
|
uiSize: 'lg',
|
|
57
79
|
});
|
|
58
80
|
|
|
81
|
+
expect(PluginPanelDescriptorSchema.parse({
|
|
82
|
+
id: 'standalone-log',
|
|
83
|
+
title: 'Log',
|
|
84
|
+
component: 'iframe',
|
|
85
|
+
pageId: 'log',
|
|
86
|
+
slot: 'radio-control-toolbar',
|
|
87
|
+
openMode: 'page',
|
|
88
|
+
})).toMatchObject({ openMode: 'page' });
|
|
89
|
+
|
|
59
90
|
expect(() => PluginPanelDescriptorSchema.parse({
|
|
60
91
|
id: 'bad-toolbar',
|
|
61
92
|
title: 'Bad',
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
CAPABILITY_IDS,
|
|
4
|
+
CapabilityDescriptorSchema,
|
|
5
|
+
CapabilityStateSchema,
|
|
6
|
+
type CapabilityId,
|
|
7
|
+
} from '../src/schema/radio-capability.schema';
|
|
8
|
+
|
|
9
|
+
describe('CAPABILITY_IDS', () => {
|
|
10
|
+
it('includes radio_mode for dynamic voice radio mode discovery', () => {
|
|
11
|
+
const id: CapabilityId = 'radio_mode';
|
|
12
|
+
|
|
13
|
+
expect(CAPABILITY_IDS).toContain(id);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('accepts radio_mode as an enum capability descriptor and state', () => {
|
|
17
|
+
expect(CapabilityDescriptorSchema.parse({
|
|
18
|
+
id: 'radio_mode',
|
|
19
|
+
category: 'operation',
|
|
20
|
+
valueType: 'enum',
|
|
21
|
+
options: [{ value: 'USB' }, { value: 'WFM' }],
|
|
22
|
+
readable: true,
|
|
23
|
+
writable: false,
|
|
24
|
+
updateMode: 'polling',
|
|
25
|
+
labelI18nKey: 'radio:capability.radio_mode.label',
|
|
26
|
+
hasSurfaceControl: false,
|
|
27
|
+
})).toMatchObject({
|
|
28
|
+
id: 'radio_mode',
|
|
29
|
+
valueType: 'enum',
|
|
30
|
+
options: [{ value: 'USB' }, { value: 'WFM' }],
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
expect(CapabilityStateSchema.parse({
|
|
34
|
+
id: 'radio_mode',
|
|
35
|
+
supported: true,
|
|
36
|
+
value: 'WFM',
|
|
37
|
+
updatedAt: 1,
|
|
38
|
+
})).toMatchObject({
|
|
39
|
+
id: 'radio_mode',
|
|
40
|
+
supported: true,
|
|
41
|
+
value: 'WFM',
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
});
|
package/CLAUDE.md
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# CLAUDE.md - Contracts
|
|
2
|
-
|
|
3
|
-
Zod Schema 和 TypeScript 类型定义包,为整个 TX-5DR 系统提供数据契约。
|
|
4
|
-
|
|
5
|
-
## 核心文件
|
|
6
|
-
- **websocket.schema.ts**: WebSocket 消息类型
|
|
7
|
-
- **radio/audio.schema.ts**: 电台和音频控制
|
|
8
|
-
- **ft8/operator.schema.ts**: FT8 消息和操作员
|
|
9
|
-
- **logbook/qso.schema.ts**: 日志本和联络记录
|
|
10
|
-
- **其他**: slot-info, mode, cycle, hello
|
|
11
|
-
|
|
12
|
-
## 开发规范
|
|
13
|
-
|
|
14
|
-
### 新增 Schema
|
|
15
|
-
1. `src/schema/` 创建 `.schema.ts` 文件
|
|
16
|
-
2. 定义 Zod Schema:
|
|
17
|
-
```typescript
|
|
18
|
-
export const DataSchema = z.object({
|
|
19
|
-
id: z.string(),
|
|
20
|
-
value: z.number().optional(),
|
|
21
|
-
});
|
|
22
|
-
export type Data = z.infer<typeof DataSchema>;
|
|
23
|
-
```
|
|
24
|
-
3. `src/index.ts` 导出
|
|
25
|
-
4. `yarn build` 生成类型
|
|
26
|
-
|
|
27
|
-
### WebSocket 消息
|
|
28
|
-
```typescript
|
|
29
|
-
export const WSMessageType = {
|
|
30
|
-
COMMAND_NAME: 'command_name', // 客户端→服务端
|
|
31
|
-
EVENT_NAME: 'event_name', // 服务端→客户端
|
|
32
|
-
} as const;
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### 设计原则
|
|
36
|
-
- 严格验证,新字段用 `.optional()` 保证兼容性
|
|
37
|
-
- 复用现有 Schema,避免重复定义
|
|
38
|
-
- 使用语义化的命名
|
|
39
|
-
|
|
40
|
-
## 命令
|
|
41
|
-
`yarn build` - 构建类型定义
|