@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
|
@@ -1,5 +1,70 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { PresetFrequencySchema } from '../radio.schema.js';
|
|
2
|
+
import { DdsFrequencyRequestSchema, DigitalModeRadioModePreferenceSchema, HamlibConfigSchema, PresetFrequencySchema, RadioInfoSchema } from '../radio.schema.js';
|
|
3
|
+
|
|
4
|
+
describe('HamlibConfigSchema digital mode radio mode preference', () => {
|
|
5
|
+
it('accepts legacy configs without a digital mode radio mode preference', () => {
|
|
6
|
+
const parsed = HamlibConfigSchema.parse({ type: 'none' });
|
|
7
|
+
|
|
8
|
+
expect(parsed.digitalModeRadioMode).toBeUndefined();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('accepts supported FT8/FT4 radio mode preferences', () => {
|
|
12
|
+
expect(DigitalModeRadioModePreferenceSchema.parse('none')).toBe('none');
|
|
13
|
+
expect(DigitalModeRadioModePreferenceSchema.parse('usb')).toBe('usb');
|
|
14
|
+
expect(DigitalModeRadioModePreferenceSchema.parse('usb-data')).toBe('usb-data');
|
|
15
|
+
expect(HamlibConfigSchema.parse({ type: 'serial', digitalModeRadioMode: 'usb-data' }).digitalModeRadioMode).toBe('usb-data');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('rejects invalid FT8/FT4 radio mode preferences', () => {
|
|
19
|
+
expect(() => HamlibConfigSchema.parse({ type: 'none', digitalModeRadioMode: 'lsb-data' })).toThrow();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('HamlibConfigSchema TCI connection', () => {
|
|
24
|
+
it('accepts TCI configs and applies SunSDR defaults', () => {
|
|
25
|
+
const parsed = HamlibConfigSchema.parse({
|
|
26
|
+
type: 'tci',
|
|
27
|
+
tci: {},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
expect(parsed.tci).toMatchObject({
|
|
31
|
+
host: '127.0.0.1',
|
|
32
|
+
port: 40001,
|
|
33
|
+
receiver: 0,
|
|
34
|
+
trx: 0,
|
|
35
|
+
vfo: 0,
|
|
36
|
+
audioEnabled: true,
|
|
37
|
+
audioSampleRate: 12000,
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('accepts only credential-free WebSocket URLs for TCI', () => {
|
|
42
|
+
expect(() => HamlibConfigSchema.parse({ type: 'tci', tci: { url: 'wss://radio.example/tci' } })).not.toThrow();
|
|
43
|
+
expect(() => HamlibConfigSchema.parse({ type: 'tci', tci: { url: 'https://radio.example/tci' } })).toThrow();
|
|
44
|
+
expect(() => HamlibConfigSchema.parse({ type: 'tci', tci: { url: 'ws://user:secret@radio.example/tci' } })).toThrow();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('accepts TCI as a reported radio connection type', () => {
|
|
48
|
+
const parsed = RadioInfoSchema.parse({
|
|
49
|
+
manufacturer: 'Expert Electronics',
|
|
50
|
+
model: 'SunSDR',
|
|
51
|
+
connectionType: 'tci',
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
expect(parsed.connectionType).toBe('tci');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('DdsFrequencyRequestSchema', () => {
|
|
59
|
+
it('accepts non-negative center frequency and receiver values', () => {
|
|
60
|
+
expect(DdsFrequencyRequestSchema.parse({ frequency: 14_075_000, receiver: 0 })).toEqual({ frequency: 14_075_000, receiver: 0 });
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('rejects invalid center frequency and receiver values', () => {
|
|
64
|
+
expect(() => DdsFrequencyRequestSchema.parse({ frequency: -1 })).toThrow();
|
|
65
|
+
expect(() => DdsFrequencyRequestSchema.parse({ frequency: 14_075_000, receiver: 0.5 })).toThrow();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
3
68
|
|
|
4
69
|
describe('PresetFrequencySchema repeater DUP fields', () => {
|
|
5
70
|
it('accepts existing presets without repeater DUP fields', () => {
|
|
@@ -71,6 +136,48 @@ describe('PresetFrequencySchema repeater DUP fields', () => {
|
|
|
71
136
|
});
|
|
72
137
|
});
|
|
73
138
|
|
|
139
|
+
describe('PresetFrequencySchema dial frequency precision', () => {
|
|
140
|
+
it('accepts integer-Hz presets represented by up to six MHz decimal places', () => {
|
|
141
|
+
const parsed = PresetFrequencySchema.parse({
|
|
142
|
+
band: '4MHz',
|
|
143
|
+
mode: 'FAX',
|
|
144
|
+
radioMode: 'USB',
|
|
145
|
+
frequency: 4_233_100,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
expect(parsed.frequency).toBe(4_233_100);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('accepts marine FAX assigned-frequency and emission metadata', () => {
|
|
152
|
+
const parsed = PresetFrequencySchema.parse({
|
|
153
|
+
band: '4MHz',
|
|
154
|
+
mode: 'FAX',
|
|
155
|
+
radioMode: 'USB',
|
|
156
|
+
frequency: 4_197_850,
|
|
157
|
+
assignedFrequency: 4_199_750,
|
|
158
|
+
audioCenterHz: 1_900,
|
|
159
|
+
faxEmission: 'F3C',
|
|
160
|
+
imagePurpose: 'weatherfax',
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
expect(parsed.assignedFrequency).toBe(4_199_750);
|
|
164
|
+
expect(parsed.faxEmission).toBe('F3C');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('rejects fractional-Hz and out-of-range preset frequencies', () => {
|
|
168
|
+
expect(() => PresetFrequencySchema.parse({
|
|
169
|
+
band: '20m',
|
|
170
|
+
mode: 'SSTV',
|
|
171
|
+
frequency: 14_230_000.5,
|
|
172
|
+
})).toThrow();
|
|
173
|
+
expect(() => PresetFrequencySchema.parse({
|
|
174
|
+
band: 'custom',
|
|
175
|
+
mode: 'VOICE',
|
|
176
|
+
frequency: 1_000_000_001,
|
|
177
|
+
})).toThrow();
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
74
181
|
describe('PresetFrequencySchema tone squelch fields', () => {
|
|
75
182
|
it('accepts CTCSS tone presets with positive 0.1 Hz values', () => {
|
|
76
183
|
const parsed = PresetFrequencySchema.parse({
|
|
@@ -9,9 +9,10 @@ import {
|
|
|
9
9
|
} from '../realtime.schema.js';
|
|
10
10
|
|
|
11
11
|
describe('Realtime transport schemas', () => {
|
|
12
|
-
it('accepts
|
|
12
|
+
it('accepts realtime network transports plus the Android native diagnostics transport', () => {
|
|
13
13
|
expect(RealtimeTransportKindSchema.parse('rtc-data-audio')).toBe('rtc-data-audio');
|
|
14
14
|
expect(RealtimeTransportKindSchema.parse('ws-compat')).toBe('ws-compat');
|
|
15
|
+
expect(RealtimeTransportKindSchema.parse('android-native')).toBe('android-native');
|
|
15
16
|
const retiredTransport = 'live' + 'kit';
|
|
16
17
|
expect(() => RealtimeTransportKindSchema.parse(retiredTransport)).toThrow();
|
|
17
18
|
expect(() => RealtimeSessionRequestSchema.parse({
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
isSecureRemoteAccessOrigin,
|
|
4
|
+
normalizeRemoteAccessOrigin,
|
|
5
|
+
} from '../auth.schema.js';
|
|
6
|
+
|
|
7
|
+
describe('remote access origins', () => {
|
|
8
|
+
it('normalizes exact browser origins and rejects paths or credentials', () => {
|
|
9
|
+
expect(normalizeRemoteAccessOrigin('https://radio.example.com/')).toBe('https://radio.example.com');
|
|
10
|
+
expect(normalizeRemoteAccessOrigin('http://10.8.0.2:8076')).toBe('http://10.8.0.2:8076');
|
|
11
|
+
expect(normalizeRemoteAccessOrigin('https://radio.example.com/tx5dr')).toBeNull();
|
|
12
|
+
expect(normalizeRemoteAccessOrigin('https://user:pass@radio.example.com')).toBeNull();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('identifies origins with transport security without enforcing public-access policy', () => {
|
|
16
|
+
expect(isSecureRemoteAccessOrigin('https://radio.example.com')).toBe(true);
|
|
17
|
+
expect(isSecureRemoteAccessOrigin('http://radio.example.com')).toBe(false);
|
|
18
|
+
expect(isSecureRemoteAccessOrigin('http://203.0.113.10:8076')).toBe(false);
|
|
19
|
+
expect(isSecureRemoteAccessOrigin('http://192.168.1.20:8076')).toBe(true);
|
|
20
|
+
expect(isSecureRemoteAccessOrigin('http://100.64.0.2:8076')).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { SpectrumFrameSchema, SpectrumLevelDescriptorSchema, SpectrumSessionInteractionStateSchema } from '../spectrum.schema.js';
|
|
3
|
+
import {
|
|
4
|
+
SpectrumSettingsResponseSchema,
|
|
5
|
+
SpectrumSettingsUpdateRequestSchema,
|
|
6
|
+
TciSpectrumSettingsSchema,
|
|
7
|
+
getSpectrumPresetDefinition,
|
|
8
|
+
} from '../spectrum-config.schema.js';
|
|
9
|
+
|
|
10
|
+
describe('spectrum level descriptor schema', () => {
|
|
11
|
+
it('accepts dBFS, calibrated dB and raw Level descriptors', () => {
|
|
12
|
+
for (const level of [
|
|
13
|
+
{ domain: 'dbfs', unit: 'dBFS', reference: 'full-scale', calibrated: true, min: -120, max: 0 },
|
|
14
|
+
{ domain: 'calibrated-db', unit: 'dB', reference: 'device', calibrated: true, min: -130, max: 10 },
|
|
15
|
+
{ domain: 'raw', unit: 'Level', reference: 'none', calibrated: false, min: 0, max: 255 },
|
|
16
|
+
]) {
|
|
17
|
+
expect(SpectrumLevelDescriptorSchema.safeParse(level).success).toBe(true);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('rejects invalid or non-increasing level ranges', () => {
|
|
22
|
+
expect(SpectrumLevelDescriptorSchema.safeParse({
|
|
23
|
+
domain: 'raw',
|
|
24
|
+
unit: 'dBFS',
|
|
25
|
+
reference: 'none',
|
|
26
|
+
calibrated: false,
|
|
27
|
+
min: 255,
|
|
28
|
+
max: 0,
|
|
29
|
+
}).success).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('keeps level optional for old spectrum frames', () => {
|
|
33
|
+
const result = SpectrumFrameSchema.safeParse({
|
|
34
|
+
timestamp: 1,
|
|
35
|
+
kind: 'radio-sdr',
|
|
36
|
+
frequencyRange: { min: 7_000_000, max: 7_100_000 },
|
|
37
|
+
binaryData: {
|
|
38
|
+
data: 'AA==',
|
|
39
|
+
format: { type: 'int16', length: 1 },
|
|
40
|
+
},
|
|
41
|
+
meta: {
|
|
42
|
+
sourceBinCount: 1,
|
|
43
|
+
displayBinCount: 1,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
expect(result.success).toBe(true);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('defaults legacy interaction state to radio-center and accepts split TX targets', () => {
|
|
50
|
+
const interaction = SpectrumSessionInteractionStateSchema.parse({
|
|
51
|
+
showTxMarkers: false,
|
|
52
|
+
showRxMarkers: false,
|
|
53
|
+
canDragTx: false,
|
|
54
|
+
canRightClickSetFrequency: false,
|
|
55
|
+
canDoubleClickSetFrequency: false,
|
|
56
|
+
canDragFrequency: false,
|
|
57
|
+
frequencyGestureTarget: null,
|
|
58
|
+
frequencyStepHz: null,
|
|
59
|
+
presetMarkers: [],
|
|
60
|
+
frequencyOverlays: [{
|
|
61
|
+
id: 'split',
|
|
62
|
+
label: 'TX',
|
|
63
|
+
lineFrequency: 14_052_500,
|
|
64
|
+
rangeStartFrequency: 14_052_500,
|
|
65
|
+
rangeEndFrequency: 14_052_500,
|
|
66
|
+
variant: 'tx',
|
|
67
|
+
draggable: true,
|
|
68
|
+
frequencyTarget: 'split-frequency',
|
|
69
|
+
}],
|
|
70
|
+
canDragVoiceOverlay: false,
|
|
71
|
+
showVoiceOverlay: false,
|
|
72
|
+
canLocalViewportZoom: false,
|
|
73
|
+
canLocalViewportPan: false,
|
|
74
|
+
supportsManualRange: true,
|
|
75
|
+
supportsAutoRange: false,
|
|
76
|
+
defaultRangeMode: 'manual',
|
|
77
|
+
});
|
|
78
|
+
expect(interaction.viewMode).toBe('radio-center');
|
|
79
|
+
expect(interaction.viewport.enabled).toBe(false);
|
|
80
|
+
expect(interaction.frequencyOverlays[0]?.frequencyTarget).toBe('split-frequency');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('spectrum analysis settings schemas', () => {
|
|
85
|
+
it('validates preset updates and derived render settings', () => {
|
|
86
|
+
expect(SpectrumSettingsUpdateRequestSchema.parse({ preset: 'fine' })).toEqual({ preset: 'fine' });
|
|
87
|
+
const balanced = getSpectrumPresetDefinition('balanced');
|
|
88
|
+
expect(SpectrumSettingsResponseSchema.parse({
|
|
89
|
+
success: true,
|
|
90
|
+
currentSettings: { ...balanced, revision: 3 },
|
|
91
|
+
presets: [getSpectrumPresetDefinition('responsive'), balanced, getSpectrumPresetDefinition('fine')],
|
|
92
|
+
}).currentSettings.displayBinCount).toBe(4097);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('rejects arbitrary analysis parameters', () => {
|
|
96
|
+
expect(() => SpectrumSettingsUpdateRequestSchema.parse({ preset: 'custom', fftSize: 4096 })).toThrow();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('accepts a validated custom analysis draft', () => {
|
|
100
|
+
expect(SpectrumSettingsUpdateRequestSchema.parse({
|
|
101
|
+
preset: 'custom',
|
|
102
|
+
settings: {
|
|
103
|
+
analysisIntervalMs: 275,
|
|
104
|
+
fftSize: 4096,
|
|
105
|
+
targetSampleRate: 8000,
|
|
106
|
+
windowFunction: 'hann',
|
|
107
|
+
haloReduce: true,
|
|
108
|
+
},
|
|
109
|
+
}).preset).toBe('custom');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('accepts high-performance TCI analysis settings within the supported bounds', () => {
|
|
113
|
+
expect(TciSpectrumSettingsSchema.parse({
|
|
114
|
+
fftSize: 65536,
|
|
115
|
+
displayBinCount: 16384,
|
|
116
|
+
analysisIntervalMs: 20,
|
|
117
|
+
})).toEqual({ fftSize: 65536, displayBinCount: 16384, analysisIntervalMs: 20 });
|
|
118
|
+
});
|
|
119
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
OperatorStatusSchema,
|
|
4
|
+
StrategyStreamSnapshotSchema,
|
|
5
|
+
StrategyTransmissionSchema,
|
|
6
|
+
WSMessageSchema,
|
|
7
|
+
} from '../../index.js';
|
|
8
|
+
|
|
9
|
+
describe('strategy transmission contracts', () => {
|
|
10
|
+
it('carries the current multi-stream transmission set in operator status', () => {
|
|
11
|
+
const currentTransmissions = [
|
|
12
|
+
{ streamId: 'stream-1', text: 'JA1AAA BG5DRB OL32', audioFrequencyHz: 1200 },
|
|
13
|
+
{ streamId: 'stream-2', text: 'JA2BBB BG5DRB R PM95', audioFrequencyHz: 1320 },
|
|
14
|
+
{ streamId: 'stream-3', text: 'JA3CCC BG5DRB RR73', audioFrequencyHz: 1440 },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
expect(StrategyTransmissionSchema.parse(currentTransmissions[0])).toEqual(currentTransmissions[0]);
|
|
18
|
+
expect(OperatorStatusSchema.parse({
|
|
19
|
+
id: 'operator-1',
|
|
20
|
+
isActive: true,
|
|
21
|
+
isTransmitting: true,
|
|
22
|
+
hasTransmitIntent: true,
|
|
23
|
+
currentTransmissions,
|
|
24
|
+
currentSlot: 'parallel',
|
|
25
|
+
context: {
|
|
26
|
+
myCall: 'BG5DRB',
|
|
27
|
+
myGrid: 'OL32',
|
|
28
|
+
targetCalls: ['JA1AAA', 'JA2BBB', 'JA3CCC'],
|
|
29
|
+
targetCall: 'JA1AAA',
|
|
30
|
+
},
|
|
31
|
+
strategy: {
|
|
32
|
+
name: 'ww-digi',
|
|
33
|
+
state: 'parallel',
|
|
34
|
+
availableSlots: ['TX6'],
|
|
35
|
+
},
|
|
36
|
+
})).toMatchObject({
|
|
37
|
+
currentTransmissions,
|
|
38
|
+
context: { targetCalls: ['JA1AAA', 'JA2BBB', 'JA3CCC'] },
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('rejects empty text and invalid audio frequencies', () => {
|
|
43
|
+
expect(StrategyTransmissionSchema.safeParse({
|
|
44
|
+
streamId: 'stream-1',
|
|
45
|
+
text: '',
|
|
46
|
+
audioFrequencyHz: 1200,
|
|
47
|
+
}).success).toBe(false);
|
|
48
|
+
expect(StrategyTransmissionSchema.safeParse({
|
|
49
|
+
streamId: 'stream-1',
|
|
50
|
+
text: 'CQ WW BG5DRB OL32',
|
|
51
|
+
audioFrequencyHz: 5001,
|
|
52
|
+
}).success).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('accepts strategy-defined stream states and a lifecycle-scoped switch command', () => {
|
|
56
|
+
expect(StrategyStreamSnapshotSchema.parse({
|
|
57
|
+
streamId: 'stream-7',
|
|
58
|
+
currentState: 'awaiting-confirmation',
|
|
59
|
+
audioFrequencyHz: 1320,
|
|
60
|
+
qsoLifecycleEpoch: 4,
|
|
61
|
+
stateOptions: [{
|
|
62
|
+
id: 'send-final',
|
|
63
|
+
label: 'stateSendFinal',
|
|
64
|
+
transmitText: 'JA1AAA BG5DRB RR73',
|
|
65
|
+
}],
|
|
66
|
+
}).stateOptions?.[0]?.id).toBe('send-final');
|
|
67
|
+
|
|
68
|
+
expect(WSMessageSchema.parse({
|
|
69
|
+
type: 'setOperatorStreamState',
|
|
70
|
+
timestamp: new Date().toISOString(),
|
|
71
|
+
data: {
|
|
72
|
+
operatorId: 'operator-1',
|
|
73
|
+
streamId: 'stream-7',
|
|
74
|
+
stateId: 'send-final',
|
|
75
|
+
expectedLifecycleEpoch: 4,
|
|
76
|
+
},
|
|
77
|
+
}).type).toBe('setOperatorStreamState');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('accepts plugin-declared actions and lifecycle-scoped action invocations', () => {
|
|
81
|
+
const stream = StrategyStreamSnapshotSchema.parse({
|
|
82
|
+
streamId: 'stream-1',
|
|
83
|
+
currentState: 'recovering',
|
|
84
|
+
audioFrequencyHz: 1500,
|
|
85
|
+
qsoLifecycleEpoch: 7,
|
|
86
|
+
completion: { state: 'committed', recordId: 'qso-1' },
|
|
87
|
+
attentions: [{ id: 'needs-action', tone: 'warning', title: 'attentionTitle', actionIds: ['reply'] }],
|
|
88
|
+
actions: [{
|
|
89
|
+
id: 'reply', label: 'replyLabel', icon: 'paper-plane', tone: 'primary', presentation: 'primary',
|
|
90
|
+
input: { kind: 'audio-frequency', value: 1500, min: 100, max: 5000, step: 10, spectrumPick: true },
|
|
91
|
+
}],
|
|
92
|
+
});
|
|
93
|
+
expect(stream.actions?.[0]?.id).toBe('reply');
|
|
94
|
+
|
|
95
|
+
expect(WSMessageSchema.parse({
|
|
96
|
+
type: 'invokeOperatorStrategyAction',
|
|
97
|
+
timestamp: new Date().toISOString(),
|
|
98
|
+
data: {
|
|
99
|
+
operatorId: 'operator-1',
|
|
100
|
+
target: { kind: 'stream', streamId: 'stream-1', lifecycleEpoch: 7 },
|
|
101
|
+
actionId: 'reply',
|
|
102
|
+
payload: { value: 1600 },
|
|
103
|
+
},
|
|
104
|
+
}).type).toBe('invokeOperatorStrategyAction');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const AndroidOperatorAudioDeviceSchema = z.object({
|
|
4
|
+
id: z.string(),
|
|
5
|
+
name: z.string(),
|
|
6
|
+
kind: z.string(),
|
|
7
|
+
socketPath: z.string(),
|
|
8
|
+
sampleRate: z.number().int().positive(),
|
|
9
|
+
connected: z.boolean().optional(),
|
|
10
|
+
});
|
|
11
|
+
export type AndroidOperatorAudioDevice = z.infer<typeof AndroidOperatorAudioDeviceSchema>;
|
|
12
|
+
|
|
13
|
+
export const AndroidOperatorAudioCaptureStateSchema = z.enum(['idle', 'preparing', 'capturing', 'error']);
|
|
14
|
+
export type AndroidOperatorAudioCaptureState = z.infer<typeof AndroidOperatorAudioCaptureStateSchema>;
|
|
15
|
+
|
|
16
|
+
export const AndroidOperatorAudioMonitorStateSchema = z.enum(['idle', 'starting', 'playing', 'paused-for-ptt', 'error']);
|
|
17
|
+
export type AndroidOperatorAudioMonitorState = z.infer<typeof AndroidOperatorAudioMonitorStateSchema>;
|
|
18
|
+
|
|
19
|
+
export const AndroidOperatorAudioStatusSchema = z.object({
|
|
20
|
+
available: z.boolean(),
|
|
21
|
+
captureState: AndroidOperatorAudioCaptureStateSchema,
|
|
22
|
+
monitorState: AndroidOperatorAudioMonitorStateSchema,
|
|
23
|
+
participantIdentity: z.string().nullable(),
|
|
24
|
+
inputLevel: z.number().min(0).max(1),
|
|
25
|
+
inputPeak: z.number().min(0).max(1),
|
|
26
|
+
rawInputLevel: z.number().min(0).max(1).optional(),
|
|
27
|
+
rawInputPeak: z.number().min(0).max(1).optional(),
|
|
28
|
+
inputSilenced: z.boolean(),
|
|
29
|
+
micGainDb: z.number(),
|
|
30
|
+
micGainMinDb: z.number(),
|
|
31
|
+
micGainMaxDb: z.number(),
|
|
32
|
+
monitorGainDb: z.number(),
|
|
33
|
+
monitorGainMinDb: z.number(),
|
|
34
|
+
monitorGainMaxDb: z.number(),
|
|
35
|
+
micDevice: AndroidOperatorAudioDeviceSchema.nullable(),
|
|
36
|
+
speakerDevice: AndroidOperatorAudioDeviceSchema.nullable(),
|
|
37
|
+
lastError: z.string().nullable(),
|
|
38
|
+
});
|
|
39
|
+
export type AndroidOperatorAudioStatus = z.infer<typeof AndroidOperatorAudioStatusSchema>;
|
|
40
|
+
|
|
41
|
+
export const AndroidOperatorAudioGainUpdateSchema = z.object({
|
|
42
|
+
micGainDb: z.number(),
|
|
43
|
+
});
|
|
44
|
+
export type AndroidOperatorAudioGainUpdate = z.infer<typeof AndroidOperatorAudioGainUpdateSchema>;
|
|
45
|
+
|
|
46
|
+
export const AndroidOperatorAudioMonitorGainUpdateSchema = z.object({
|
|
47
|
+
monitorGainDb: z.number(),
|
|
48
|
+
});
|
|
49
|
+
export type AndroidOperatorAudioMonitorGainUpdate = z.infer<typeof AndroidOperatorAudioMonitorGainUpdateSchema>;
|
|
@@ -132,6 +132,7 @@ export const LastFrequencyResponseSchema = z.object({
|
|
|
132
132
|
band: z.string(),
|
|
133
133
|
description: z.string().optional(),
|
|
134
134
|
}).nullable().optional(),
|
|
135
|
+
lastImageFrequency: PresetFrequencySchema.nullable().optional(),
|
|
135
136
|
});
|
|
136
137
|
|
|
137
138
|
/**
|
|
@@ -150,6 +151,15 @@ export const SetFrequencyResponseSchema = z.object({
|
|
|
150
151
|
ctcssToneTenthsHz: z.number().optional(),
|
|
151
152
|
dcsCode: z.number().optional(),
|
|
152
153
|
radioConnected: z.boolean().optional(),
|
|
154
|
+
confirmation: z.enum(['confirmed', 'pending', 'mismatch', 'offline']).optional(),
|
|
155
|
+
observedFrequency: z.number().optional(),
|
|
156
|
+
operationId: z.string().optional(),
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
export const SetDdsFrequencyResponseSchema = z.object({
|
|
160
|
+
success: z.literal(true),
|
|
161
|
+
frequency: z.number(),
|
|
162
|
+
receiver: z.number().int().nonnegative(),
|
|
153
163
|
});
|
|
154
164
|
|
|
155
165
|
// ========== 时隙包相关响应 ==========
|
|
@@ -203,6 +213,7 @@ export type DisconnectRadioResponse = z.infer<typeof DisconnectRadioResponseSche
|
|
|
203
213
|
|
|
204
214
|
export type LastFrequencyResponse = z.infer<typeof LastFrequencyResponseSchema>;
|
|
205
215
|
export type SetFrequencyResponse = z.infer<typeof SetFrequencyResponseSchema>;
|
|
216
|
+
export type SetDdsFrequencyResponse = z.infer<typeof SetDdsFrequencyResponseSchema>;
|
|
206
217
|
|
|
207
218
|
export type SlotPacksResponse = z.infer<typeof SlotPacksResponseSchema>;
|
|
208
219
|
export type SlotPackResponse = z.infer<typeof SlotPackResponseSchema>;
|
|
@@ -29,6 +29,29 @@ export const AudioSidecarErrorSchema = z.object({
|
|
|
29
29
|
|
|
30
30
|
export type AudioSidecarError = z.infer<typeof AudioSidecarErrorSchema>;
|
|
31
31
|
|
|
32
|
+
export const AudioSidecarPhaseSchema = z.enum([
|
|
33
|
+
'startStream',
|
|
34
|
+
'startOutput',
|
|
35
|
+
'runtime',
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
export const AudioSidecarClassificationSchema = z.enum([
|
|
39
|
+
'startup-failure',
|
|
40
|
+
'runtime-loss',
|
|
41
|
+
'sample-rate-fallback',
|
|
42
|
+
'sample-rate-fallback-failed',
|
|
43
|
+
'device-unavailable',
|
|
44
|
+
'disabled',
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
export const AudioSidecarFallbackSchema = z.object({
|
|
48
|
+
active: z.boolean(),
|
|
49
|
+
fromSampleRate: z.number().int().positive().nullable(),
|
|
50
|
+
toSampleRate: z.number().int().positive().nullable(),
|
|
51
|
+
persisted: z.boolean().optional(),
|
|
52
|
+
reason: z.string().optional(),
|
|
53
|
+
});
|
|
54
|
+
|
|
32
55
|
/**
|
|
33
56
|
* AudioSidecar 状态变化载荷。
|
|
34
57
|
* 前端以此渲染 RadioControl 中的音频副状态 spinner + Popover。
|
|
@@ -48,6 +71,18 @@ export const AudioSidecarStatusPayloadSchema = z.object({
|
|
|
48
71
|
lastError: AudioSidecarErrorSchema.nullable(),
|
|
49
72
|
/** 当前目标设备名(来自 AudioConfig.inputDeviceName) */
|
|
50
73
|
deviceName: z.string().nullable(),
|
|
74
|
+
/** 当前失败/重试阶段 */
|
|
75
|
+
phase: AudioSidecarPhaseSchema.optional(),
|
|
76
|
+
/** 机器可读的失败分类,用于 UI 展示和诊断 */
|
|
77
|
+
classification: AudioSidecarClassificationSchema.optional(),
|
|
78
|
+
/** 具体受影响的输入/输出设备名 */
|
|
79
|
+
affectedDeviceName: z.string().nullable().optional(),
|
|
80
|
+
/** 失败时使用的采样率 */
|
|
81
|
+
sampleRate: z.number().int().positive().nullable().optional(),
|
|
82
|
+
/** 自动降级状态 */
|
|
83
|
+
fallback: AudioSidecarFallbackSchema.optional(),
|
|
84
|
+
/** 当前重试原因摘要 */
|
|
85
|
+
retryReason: z.string().optional(),
|
|
51
86
|
});
|
|
52
87
|
|
|
53
88
|
export type AudioSidecarStatusPayload = z.infer<typeof AudioSidecarStatusPayloadSchema>;
|