@tx5dr/contracts 1.7.2 → 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__/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 +16 -16
- 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 +363 -139
- 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__/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/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
|
@@ -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
|
+
});
|