@tx5dr/contracts 1.2.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.
Files changed (180) hide show
  1. package/CLAUDE.md +41 -0
  2. package/dist/index.d.ts +55 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +86 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/schema/__tests__/plugin-runtime-log.schema.test.d.ts +2 -0
  7. package/dist/schema/__tests__/plugin-runtime-log.schema.test.d.ts.map +1 -0
  8. package/dist/schema/__tests__/plugin-runtime-log.schema.test.js +78 -0
  9. package/dist/schema/__tests__/plugin-runtime-log.schema.test.js.map +1 -0
  10. package/dist/schema/ability.d.ts +85 -0
  11. package/dist/schema/ability.d.ts.map +1 -0
  12. package/dist/schema/ability.js +119 -0
  13. package/dist/schema/ability.js.map +1 -0
  14. package/dist/schema/api-response.schema.d.ts +1017 -0
  15. package/dist/schema/api-response.schema.d.ts.map +1 -0
  16. package/dist/schema/api-response.schema.js +137 -0
  17. package/dist/schema/api-response.schema.js.map +1 -0
  18. package/dist/schema/audio-sidecar.schema.d.ts +106 -0
  19. package/dist/schema/audio-sidecar.schema.d.ts.map +1 -0
  20. package/dist/schema/audio-sidecar.schema.js +47 -0
  21. package/dist/schema/audio-sidecar.schema.js.map +1 -0
  22. package/dist/schema/audio.schema.d.ts +227 -0
  23. package/dist/schema/audio.schema.d.ts.map +1 -0
  24. package/dist/schema/audio.schema.js +56 -0
  25. package/dist/schema/audio.schema.js.map +1 -0
  26. package/dist/schema/auth.schema.d.ts +738 -0
  27. package/dist/schema/auth.schema.d.ts.map +1 -0
  28. package/dist/schema/auth.schema.js +161 -0
  29. package/dist/schema/auth.schema.js.map +1 -0
  30. package/dist/schema/cycle.schema.d.ts +33 -0
  31. package/dist/schema/cycle.schema.d.ts.map +1 -0
  32. package/dist/schema/cycle.schema.js +23 -0
  33. package/dist/schema/cycle.schema.js.map +1 -0
  34. package/dist/schema/desktop-https.schema.d.ts +146 -0
  35. package/dist/schema/desktop-https.schema.d.ts.map +1 -0
  36. package/dist/schema/desktop-https.schema.js +31 -0
  37. package/dist/schema/desktop-https.schema.js.map +1 -0
  38. package/dist/schema/ft8.schema.d.ts +1107 -0
  39. package/dist/schema/ft8.schema.d.ts.map +1 -0
  40. package/dist/schema/ft8.schema.js +268 -0
  41. package/dist/schema/ft8.schema.js.map +1 -0
  42. package/dist/schema/hello.schema.d.ts +10 -0
  43. package/dist/schema/hello.schema.d.ts.map +1 -0
  44. package/dist/schema/hello.schema.js +5 -0
  45. package/dist/schema/hello.schema.js.map +1 -0
  46. package/dist/schema/logbook.schema.d.ts +1472 -0
  47. package/dist/schema/logbook.schema.d.ts.map +1 -0
  48. package/dist/schema/logbook.schema.js +256 -0
  49. package/dist/schema/logbook.schema.js.map +1 -0
  50. package/dist/schema/mode.schema.d.ts +130 -0
  51. package/dist/schema/mode.schema.d.ts.map +1 -0
  52. package/dist/schema/mode.schema.js +141 -0
  53. package/dist/schema/mode.schema.js.map +1 -0
  54. package/dist/schema/openwebrx.schema.d.ts +352 -0
  55. package/dist/schema/openwebrx.schema.d.ts.map +1 -0
  56. package/dist/schema/openwebrx.schema.js +139 -0
  57. package/dist/schema/openwebrx.schema.js.map +1 -0
  58. package/dist/schema/operator.schema.d.ts +883 -0
  59. package/dist/schema/operator.schema.d.ts.map +1 -0
  60. package/dist/schema/operator.schema.js +97 -0
  61. package/dist/schema/operator.schema.js.map +1 -0
  62. package/dist/schema/plugin.schema.d.ts +1579 -0
  63. package/dist/schema/plugin.schema.d.ts.map +1 -0
  64. package/dist/schema/plugin.schema.js +336 -0
  65. package/dist/schema/plugin.schema.js.map +1 -0
  66. package/dist/schema/process-monitor.schema.d.ts +282 -0
  67. package/dist/schema/process-monitor.schema.d.ts.map +1 -0
  68. package/dist/schema/process-monitor.schema.js +31 -0
  69. package/dist/schema/process-monitor.schema.js.map +1 -0
  70. package/dist/schema/pskreporter.schema.d.ts +185 -0
  71. package/dist/schema/pskreporter.schema.d.ts.map +1 -0
  72. package/dist/schema/pskreporter.schema.js +80 -0
  73. package/dist/schema/pskreporter.schema.js.map +1 -0
  74. package/dist/schema/qso.schema.d.ts +419 -0
  75. package/dist/schema/qso.schema.d.ts.map +1 -0
  76. package/dist/schema/qso.schema.js +137 -0
  77. package/dist/schema/qso.schema.js.map +1 -0
  78. package/dist/schema/radio-capability.schema.d.ts +625 -0
  79. package/dist/schema/radio-capability.schema.d.ts.map +1 -0
  80. package/dist/schema/radio-capability.schema.js +191 -0
  81. package/dist/schema/radio-capability.schema.js.map +1 -0
  82. package/dist/schema/radio-power-support.d.ts +45 -0
  83. package/dist/schema/radio-power-support.d.ts.map +1 -0
  84. package/dist/schema/radio-power-support.js +64 -0
  85. package/dist/schema/radio-power-support.js.map +1 -0
  86. package/dist/schema/radio-power.schema.d.ts +319 -0
  87. package/dist/schema/radio-power.schema.d.ts.map +1 -0
  88. package/dist/schema/radio-power.schema.js +87 -0
  89. package/dist/schema/radio-power.schema.js.map +1 -0
  90. package/dist/schema/radio-profile.schema.d.ts +2694 -0
  91. package/dist/schema/radio-profile.schema.d.ts.map +1 -0
  92. package/dist/schema/radio-profile.schema.js +71 -0
  93. package/dist/schema/radio-profile.schema.js.map +1 -0
  94. package/dist/schema/radio.schema.d.ts +1438 -0
  95. package/dist/schema/radio.schema.d.ts.map +1 -0
  96. package/dist/schema/radio.schema.js +314 -0
  97. package/dist/schema/radio.schema.js.map +1 -0
  98. package/dist/schema/realtime.schema.d.ts +1299 -0
  99. package/dist/schema/realtime.schema.d.ts.map +1 -0
  100. package/dist/schema/realtime.schema.js +184 -0
  101. package/dist/schema/realtime.schema.js.map +1 -0
  102. package/dist/schema/rigctld.schema.d.ts +151 -0
  103. package/dist/schema/rigctld.schema.d.ts.map +1 -0
  104. package/dist/schema/rigctld.schema.js +42 -0
  105. package/dist/schema/rigctld.schema.js.map +1 -0
  106. package/dist/schema/server-message-keys.d.ts +21 -0
  107. package/dist/schema/server-message-keys.d.ts.map +1 -0
  108. package/dist/schema/server-message-keys.js +22 -0
  109. package/dist/schema/server-message-keys.js.map +1 -0
  110. package/dist/schema/slot-info.schema.d.ts +696 -0
  111. package/dist/schema/slot-info.schema.d.ts.map +1 -0
  112. package/dist/schema/slot-info.schema.js +144 -0
  113. package/dist/schema/slot-info.schema.js.map +1 -0
  114. package/dist/schema/spectrum.schema.d.ts +716 -0
  115. package/dist/schema/spectrum.schema.d.ts.map +1 -0
  116. package/dist/schema/spectrum.schema.js +128 -0
  117. package/dist/schema/spectrum.schema.js.map +1 -0
  118. package/dist/schema/station-info.schema.d.ts +202 -0
  119. package/dist/schema/station-info.schema.d.ts.map +1 -0
  120. package/dist/schema/station-info.schema.js +32 -0
  121. package/dist/schema/station-info.schema.js.map +1 -0
  122. package/dist/schema/system.schema.d.ts +113 -0
  123. package/dist/schema/system.schema.d.ts.map +1 -0
  124. package/dist/schema/system.schema.js +95 -0
  125. package/dist/schema/system.schema.js.map +1 -0
  126. package/dist/schema/transmission.schema.d.ts +413 -0
  127. package/dist/schema/transmission.schema.d.ts.map +1 -0
  128. package/dist/schema/transmission.schema.js +78 -0
  129. package/dist/schema/transmission.schema.js.map +1 -0
  130. package/dist/schema/voice.schema.d.ts +38 -0
  131. package/dist/schema/voice.schema.d.ts.map +1 -0
  132. package/dist/schema/voice.schema.js +24 -0
  133. package/dist/schema/voice.schema.js.map +1 -0
  134. package/dist/schema/websocket.schema.d.ts +16916 -0
  135. package/dist/schema/websocket.schema.d.ts.map +1 -0
  136. package/dist/schema/websocket.schema.js +1050 -0
  137. package/dist/schema/websocket.schema.js.map +1 -0
  138. package/dist/utils/grid.d.ts +13 -0
  139. package/dist/utils/grid.d.ts.map +1 -0
  140. package/dist/utils/grid.js +71 -0
  141. package/dist/utils/grid.js.map +1 -0
  142. package/eslint.config.js +15 -0
  143. package/package.json +28 -0
  144. package/src/index.ts +152 -0
  145. package/src/schema/__tests__/plugin-runtime-log.schema.test.ts +90 -0
  146. package/src/schema/ability.ts +205 -0
  147. package/src/schema/api-response.schema.ts +187 -0
  148. package/src/schema/audio-sidecar.schema.ts +53 -0
  149. package/src/schema/audio.schema.ts +73 -0
  150. package/src/schema/auth.schema.ts +224 -0
  151. package/src/schema/cycle.schema.ts +25 -0
  152. package/src/schema/desktop-https.schema.ts +43 -0
  153. package/src/schema/ft8.schema.ts +362 -0
  154. package/src/schema/hello.schema.ts +7 -0
  155. package/src/schema/logbook.schema.ts +310 -0
  156. package/src/schema/mode.schema.ts +158 -0
  157. package/src/schema/openwebrx.schema.ts +160 -0
  158. package/src/schema/operator.schema.ts +112 -0
  159. package/src/schema/plugin.schema.ts +503 -0
  160. package/src/schema/process-monitor.schema.ts +41 -0
  161. package/src/schema/pskreporter.schema.ts +102 -0
  162. package/src/schema/qso.schema.ts +173 -0
  163. package/src/schema/radio-capability.schema.ts +244 -0
  164. package/src/schema/radio-power-support.ts +107 -0
  165. package/src/schema/radio-power.schema.ts +101 -0
  166. package/src/schema/radio-profile.schema.ts +91 -0
  167. package/src/schema/radio.schema.ts +385 -0
  168. package/src/schema/realtime.schema.ts +262 -0
  169. package/src/schema/rigctld.schema.ts +51 -0
  170. package/src/schema/server-message-keys.ts +26 -0
  171. package/src/schema/slot-info.schema.ts +162 -0
  172. package/src/schema/spectrum.schema.ts +166 -0
  173. package/src/schema/station-info.schema.ts +40 -0
  174. package/src/schema/system.schema.ts +121 -0
  175. package/src/schema/transmission.schema.ts +105 -0
  176. package/src/schema/voice.schema.ts +28 -0
  177. package/src/schema/websocket.schema.ts +1480 -0
  178. package/src/utils/grid.ts +94 -0
  179. package/test/mode-schema.test.ts +48 -0
  180. package/tsconfig.json +9 -0
@@ -0,0 +1,362 @@
1
+ import { z } from 'zod';
2
+ import { LogbookAnalysisSchema } from './slot-info.schema.js';
3
+
4
+ // FT8解码帧信息(基于wsjtx-lib的数据类型)
5
+ export const FT8DecodeSchema = z.object({
6
+ // 时间戳
7
+ timestamp: z.number(),
8
+ // 信噪比
9
+ snr: z.number(),
10
+ // 时间偏移(秒)
11
+ dt: z.number(),
12
+ // 频率偏移(Hz)
13
+ df: z.number(),
14
+ // 解码的消息文本
15
+ message: z.string(),
16
+ // 是否为低置信度解码
17
+ lowConfidence: z.boolean().optional(),
18
+ // 解码周期(15秒周期内的序号)
19
+ cycle: z.number(),
20
+ });
21
+
22
+ // FT8编码请求
23
+ export const FT8EncodeRequestSchema = z.object({
24
+ message: z.string(),
25
+ frequency: z.number().optional(),
26
+ // 发射功率(dBm)
27
+ power: z.number().optional(),
28
+ });
29
+
30
+ // FT8编码响应
31
+ export const FT8EncodeResponseSchema = z.object({
32
+ success: z.boolean(),
33
+ audioData: z.array(z.number()).optional(),
34
+ duration: z.number().optional(),
35
+ error: z.string().optional(),
36
+ });
37
+
38
+ // FT8解码帧列表响应
39
+ export const FT8DecodesResponseSchema = z.object({
40
+ decodes: z.array(FT8DecodeSchema),
41
+ cycle: z.number(),
42
+ timestamp: z.number(),
43
+ });
44
+
45
+ // FT8频谱数据
46
+ export const FT8SpectrumSchema = z.object({
47
+ // 时间戳
48
+ timestamp: z.number(),
49
+ // 采样率
50
+ sampleRate: z.number(),
51
+ // 频率范围
52
+ frequencyRange: z.object({
53
+ min: z.number(),
54
+ max: z.number(),
55
+ }),
56
+ // 二进制频谱数据
57
+ binaryData: z.object({
58
+ // 二进制数据,使用base64编码
59
+ data: z.string(),
60
+ // 数据格式描述
61
+ format: z.object({
62
+ type: z.literal('int16'),
63
+ // 数据点数量
64
+ length: z.number(),
65
+ // 缩放因子(可选)
66
+ scale: z.number().optional(),
67
+ // 偏移量(可选)
68
+ offset: z.number().optional(),
69
+ }),
70
+ }),
71
+ // 频谱数据摘要
72
+ summary: z.object({
73
+ // 峰值频率(Hz)
74
+ peakFrequency: z.number(),
75
+ // 峰值幅度(dB)
76
+ peakMagnitude: z.number(),
77
+ // 平均幅度(dB)
78
+ averageMagnitude: z.number(),
79
+ // 动态范围(dB)
80
+ dynamicRange: z.number(),
81
+ // 能量分布(可选)
82
+ energyDistribution: z.array(z.number()).optional(),
83
+ }).optional(),
84
+ });
85
+
86
+ // FT8频谱响应
87
+ export const FT8SpectrumResponseSchema = z.object({
88
+ spectrum: FT8SpectrumSchema,
89
+ });
90
+
91
+ // FT8发射控制请求
92
+ export const FT8TransmitRequestSchema = z.object({
93
+ message: z.string(),
94
+ frequency: z.number(),
95
+ // 是否立即发射
96
+ immediate: z.boolean().optional(),
97
+ // 发射周期(如果不是立即发射)
98
+ cycle: z.number().optional(),
99
+ });
100
+
101
+ // FT8发射控制响应
102
+ export const FT8TransmitResponseSchema = z.object({
103
+ success: z.boolean(),
104
+ message: z.string().optional(),
105
+ scheduledCycle: z.number().optional(),
106
+ });
107
+
108
+ /**
109
+ * Canonical FT8 message kind identifiers used by the parser.
110
+ *
111
+ * These values describe the semantic role of a decoded message after TX-5DR has
112
+ * normalized the raw free-text payload into structured FT8/QSO stages.
113
+ */
114
+ export const FT8MessageType = {
115
+ CQ: 'cq', // CQ呼叫
116
+ CALL: 'call', // 响应呼叫
117
+ SIGNAL_REPORT: 'signal_report',// 信号报告
118
+ ROGER_REPORT: 'roger_report', // 确认信号报告
119
+ RRR: 'rrr', // RRR确认
120
+ SEVENTY_THREE: '73', // 73告别
121
+ FOX_RR73: 'fox_rr73', // Fox/Hound DXpedition模式:Fox确认完成并邀请下一个Hound
122
+ CUSTOM: 'custom', // 自定义消息
123
+ UNKNOWN: 'unknown', // 未知消息类型
124
+ } as const;
125
+
126
+ /**
127
+ * Zod schema for {@link FT8MessageType} values.
128
+ */
129
+ export const FT8MessageTypeSchema = z.enum([
130
+ FT8MessageType.CQ,
131
+ FT8MessageType.CALL,
132
+ FT8MessageType.SIGNAL_REPORT,
133
+ FT8MessageType.ROGER_REPORT,
134
+ FT8MessageType.RRR,
135
+ FT8MessageType.SEVENTY_THREE,
136
+ FT8MessageType.FOX_RR73,
137
+ FT8MessageType.CUSTOM,
138
+ FT8MessageType.UNKNOWN,
139
+ ]);
140
+
141
+ /**
142
+ * Base shape shared by every structured FT8 message.
143
+ *
144
+ * Use this when code only needs to discriminate on the message `type` without
145
+ * caring about the rest of the payload.
146
+ */
147
+ export const FT8MessageBaseSchema = z.object({
148
+ type: FT8MessageTypeSchema,
149
+ });
150
+
151
+ /**
152
+ * Structured representation of a CQ message.
153
+ *
154
+ * This is typically the main entry point for automation plugins that scan the
155
+ * band for new targets to answer.
156
+ */
157
+ export const FT8MessageCQSchema = FT8MessageBaseSchema.extend({
158
+ type: z.literal('cq'),
159
+ senderCallsign: z.string(),
160
+ // Reuses the legacy field name for compatibility. The value can be a
161
+ // directed-CQ modifier such as DX/EU/JA or a callback token such as 290.
162
+ flag: z.string().optional(),
163
+ grid: z.string().optional(),
164
+ });
165
+
166
+ /**
167
+ * Structured representation of a directed call message.
168
+ *
169
+ * This covers "A B" style messages where one station calls or answers a
170
+ * specific target station, optionally including grid information.
171
+ */
172
+ export const FT8MessageCallSchema = FT8MessageBaseSchema.extend({
173
+ type: z.literal('call'),
174
+ senderCallsign: z.string(),
175
+ targetCallsign: z.string(),
176
+ grid: z.string().optional(),
177
+ });
178
+
179
+ /**
180
+ * Structured representation of a signal report message.
181
+ *
182
+ * This usually corresponds to the report-exchange phase of a normal FT8 QSO.
183
+ */
184
+ export const FT8MessageSignalReportSchema = FT8MessageBaseSchema.extend({
185
+ type: z.literal('signal_report'),
186
+ senderCallsign: z.string(),
187
+ targetCallsign: z.string(),
188
+ report: z.number(),
189
+ });
190
+
191
+ /**
192
+ * Structured representation of an RR73-style "roger + report" message.
193
+ *
194
+ * In standard FT8 flow this acknowledges the received report while also
195
+ * carrying the sender's report for the other station.
196
+ */
197
+ export const FT8MessageRogerReportSchema = FT8MessageBaseSchema.extend({
198
+ type: z.literal('roger_report'),
199
+ senderCallsign: z.string(),
200
+ targetCallsign: z.string(),
201
+ report: z.number(),
202
+ });
203
+
204
+ /**
205
+ * Structured representation of an `RRR` confirmation message.
206
+ *
207
+ * This indicates the sender considers the report exchange complete.
208
+ */
209
+ export const FT8MessageRRRSchema = FT8MessageBaseSchema.extend({
210
+ type: z.literal('rrr'),
211
+ senderCallsign: z.string(),
212
+ targetCallsign: z.string(),
213
+ });
214
+
215
+ /**
216
+ * Structured representation of a final `73` closing message.
217
+ *
218
+ * This is typically the terminal stage of a completed FT8 QSO.
219
+ */
220
+ export const FT8MessageSeventyThreeSchema = FT8MessageBaseSchema.extend({
221
+ type: z.literal('73'),
222
+ senderCallsign: z.string(),
223
+ targetCallsign: z.string(),
224
+ });
225
+
226
+ /**
227
+ * Structured representation of a Fox/Hound `RR73` completion message.
228
+ *
229
+ * This variant appears in DXpedition workflows where the Fox acknowledges one
230
+ * completed Hound and may invite the next one in the same frame.
231
+ */
232
+ export const FT8MessageFoxRR73Schema = FT8MessageBaseSchema.extend({
233
+ type: z.literal('fox_rr73'),
234
+ senderCallsign: z.string().optional(), // 可解析时填入真实 Fox 呼号;仅短哈希时留空
235
+ completedCallsign: z.string(), // 已完成QSO的Hound呼号
236
+ nextCallsign: z.string(), // 下一个被邀请的Hound呼号
237
+ foxHash: z.string().optional(), // Fox的哈希码(去掉尖括号后的值)
238
+ snrForNext: z.number().optional(), // Fox告知下一个Hound的信号强度(如+04→4)
239
+ });
240
+
241
+ /**
242
+ * Structured representation of a decoder-recognized message whose free-text
243
+ * payload is intentionally left uninterpreted.
244
+ */
245
+ export const FT8MessageCustomSchema = FT8MessageBaseSchema.extend({
246
+ type: z.literal('custom'),
247
+ });
248
+
249
+ /**
250
+ * Fallback structured representation for a decoded message that the parser
251
+ * could not confidently classify.
252
+ */
253
+ export const FT8MessageUnknownSchema = FT8MessageBaseSchema.extend({
254
+ type: z.literal('unknown'),
255
+ });
256
+
257
+ /**
258
+ * Discriminated union of every structured FT8 message variant understood by
259
+ * TX-5DR.
260
+ */
261
+ export const FT8MessageSchema = z.discriminatedUnion('type', [
262
+ FT8MessageCQSchema,
263
+ FT8MessageCallSchema,
264
+ FT8MessageSignalReportSchema,
265
+ FT8MessageRogerReportSchema,
266
+ FT8MessageRRRSchema,
267
+ FT8MessageSeventyThreeSchema,
268
+ FT8MessageFoxRR73Schema,
269
+ FT8MessageCustomSchema,
270
+ FT8MessageUnknownSchema,
271
+ ]);
272
+
273
+ /**
274
+ * Fully parsed decode entry used by selection, filtering and automation logic.
275
+ *
276
+ * This is the main plugin-facing FT8 payload. It combines RF metrics from the
277
+ * decoder (`snr`, `dt`, `df`), the original unparsed text (`rawMessage`), the
278
+ * normalized semantic form (`message`) and optional logbook enrichment.
279
+ */
280
+ export const ParsedFT8MessageSchema = z.object({
281
+ snr: z.number(),
282
+ dt: z.number(),
283
+ df: z.number(),
284
+ rawMessage: z.string(),
285
+ message: FT8MessageSchema,
286
+ slotId: z.string(),
287
+ timestamp: z.number(),
288
+ logbookAnalysis: LogbookAnalysisSchema.optional(),
289
+ });
290
+
291
+ export type FT8Decode = z.infer<typeof FT8DecodeSchema>;
292
+ export type FT8EncodeRequest = z.infer<typeof FT8EncodeRequestSchema>;
293
+ export type FT8EncodeResponse = z.infer<typeof FT8EncodeResponseSchema>;
294
+ export type FT8DecodesResponse = z.infer<typeof FT8DecodesResponseSchema>;
295
+ export type FT8Spectrum = z.infer<typeof FT8SpectrumSchema>;
296
+ export type FT8SpectrumResponse = z.infer<typeof FT8SpectrumResponseSchema>;
297
+ export type FT8TransmitRequest = z.infer<typeof FT8TransmitRequestSchema>;
298
+ export type FT8TransmitResponse = z.infer<typeof FT8TransmitResponseSchema>;
299
+
300
+ /**
301
+ * Base FT8 message type containing only the discriminant field.
302
+ */
303
+ export type FT8MessageBase = z.infer<typeof FT8MessageBaseSchema>;
304
+
305
+ /**
306
+ * Structured CQ message with sender identity and optional grid/modifier metadata.
307
+ */
308
+ export type FT8MessageCQ = z.infer<typeof FT8MessageCQSchema>;
309
+
310
+ /**
311
+ * Structured directed-call message between a sender and a target station.
312
+ */
313
+ export type FT8MessageCall = z.infer<typeof FT8MessageCallSchema>;
314
+
315
+ /**
316
+ * Structured signal-report exchange message carrying a numeric report.
317
+ */
318
+ export type FT8MessageSignalReport = z.infer<typeof FT8MessageSignalReportSchema>;
319
+
320
+ /**
321
+ * Structured "roger + report" exchange message.
322
+ */
323
+ export type FT8MessageRogerReport = z.infer<typeof FT8MessageRogerReportSchema>;
324
+
325
+ /**
326
+ * Structured `RRR` completion/acknowledgement message.
327
+ */
328
+ export type FT8MessageRRR = z.infer<typeof FT8MessageRRRSchema>;
329
+
330
+ /**
331
+ * Structured final `73` closing message.
332
+ */
333
+ export type FT8MessageSeventyThree = z.infer<typeof FT8MessageSeventyThreeSchema>;
334
+
335
+ /**
336
+ * Structured Fox/Hound `RR73` completion-and-invite message.
337
+ */
338
+ export type FT8MessageFoxRR73 = z.infer<typeof FT8MessageFoxRR73Schema>;
339
+
340
+ /**
341
+ * Structured custom FT8 message whose payload is intentionally not further
342
+ * parsed by the core parser.
343
+ */
344
+ export type FT8MessageCustom = z.infer<typeof FT8MessageCustomSchema>;
345
+
346
+ /**
347
+ * Structured fallback FT8 message for unclassified decoder output.
348
+ */
349
+ export type FT8MessageUnknown = z.infer<typeof FT8MessageUnknownSchema>;
350
+
351
+ /**
352
+ * Union of every structured FT8 message variant recognized by TX-5DR.
353
+ */
354
+ export type FT8Message = z.infer<typeof FT8MessageSchema>;
355
+
356
+ /**
357
+ * Primary plugin-facing FT8 decode model.
358
+ *
359
+ * Prefer this type when filtering targets, scoring candidates or reacting to
360
+ * decoded traffic in plugin hooks.
361
+ */
362
+ export type ParsedFT8Message = z.infer<typeof ParsedFT8MessageSchema>;
@@ -0,0 +1,7 @@
1
+ import { z } from 'zod';
2
+
3
+ export const HelloResponseSchema = z.object({
4
+ message: z.string(),
5
+ });
6
+
7
+ export type HelloResponse = z.infer<typeof HelloResponseSchema>;
@@ -0,0 +1,310 @@
1
+ import { z } from 'zod';
2
+
3
+ export const DxccCountSummarySchema = z.object({
4
+ current: z.number().default(0),
5
+ total: z.number().default(0),
6
+ deleted: z.number().default(0),
7
+ });
8
+
9
+ export const DxccBucketItemSchema = z.object({
10
+ key: z.string(),
11
+ worked: z.number().default(0),
12
+ confirmed: z.number().default(0),
13
+ });
14
+
15
+ export const LogBookDxccSummarySchema = z.object({
16
+ worked: DxccCountSummarySchema,
17
+ confirmed: DxccCountSummarySchema,
18
+ reviewCount: z.number().default(0),
19
+ byBand: z.array(DxccBucketItemSchema).default([]),
20
+ byMode: z.array(DxccBucketItemSchema).default([]),
21
+ });
22
+
23
+ /**
24
+ * 日志本信息Schema
25
+ */
26
+ export const LogBookInfoSchema = z.object({
27
+ id: z.string(),
28
+ name: z.string(),
29
+ description: z.string().optional(),
30
+ filePath: z.string(),
31
+ createdAt: z.number(),
32
+ lastUsed: z.number(),
33
+ isActive: z.boolean(),
34
+ });
35
+
36
+ /**
37
+ * 创建日志本请求Schema
38
+ */
39
+ export const CreateLogBookRequestSchema = z.object({
40
+ id: z.string(),
41
+ name: z.string(),
42
+ description: z.string().optional(),
43
+ filePath: z.string().optional(),
44
+ logFileName: z.string().optional(),
45
+ autoCreateFile: z.boolean().optional().default(true),
46
+ });
47
+
48
+ /**
49
+ * 更新日志本请求Schema
50
+ */
51
+ export const UpdateLogBookRequestSchema = z.object({
52
+ name: z.string().optional(),
53
+ description: z.string().optional(),
54
+ isActive: z.boolean().optional(),
55
+ });
56
+
57
+ /**
58
+ * 连接操作员到日志本请求Schema
59
+ */
60
+ export const ConnectOperatorToLogBookRequestSchema = z.object({
61
+ operatorId: z.string(),
62
+ logBookId: z.string(),
63
+ });
64
+
65
+ /**
66
+ * 日志本统计信息Schema
67
+ */
68
+ export const LogBookStatisticsSchema = z.object({
69
+ totalQSOs: z.number(),
70
+ totalOperators: z.number(),
71
+ uniqueCallsigns: z.number(),
72
+ lastQSO: z.string().optional(),
73
+ firstQSO: z.string().optional(),
74
+ dxcc: LogBookDxccSummarySchema.optional(),
75
+ });
76
+
77
+ /**
78
+ * 日志本列表响应Schema
79
+ */
80
+ export const LogBookListResponseSchema = z.object({
81
+ success: z.boolean(),
82
+ data: z.array(LogBookInfoSchema),
83
+ });
84
+
85
+ /**
86
+ * 日志本详情响应Schema
87
+ */
88
+ export const LogBookDetailResponseSchema = z.object({
89
+ success: z.boolean(),
90
+ data: LogBookInfoSchema.merge(z.object({
91
+ statistics: LogBookStatisticsSchema,
92
+ connectedOperators: z.array(z.string()),
93
+ })),
94
+ });
95
+
96
+ /**
97
+ * 日志本操作响应Schema
98
+ */
99
+ export const LogBookActionResponseSchema = z.object({
100
+ success: z.boolean(),
101
+ message: z.string(),
102
+ data: LogBookInfoSchema.optional(),
103
+ });
104
+
105
+ /**
106
+ * 日志本QSO查询选项Schema
107
+ */
108
+ export const LogBookQSOQueryOptionsSchema = z.object({
109
+ callsign: z.string().optional(),
110
+ grid: z.string().optional(),
111
+ band: z.string().optional(),
112
+ mode: z.string().optional(),
113
+ dxccStatus: z.enum(['deleted']).optional(),
114
+ qslFlow: z.enum(['two_way_confirmed', 'not_two_way_confirmed']).optional(),
115
+ /** 排除的模式列表,逗号分隔,如 "FT8,FT4" */
116
+ excludeModes: z.string().optional(),
117
+ startDate: z.string().optional(),
118
+ endDate: z.string().optional(),
119
+ qslStatus: z.enum(['confirmed', 'uploaded', 'none']).optional(),
120
+ limit: z.coerce.number().optional().default(100),
121
+ offset: z.coerce.number().optional().default(0),
122
+ });
123
+
124
+ export const LogBookRecentGlobeQuerySchema = z.object({
125
+ operatorId: z.string().optional(),
126
+ hours: z.coerce.number().int().min(1).max(168).optional().default(24),
127
+ limit: z.coerce.number().int().min(1).max(500).optional().default(300),
128
+ });
129
+
130
+ export const LogBookRecentGlobeHomeSourceSchema = z.enum([
131
+ 'operator_grid',
132
+ 'station_coordinates',
133
+ 'station_grid',
134
+ ]);
135
+
136
+ export const LogBookRecentGlobeHomeSchema = z.object({
137
+ source: LogBookRecentGlobeHomeSourceSchema,
138
+ grid: z.string().optional(),
139
+ latitude: z.number().min(-90).max(90),
140
+ longitude: z.number().min(-180).max(180),
141
+ });
142
+
143
+ export const LogBookRecentGlobeItemSchema = z.object({
144
+ id: z.string(),
145
+ callsign: z.string(),
146
+ startTime: z.number(),
147
+ mode: z.string(),
148
+ frequency: z.number(),
149
+ grid: z.string(),
150
+ });
151
+
152
+ export const LogBookRecentGlobeResponseSchema = z.object({
153
+ success: z.boolean(),
154
+ data: z.object({
155
+ home: LogBookRecentGlobeHomeSchema.nullable(),
156
+ items: z.array(LogBookRecentGlobeItemSchema),
157
+ meta: z.object({
158
+ hours: z.number().int().min(1),
159
+ totalReturned: z.number().int().nonnegative(),
160
+ droppedInvalidGrid: z.number().int().nonnegative(),
161
+ limited: z.boolean(),
162
+ }),
163
+ }),
164
+ });
165
+
166
+ export const LogBookWorkedGridQuerySchema = z.object({
167
+ band: z.string().optional(),
168
+ });
169
+
170
+ export const LogBookWorkedGridItemSchema = z.object({
171
+ grid: z.string().regex(/^[A-R]{2}[0-9]{2}$/),
172
+ count: z.number().int().positive(),
173
+ });
174
+
175
+ export const LogBookWorkedGridResponseSchema = z.object({
176
+ success: z.boolean(),
177
+ data: z.object({
178
+ items: z.array(LogBookWorkedGridItemSchema),
179
+ meta: z.object({
180
+ band: z.string().optional(),
181
+ total: z.number().int().nonnegative(),
182
+ }),
183
+ }),
184
+ });
185
+
186
+ /**
187
+ * 日志本导出选项Schema
188
+ */
189
+ export const LogBookExportOptionsSchema = z.object({
190
+ format: z.enum(['adif', 'csv']).default('adif'),
191
+ startDate: z.string().optional(),
192
+ endDate: z.string().optional(),
193
+ callsign: z.string().optional(),
194
+ });
195
+
196
+ export const LogBookImportFormatSchema = z.enum(['adif', 'csv']);
197
+
198
+ export const LogBookImportResultSchema = z.object({
199
+ detectedFormat: LogBookImportFormatSchema,
200
+ totalRead: z.number().int().nonnegative(),
201
+ imported: z.number().int().nonnegative(),
202
+ merged: z.number().int().nonnegative(),
203
+ skipped: z.number().int().nonnegative(),
204
+ });
205
+
206
+ export const LogBookImportResponseSchema = z.object({
207
+ success: z.boolean(),
208
+ message: z.string(),
209
+ data: LogBookImportResultSchema,
210
+ });
211
+
212
+ /**
213
+ * 更新QSO记录请求Schema
214
+ */
215
+ export const UpdateQSORequestSchema = z.object({
216
+ callsign: z.string().optional(),
217
+ grid: z.string().optional(),
218
+ qth: z.string().optional(),
219
+ frequency: z.number().optional(),
220
+ mode: z.string().optional(),
221
+ submode: z.string().optional(),
222
+ startTime: z.number().optional(),
223
+ endTime: z.number().optional(),
224
+ reportSent: z.string().optional(),
225
+ reportReceived: z.string().optional(),
226
+ messageHistory: z.array(z.string()).optional(),
227
+ comment: z.string().optional(),
228
+ myGrid: z.string().optional(),
229
+ myCallsign: z.string().optional(),
230
+ // QSL 确认状态
231
+ lotwQslSent: z.enum(['Y', 'N', 'R', 'Q', 'I']).optional(),
232
+ lotwQslReceived: z.enum(['Y', 'N', 'R', 'I', 'V']).optional(),
233
+ lotwQslSentDate: z.number().optional(),
234
+ lotwQslReceivedDate: z.number().optional(),
235
+ qrzQslSent: z.enum(['Y', 'N']).optional(),
236
+ qrzQslReceived: z.enum(['Y', 'N']).optional(),
237
+ qrzQslSentDate: z.number().optional(),
238
+ qrzQslReceivedDate: z.number().optional(),
239
+ notes: z.string().optional(),
240
+ });
241
+
242
+ /**
243
+ * 手动补录QSO记录请求Schema
244
+ */
245
+ export const CreateQSORequestSchema = z.object({
246
+ callsign: z.string().min(1),
247
+ frequency: z.number().positive(),
248
+ mode: z.string().min(1),
249
+ submode: z.string().optional(),
250
+ startTime: z.number().positive(),
251
+ endTime: z.number().optional(),
252
+ grid: z.string().optional(),
253
+ qth: z.string().optional(),
254
+ reportSent: z.string().optional(),
255
+ reportReceived: z.string().optional(),
256
+ messageHistory: z.array(z.string()).optional().default([]),
257
+ comment: z.string().optional(),
258
+ notes: z.string().optional(),
259
+ });
260
+ export type CreateQSORequest = z.infer<typeof CreateQSORequestSchema>;
261
+
262
+ /**
263
+ * QSO操作响应Schema
264
+ */
265
+ export const QSOActionResponseSchema = z.object({
266
+ success: z.boolean(),
267
+ message: z.string(),
268
+ data: z.object({
269
+ id: z.string(),
270
+ callsign: z.string(),
271
+ grid: z.string().optional(),
272
+ frequency: z.number(),
273
+ mode: z.string(),
274
+ submode: z.string().optional(),
275
+ startTime: z.number(),
276
+ endTime: z.number().optional(),
277
+ reportSent: z.string().optional(),
278
+ reportReceived: z.string().optional(),
279
+ messageHistory: z.array(z.string()),
280
+ comment: z.string().optional(),
281
+ notes: z.string().optional(),
282
+ }).optional(),
283
+ });
284
+
285
+ // ========== 类型导出 ==========
286
+
287
+ export type LogBookInfo = z.infer<typeof LogBookInfoSchema>;
288
+ export type CreateLogBookRequest = z.infer<typeof CreateLogBookRequestSchema>;
289
+ export type UpdateLogBookRequest = z.infer<typeof UpdateLogBookRequestSchema>;
290
+ export type ConnectOperatorToLogBookRequest = z.infer<typeof ConnectOperatorToLogBookRequestSchema>;
291
+ export type LogBookStatistics = z.infer<typeof LogBookStatisticsSchema>;
292
+ export type LogBookDxccSummary = z.infer<typeof LogBookDxccSummarySchema>;
293
+ export type LogBookListResponse = z.infer<typeof LogBookListResponseSchema>;
294
+ export type LogBookDetailResponse = z.infer<typeof LogBookDetailResponseSchema>;
295
+ export type LogBookActionResponse = z.infer<typeof LogBookActionResponseSchema>;
296
+ export type LogBookQSOQueryOptions = z.infer<typeof LogBookQSOQueryOptionsSchema>;
297
+ export type LogBookRecentGlobeQuery = z.infer<typeof LogBookRecentGlobeQuerySchema>;
298
+ export type LogBookRecentGlobeHomeSource = z.infer<typeof LogBookRecentGlobeHomeSourceSchema>;
299
+ export type LogBookRecentGlobeHome = z.infer<typeof LogBookRecentGlobeHomeSchema>;
300
+ export type LogBookRecentGlobeItem = z.infer<typeof LogBookRecentGlobeItemSchema>;
301
+ export type LogBookRecentGlobeResponse = z.infer<typeof LogBookRecentGlobeResponseSchema>;
302
+ export type LogBookWorkedGridQuery = z.infer<typeof LogBookWorkedGridQuerySchema>;
303
+ export type LogBookWorkedGridItem = z.infer<typeof LogBookWorkedGridItemSchema>;
304
+ export type LogBookWorkedGridResponse = z.infer<typeof LogBookWorkedGridResponseSchema>;
305
+ export type LogBookExportOptions = z.infer<typeof LogBookExportOptionsSchema>;
306
+ export type LogBookImportFormat = z.infer<typeof LogBookImportFormatSchema>;
307
+ export type LogBookImportResult = z.infer<typeof LogBookImportResultSchema>;
308
+ export type LogBookImportResponse = z.infer<typeof LogBookImportResponseSchema>;
309
+ export type UpdateQSORequest = z.infer<typeof UpdateQSORequestSchema>;
310
+ export type QSOActionResponse = z.infer<typeof QSOActionResponseSchema>;