@tx5dr/contracts 1.7.1 → 1.7.3
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 +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/schema/__tests__/audio.schema.test.js +4 -0
- package/dist/schema/__tests__/audio.schema.test.js.map +1 -1
- package/dist/schema/__tests__/operator.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/operator.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/operator.schema.test.js +23 -0
- package/dist/schema/__tests__/operator.schema.test.js.map +1 -0
- package/dist/schema/__tests__/plugin-runtime-log.schema.test.js +13 -1
- package/dist/schema/__tests__/plugin-runtime-log.schema.test.js.map +1 -1
- package/dist/schema/__tests__/process-monitor.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/process-monitor.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/process-monitor.schema.test.js +139 -0
- package/dist/schema/__tests__/process-monitor.schema.test.js.map +1 -0
- package/dist/schema/api-response.schema.d.ts +2 -2
- package/dist/schema/audio.schema.d.ts +369 -0
- package/dist/schema/audio.schema.d.ts.map +1 -1
- package/dist/schema/audio.schema.js +3 -0
- package/dist/schema/audio.schema.js.map +1 -1
- package/dist/schema/logbook.schema.d.ts +2 -2
- package/dist/schema/operator.schema.d.ts +10 -10
- package/dist/schema/operator.schema.d.ts.map +1 -1
- package/dist/schema/operator.schema.js +6 -1
- package/dist/schema/operator.schema.js.map +1 -1
- package/dist/schema/plugin.schema.d.ts +99 -22
- package/dist/schema/plugin.schema.d.ts.map +1 -1
- package/dist/schema/plugin.schema.js +5 -1
- package/dist/schema/plugin.schema.js.map +1 -1
- package/dist/schema/process-monitor.schema.d.ts +1373 -0
- package/dist/schema/process-monitor.schema.d.ts.map +1 -1
- package/dist/schema/process-monitor.schema.js +43 -0
- package/dist/schema/process-monitor.schema.js.map +1 -1
- package/dist/schema/radio-capability.schema.d.ts +6 -6
- package/dist/schema/radio.schema.d.ts +6 -6
- package/dist/schema/slot-info.schema.d.ts +136 -0
- package/dist/schema/slot-info.schema.d.ts.map +1 -1
- package/dist/schema/slot-info.schema.js +27 -2
- package/dist/schema/slot-info.schema.js.map +1 -1
- package/dist/schema/spectrum.schema.d.ts +24 -24
- package/dist/schema/voice-keyer.schema.d.ts +2 -2
- package/dist/schema/websocket.schema.d.ts +467 -159
- package/dist/schema/websocket.schema.d.ts.map +1 -1
- package/dist/schema/websocket.schema.js +4 -2
- package/dist/schema/websocket.schema.js.map +1 -1
- package/dist/utils/callsign.d.ts +2 -0
- package/dist/utils/callsign.d.ts.map +1 -0
- package/dist/utils/callsign.js +8 -0
- package/dist/utils/callsign.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/schema/__tests__/audio.schema.test.ts +4 -0
- package/src/schema/__tests__/operator.schema.test.ts +29 -0
- package/src/schema/__tests__/plugin-runtime-log.schema.test.ts +13 -1
- package/src/schema/__tests__/process-monitor.schema.test.ts +146 -0
- package/src/schema/audio.schema.ts +3 -0
- package/src/schema/operator.schema.ts +7 -1
- package/src/schema/plugin.schema.ts +7 -1
- package/src/schema/process-monitor.schema.ts +51 -0
- package/src/schema/slot-info.schema.ts +33 -2
- package/src/schema/websocket.schema.ts +16 -2
- package/src/utils/callsign.ts +9 -0
- package/test/decode-request-schema.test.ts +48 -0
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { ModeDescriptorSchema } from './mode.schema.js';
|
|
3
|
+
import { sanitizeCallsignInput } from '../utils/callsign.js';
|
|
4
|
+
|
|
5
|
+
const OperatorCallsignSchema = z
|
|
6
|
+
.string()
|
|
7
|
+
.transform(sanitizeCallsignInput)
|
|
8
|
+
.pipe(z.string().min(1, '呼号不能为空').max(10, '呼号不能超过10个字符'));
|
|
3
9
|
|
|
4
10
|
// 操作员配置 Schema (重命名以避免冲突)
|
|
5
11
|
export const RadioOperatorConfigSchema = z.object({
|
|
6
12
|
id: z.string().min(1, '操作员ID不能为空'),
|
|
7
13
|
createdByTokenId: z.string().optional(), // 创建者 Token ID(仅用于审计,不参与权限判断)
|
|
8
|
-
myCallsign:
|
|
14
|
+
myCallsign: OperatorCallsignSchema,
|
|
9
15
|
myGrid: z.string().min(4, '网格坐标至少4位').max(8, '网格坐标不能超过8位').optional(),
|
|
10
16
|
frequency: z.number().min(0).max(1000000000, '频率必须在0-1GHz之间').default(1000), // 音频偏移频率(Hz),默认1000Hz,创建时自动分配不重复值
|
|
11
17
|
transmitCycles: z.array(z.number().min(0).max(1)).default([0]), // 0=偶数周期,1=奇数周期
|
|
@@ -643,11 +643,17 @@ export const PluginRuntimeLogEntrySchema = z.object({
|
|
|
643
643
|
});
|
|
644
644
|
export type PluginRuntimeLogEntry = z.infer<typeof PluginRuntimeLogEntrySchema>;
|
|
645
645
|
|
|
646
|
+
export const PluginLogHistoryEntrySchema = z.union([
|
|
647
|
+
PluginRuntimeLogEntrySchema,
|
|
648
|
+
PluginLogEntrySchema,
|
|
649
|
+
]);
|
|
650
|
+
export type PluginLogHistoryEntry = z.infer<typeof PluginLogHistoryEntrySchema>;
|
|
651
|
+
|
|
646
652
|
/**
|
|
647
653
|
* 宿主级插件运行日志历史响应载荷
|
|
648
654
|
*/
|
|
649
655
|
export const PluginRuntimeLogHistoryPayloadSchema = z.object({
|
|
650
|
-
entries: z.array(
|
|
656
|
+
entries: z.array(PluginLogHistoryEntrySchema),
|
|
651
657
|
});
|
|
652
658
|
export type PluginRuntimeLogHistoryPayload = z.infer<typeof PluginRuntimeLogHistoryPayloadSchema>;
|
|
653
659
|
|
|
@@ -28,6 +28,52 @@ export const EventLoopDelaySchema = z.object({
|
|
|
28
28
|
p99: z.number(),
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
+
export const DecodeWorkerCurrentJobSchema = z.object({
|
|
32
|
+
jobId: z.number(),
|
|
33
|
+
slotId: z.string(),
|
|
34
|
+
windowIdx: z.number(),
|
|
35
|
+
mode: z.string(),
|
|
36
|
+
startedAt: z.number(),
|
|
37
|
+
elapsedMs: z.number(),
|
|
38
|
+
requestAudioDurationMs: z.number().optional(),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export const DecodeWorkerTelemetryWorkerSchema = z.object({
|
|
42
|
+
workerId: z.number(),
|
|
43
|
+
pid: z.number().optional(),
|
|
44
|
+
ready: z.boolean(),
|
|
45
|
+
busy: z.boolean(),
|
|
46
|
+
nativeThreads: z.number().int().positive(),
|
|
47
|
+
uptimeSeconds: z.number(),
|
|
48
|
+
memory: ProcessMemorySchema,
|
|
49
|
+
cpu: ProcessCpuSchema,
|
|
50
|
+
currentJob: DecodeWorkerCurrentJobSchema.optional(),
|
|
51
|
+
lastSeenAt: z.number(),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const DecodeWorkerTelemetrySummarySchema = z.object({
|
|
55
|
+
status: z.enum(['stopped', 'starting', 'ready', 'degraded', 'unavailable']).optional(),
|
|
56
|
+
workerCount: z.number().int().nonnegative(),
|
|
57
|
+
desiredWorkers: z.number().int().nonnegative().optional(),
|
|
58
|
+
readyCount: z.number().int().nonnegative(),
|
|
59
|
+
busyCount: z.number().int().nonnegative(),
|
|
60
|
+
totalRss: z.number().nonnegative(),
|
|
61
|
+
totalCpu: z.number().nonnegative(),
|
|
62
|
+
nativeThreadsPerWorker: z.number().int().positive(),
|
|
63
|
+
pendingJobs: z.number().int().nonnegative(),
|
|
64
|
+
activeJobs: z.number().int().nonnegative(),
|
|
65
|
+
lastError: z.string().optional(),
|
|
66
|
+
lastFailureAt: z.number().optional(),
|
|
67
|
+
restartAttempts: z.number().int().nonnegative().optional(),
|
|
68
|
+
workerEntry: z.string().optional(),
|
|
69
|
+
workerMode: z.enum(['development', 'production']).optional(),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
export const DecodeWorkerTelemetrySnapshotSchema = z.object({
|
|
73
|
+
summary: DecodeWorkerTelemetrySummarySchema,
|
|
74
|
+
workers: z.array(DecodeWorkerTelemetryWorkerSchema),
|
|
75
|
+
});
|
|
76
|
+
|
|
31
77
|
export const ProcessSnapshotSchema = z.object({
|
|
32
78
|
timestamp: z.number(),
|
|
33
79
|
uptimeSeconds: z.number(),
|
|
@@ -35,6 +81,7 @@ export const ProcessSnapshotSchema = z.object({
|
|
|
35
81
|
cpu: ProcessCpuSchema,
|
|
36
82
|
hostCpu: HostCpuSchema.optional(),
|
|
37
83
|
eventLoop: EventLoopDelaySchema,
|
|
84
|
+
decodeWorkers: DecodeWorkerTelemetrySnapshotSchema.optional(),
|
|
38
85
|
});
|
|
39
86
|
|
|
40
87
|
export const ProcessSnapshotHistorySchema = z.object({
|
|
@@ -47,5 +94,9 @@ export type ProcessMemory = z.infer<typeof ProcessMemorySchema>;
|
|
|
47
94
|
export type ProcessCpu = z.infer<typeof ProcessCpuSchema>;
|
|
48
95
|
export type HostCpu = z.infer<typeof HostCpuSchema>;
|
|
49
96
|
export type EventLoopDelay = z.infer<typeof EventLoopDelaySchema>;
|
|
97
|
+
export type DecodeWorkerCurrentJob = z.infer<typeof DecodeWorkerCurrentJobSchema>;
|
|
98
|
+
export type DecodeWorkerTelemetryWorker = z.infer<typeof DecodeWorkerTelemetryWorkerSchema>;
|
|
99
|
+
export type DecodeWorkerTelemetrySummary = z.infer<typeof DecodeWorkerTelemetrySummarySchema>;
|
|
100
|
+
export type DecodeWorkerTelemetrySnapshot = z.infer<typeof DecodeWorkerTelemetrySnapshotSchema>;
|
|
50
101
|
export type ProcessSnapshot = z.infer<typeof ProcessSnapshotSchema>;
|
|
51
102
|
export type ProcessSnapshotHistory = z.infer<typeof ProcessSnapshotHistorySchema>;
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { DxccStatusSchema, SubdivisionConfidenceSchema } from './qso.schema.js';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Frequency context captured when a slot pack is created.
|
|
6
|
+
* Fields are optional so older persisted slot packs remain valid.
|
|
7
|
+
*/
|
|
8
|
+
export const SlotPackFrequencyContextSchema = z.object({
|
|
9
|
+
frequency: z.number().optional(),
|
|
10
|
+
mode: z.string().optional(),
|
|
11
|
+
band: z.string().optional(),
|
|
12
|
+
radioMode: z.string().optional(),
|
|
13
|
+
description: z.string().optional(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export type SlotPackFrequencyContext = z.infer<typeof SlotPackFrequencyContextSchema>;
|
|
17
|
+
|
|
4
18
|
/**
|
|
5
19
|
* 时隙周期(偶数奇数)
|
|
6
20
|
*/
|
|
@@ -83,6 +97,19 @@ export const FrameMessageSchema = z.object({
|
|
|
83
97
|
|
|
84
98
|
export type FrameMessage = z.infer<typeof FrameMessageSchema>;
|
|
85
99
|
|
|
100
|
+
export const DecodeApContextSchema = z.object({
|
|
101
|
+
operatorId: z.string(),
|
|
102
|
+
myCall: z.string(),
|
|
103
|
+
myGrid: z.string().optional(),
|
|
104
|
+
dxCall: z.string(),
|
|
105
|
+
dxGrid: z.string().optional(),
|
|
106
|
+
frequencyHz: z.number(),
|
|
107
|
+
qsoProgress: z.number(),
|
|
108
|
+
currentSlot: z.string(),
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
export type DecodeApContext = z.infer<typeof DecodeApContextSchema>;
|
|
112
|
+
|
|
86
113
|
/**
|
|
87
114
|
* 解码请求,用于SlotScheduler内部
|
|
88
115
|
*/
|
|
@@ -100,7 +127,9 @@ export const DecodeRequestSchema = z.object({
|
|
|
100
127
|
/** 请求时间戳 */
|
|
101
128
|
timestamp: z.number().default(() => Date.now()),
|
|
102
129
|
/** 窗口时间偏移(毫秒) */
|
|
103
|
-
windowOffsetMs: z.number().default(0)
|
|
130
|
+
windowOffsetMs: z.number().default(0),
|
|
131
|
+
/** 可选的单操作员 AP decode 上下文 */
|
|
132
|
+
apContext: DecodeApContextSchema.optional()
|
|
104
133
|
});
|
|
105
134
|
|
|
106
135
|
export type DecodeRequest = z.infer<typeof DecodeRequestSchema>;
|
|
@@ -160,7 +189,9 @@ export const SlotPackSchema = z.object({
|
|
|
160
189
|
timestamp: z.number(),
|
|
161
190
|
frameCount: z.number(),
|
|
162
191
|
processingTimeMs: z.number()
|
|
163
|
-
})).default([])
|
|
192
|
+
})).default([]),
|
|
193
|
+
/** Dial/band context active when this slot was created. */
|
|
194
|
+
frequencyContext: SlotPackFrequencyContextSchema.optional()
|
|
164
195
|
});
|
|
165
196
|
|
|
166
197
|
export type SlotPack = z.infer<typeof SlotPackSchema>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { FT8DecodeSchema } from './ft8.schema.js';
|
|
3
|
-
import { SlotPackSchema, SlotInfoSchema } from './slot-info.schema.js';
|
|
3
|
+
import { SlotPackSchema, SlotInfoSchema, SlotPackFrequencyContextSchema } from './slot-info.schema.js';
|
|
4
4
|
import {
|
|
5
5
|
PluginDataPayloadSchema,
|
|
6
6
|
PluginLogEntrySchema,
|
|
@@ -779,7 +779,9 @@ export const WSTransmissionLogMessageSchema = WSBaseMessageSchema.extend({
|
|
|
779
779
|
time: z.string(),
|
|
780
780
|
message: z.string(),
|
|
781
781
|
frequency: z.number(),
|
|
782
|
-
slotStartMs: z.number()
|
|
782
|
+
slotStartMs: z.number(),
|
|
783
|
+
replaceExisting: z.boolean().optional(),
|
|
784
|
+
frequencyContext: SlotPackFrequencyContextSchema.optional(),
|
|
783
785
|
}),
|
|
784
786
|
});
|
|
785
787
|
|
|
@@ -1443,6 +1445,7 @@ export interface DigitalRadioEngineEvents {
|
|
|
1443
1445
|
frequency: number;
|
|
1444
1446
|
slotStartMs: number;
|
|
1445
1447
|
replaceExisting?: boolean;
|
|
1448
|
+
frequencyContext?: z.infer<typeof SlotPackFrequencyContextSchema>;
|
|
1446
1449
|
}) => void;
|
|
1447
1450
|
|
|
1448
1451
|
// 操作员事件
|
|
@@ -1544,6 +1547,17 @@ export interface DigitalRadioEngineEvents {
|
|
|
1544
1547
|
}) => void;
|
|
1545
1548
|
pluginPanelMeta: (data: import('./plugin.schema.js').PluginPanelMetaPayload) => void;
|
|
1546
1549
|
pluginPanelContributionsChanged: (data: import('./plugin.schema.js').PluginUIPanelContributionGroup) => void;
|
|
1550
|
+
pluginRemoteReplyToDecode: (data: { operatorId: string; callsign: string; modifiers?: number }) => void;
|
|
1551
|
+
pluginRemoteClearDecodes: (data: { operatorId: string; window?: number }) => void;
|
|
1552
|
+
pluginRemoteFreeText: (data: { operatorId: string; text?: string; send: boolean }) => void;
|
|
1553
|
+
pluginRemoteLocation: (data: { operatorId: string; location: string }) => void;
|
|
1554
|
+
pluginRemoteHighlightCallsign: (data: {
|
|
1555
|
+
operatorId: string;
|
|
1556
|
+
callsign: string;
|
|
1557
|
+
background?: string | null;
|
|
1558
|
+
foreground?: string | null;
|
|
1559
|
+
lastOnly?: boolean;
|
|
1560
|
+
}) => void;
|
|
1547
1561
|
|
|
1548
1562
|
// 内部子系统间通信事件(不通过 WebSocket 广播,用于 engine emitter 内部编排)
|
|
1549
1563
|
encodeStart: (slotInfo: z.infer<typeof SlotInfoSchema>) => void;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { DecodeRequestSchema } from '../src/schema/slot-info.schema.js';
|
|
3
|
+
|
|
4
|
+
function makePcm(): ArrayBuffer {
|
|
5
|
+
return new Float32Array(16).buffer;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
describe('DecodeRequestSchema', () => {
|
|
9
|
+
it('accepts legacy decode requests without AP context', () => {
|
|
10
|
+
const parsed = DecodeRequestSchema.parse({
|
|
11
|
+
slotId: 'FT8-1-15000',
|
|
12
|
+
mode: 'FT8',
|
|
13
|
+
windowIdx: 0,
|
|
14
|
+
pcm: makePcm(),
|
|
15
|
+
sampleRate: 12000,
|
|
16
|
+
windowOffsetMs: 0,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
expect(parsed.apContext).toBeUndefined();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('accepts a single AP decode context', () => {
|
|
23
|
+
const parsed = DecodeRequestSchema.parse({
|
|
24
|
+
slotId: 'FT8-1-15000',
|
|
25
|
+
mode: 'FT8',
|
|
26
|
+
windowIdx: 1,
|
|
27
|
+
pcm: makePcm(),
|
|
28
|
+
sampleRate: 12000,
|
|
29
|
+
windowOffsetMs: 0,
|
|
30
|
+
apContext: {
|
|
31
|
+
operatorId: 'op1',
|
|
32
|
+
myCall: 'BG4IAJ',
|
|
33
|
+
myGrid: 'OM96',
|
|
34
|
+
dxCall: 'JA1AAA',
|
|
35
|
+
dxGrid: 'PM95',
|
|
36
|
+
frequencyHz: 1500,
|
|
37
|
+
qsoProgress: 4,
|
|
38
|
+
currentSlot: 'TX4',
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
expect(parsed.apContext).toEqual(expect.objectContaining({
|
|
43
|
+
operatorId: 'op1',
|
|
44
|
+
qsoProgress: 4,
|
|
45
|
+
currentSlot: 'TX4',
|
|
46
|
+
}));
|
|
47
|
+
});
|
|
48
|
+
});
|