@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.
Files changed (255) hide show
  1. package/dist/index.d.ts +7 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +6 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/schema/__tests__/android-operator-audio.schema.test.d.ts +2 -0
  6. package/dist/schema/__tests__/android-operator-audio.schema.test.d.ts.map +1 -0
  7. package/dist/schema/__tests__/android-operator-audio.schema.test.js +27 -0
  8. package/dist/schema/__tests__/android-operator-audio.schema.test.js.map +1 -0
  9. package/dist/schema/__tests__/assisted-queue.schema.test.d.ts +2 -0
  10. package/dist/schema/__tests__/assisted-queue.schema.test.d.ts.map +1 -0
  11. package/dist/schema/__tests__/assisted-queue.schema.test.js +114 -0
  12. package/dist/schema/__tests__/assisted-queue.schema.test.js.map +1 -0
  13. package/dist/schema/__tests__/audio-sidecar.schema.test.d.ts +2 -0
  14. package/dist/schema/__tests__/audio-sidecar.schema.test.d.ts.map +1 -0
  15. package/dist/schema/__tests__/audio-sidecar.schema.test.js +42 -0
  16. package/dist/schema/__tests__/audio-sidecar.schema.test.js.map +1 -0
  17. package/dist/schema/__tests__/audio.schema.test.js +92 -1
  18. package/dist/schema/__tests__/audio.schema.test.js.map +1 -1
  19. package/dist/schema/__tests__/diagnostics.schema.test.d.ts +2 -0
  20. package/dist/schema/__tests__/diagnostics.schema.test.d.ts.map +1 -0
  21. package/dist/schema/__tests__/diagnostics.schema.test.js +31 -0
  22. package/dist/schema/__tests__/diagnostics.schema.test.js.map +1 -0
  23. package/dist/schema/__tests__/logbook-health.schema.test.d.ts +2 -0
  24. package/dist/schema/__tests__/logbook-health.schema.test.d.ts.map +1 -0
  25. package/dist/schema/__tests__/logbook-health.schema.test.js +104 -0
  26. package/dist/schema/__tests__/logbook-health.schema.test.js.map +1 -0
  27. package/dist/schema/__tests__/meter.schema.test.d.ts +2 -0
  28. package/dist/schema/__tests__/meter.schema.test.d.ts.map +1 -0
  29. package/dist/schema/__tests__/meter.schema.test.js +27 -0
  30. package/dist/schema/__tests__/meter.schema.test.js.map +1 -0
  31. package/dist/schema/__tests__/observability.schema.test.d.ts +2 -0
  32. package/dist/schema/__tests__/observability.schema.test.d.ts.map +1 -0
  33. package/dist/schema/__tests__/observability.schema.test.js +12 -0
  34. package/dist/schema/__tests__/observability.schema.test.js.map +1 -0
  35. package/dist/schema/__tests__/operator-context-report.schema.test.d.ts +2 -0
  36. package/dist/schema/__tests__/operator-context-report.schema.test.d.ts.map +1 -0
  37. package/dist/schema/__tests__/operator-context-report.schema.test.js +70 -0
  38. package/dist/schema/__tests__/operator-context-report.schema.test.js.map +1 -0
  39. package/dist/schema/__tests__/operator.schema.test.js +9 -3
  40. package/dist/schema/__tests__/operator.schema.test.js.map +1 -1
  41. package/dist/schema/__tests__/plugin-market.schema.test.js +149 -3
  42. package/dist/schema/__tests__/plugin-market.schema.test.js.map +1 -1
  43. package/dist/schema/__tests__/qso.schema.test.d.ts +2 -0
  44. package/dist/schema/__tests__/qso.schema.test.d.ts.map +1 -0
  45. package/dist/schema/__tests__/qso.schema.test.js +70 -0
  46. package/dist/schema/__tests__/qso.schema.test.js.map +1 -0
  47. package/dist/schema/__tests__/radio-power-support.test.js +15 -0
  48. package/dist/schema/__tests__/radio-power-support.test.js.map +1 -1
  49. package/dist/schema/__tests__/radio-profile.schema.test.d.ts +2 -0
  50. package/dist/schema/__tests__/radio-profile.schema.test.d.ts.map +1 -0
  51. package/dist/schema/__tests__/radio-profile.schema.test.js +36 -0
  52. package/dist/schema/__tests__/radio-profile.schema.test.js.map +1 -0
  53. package/dist/schema/__tests__/radio.schema.test.js +92 -1
  54. package/dist/schema/__tests__/radio.schema.test.js.map +1 -1
  55. package/dist/schema/__tests__/realtime-settings.schema.test.js +2 -1
  56. package/dist/schema/__tests__/realtime-settings.schema.test.js.map +1 -1
  57. package/dist/schema/__tests__/remote-access.schema.test.d.ts +2 -0
  58. package/dist/schema/__tests__/remote-access.schema.test.d.ts.map +1 -0
  59. package/dist/schema/__tests__/remote-access.schema.test.js +18 -0
  60. package/dist/schema/__tests__/remote-access.schema.test.js.map +1 -0
  61. package/dist/schema/__tests__/spectrum.schema.test.d.ts +2 -0
  62. package/dist/schema/__tests__/spectrum.schema.test.d.ts.map +1 -0
  63. package/dist/schema/__tests__/spectrum.schema.test.js +107 -0
  64. package/dist/schema/__tests__/spectrum.schema.test.js.map +1 -0
  65. package/dist/schema/__tests__/strategy-transmission.schema.test.d.ts +2 -0
  66. package/dist/schema/__tests__/strategy-transmission.schema.test.d.ts.map +1 -0
  67. package/dist/schema/__tests__/strategy-transmission.schema.test.js +95 -0
  68. package/dist/schema/__tests__/strategy-transmission.schema.test.js.map +1 -0
  69. package/dist/schema/android-operator-audio.schema.d.ts +174 -0
  70. package/dist/schema/android-operator-audio.schema.d.ts.map +1 -0
  71. package/dist/schema/android-operator-audio.schema.js +38 -0
  72. package/dist/schema/android-operator-audio.schema.js.map +1 -0
  73. package/dist/schema/api-response.schema.d.ts +503 -44
  74. package/dist/schema/api-response.schema.d.ts.map +1 -1
  75. package/dist/schema/api-response.schema.js +9 -0
  76. package/dist/schema/api-response.schema.js.map +1 -1
  77. package/dist/schema/audio-sidecar.schema.d.ts +75 -0
  78. package/dist/schema/audio-sidecar.schema.d.ts.map +1 -1
  79. package/dist/schema/audio-sidecar.schema.js +32 -0
  80. package/dist/schema/audio-sidecar.schema.js.map +1 -1
  81. package/dist/schema/audio.schema.d.ts +4749 -3
  82. package/dist/schema/audio.schema.d.ts.map +1 -1
  83. package/dist/schema/audio.schema.js +101 -2
  84. package/dist/schema/audio.schema.js.map +1 -1
  85. package/dist/schema/auth.schema.d.ts +173 -14
  86. package/dist/schema/auth.schema.d.ts.map +1 -1
  87. package/dist/schema/auth.schema.js +65 -1
  88. package/dist/schema/auth.schema.js.map +1 -1
  89. package/dist/schema/cpu-profile.schema.d.ts +2 -2
  90. package/dist/schema/cw-decoder.schema.d.ts +74 -74
  91. package/dist/schema/cw-keyer.schema.d.ts +20 -14
  92. package/dist/schema/cw-keyer.schema.d.ts.map +1 -1
  93. package/dist/schema/cw-keyer.schema.js +3 -0
  94. package/dist/schema/cw-keyer.schema.js.map +1 -1
  95. package/dist/schema/desktop-https.schema.d.ts +6 -6
  96. package/dist/schema/device-ui.schema.d.ts +16 -16
  97. package/dist/schema/diagnostics.schema.d.ts +163 -0
  98. package/dist/schema/diagnostics.schema.d.ts.map +1 -0
  99. package/dist/schema/diagnostics.schema.js +46 -0
  100. package/dist/schema/diagnostics.schema.js.map +1 -0
  101. package/dist/schema/ft8.schema.d.ts +12 -2
  102. package/dist/schema/ft8.schema.d.ts.map +1 -1
  103. package/dist/schema/ft8.schema.js +8 -0
  104. package/dist/schema/ft8.schema.js.map +1 -1
  105. package/dist/schema/image-radio.schema.d.ts +2597 -0
  106. package/dist/schema/image-radio.schema.d.ts.map +1 -0
  107. package/dist/schema/image-radio.schema.js +283 -0
  108. package/dist/schema/image-radio.schema.js.map +1 -0
  109. package/dist/schema/logbook.schema.d.ts +2128 -18
  110. package/dist/schema/logbook.schema.d.ts.map +1 -1
  111. package/dist/schema/logbook.schema.js +159 -1
  112. package/dist/schema/logbook.schema.js.map +1 -1
  113. package/dist/schema/mode.schema.d.ts +4 -6
  114. package/dist/schema/mode.schema.d.ts.map +1 -1
  115. package/dist/schema/mode.schema.js +18 -6
  116. package/dist/schema/mode.schema.js.map +1 -1
  117. package/dist/schema/observability.schema.d.ts +66 -0
  118. package/dist/schema/observability.schema.d.ts.map +1 -0
  119. package/dist/schema/observability.schema.js +20 -0
  120. package/dist/schema/observability.schema.js.map +1 -0
  121. package/dist/schema/openwebrx.schema.d.ts +2 -2
  122. package/dist/schema/operator.schema.d.ts +2682 -6
  123. package/dist/schema/operator.schema.d.ts.map +1 -1
  124. package/dist/schema/operator.schema.js +10 -20
  125. package/dist/schema/operator.schema.js.map +1 -1
  126. package/dist/schema/plugin.schema.d.ts +1977 -492
  127. package/dist/schema/plugin.schema.d.ts.map +1 -1
  128. package/dist/schema/plugin.schema.js +165 -14
  129. package/dist/schema/plugin.schema.js.map +1 -1
  130. package/dist/schema/process-monitor.schema.d.ts +132 -132
  131. package/dist/schema/pskreporter.schema.d.ts +1 -3
  132. package/dist/schema/pskreporter.schema.d.ts.map +1 -1
  133. package/dist/schema/pskreporter.schema.js +1 -3
  134. package/dist/schema/pskreporter.schema.js.map +1 -1
  135. package/dist/schema/qso.schema.d.ts +246 -1
  136. package/dist/schema/qso.schema.d.ts.map +1 -1
  137. package/dist/schema/qso.schema.js +68 -0
  138. package/dist/schema/qso.schema.js.map +1 -1
  139. package/dist/schema/radio-capability.schema.d.ts +31 -40
  140. package/dist/schema/radio-capability.schema.d.ts.map +1 -1
  141. package/dist/schema/radio-capability.schema.js +8 -15
  142. package/dist/schema/radio-capability.schema.js.map +1 -1
  143. package/dist/schema/radio-power-support.d.ts.map +1 -1
  144. package/dist/schema/radio-power-support.js +3 -0
  145. package/dist/schema/radio-power-support.js.map +1 -1
  146. package/dist/schema/radio-power.schema.d.ts +102 -13
  147. package/dist/schema/radio-power.schema.d.ts.map +1 -1
  148. package/dist/schema/radio-power.schema.js +15 -8
  149. package/dist/schema/radio-power.schema.js.map +1 -1
  150. package/dist/schema/radio-profile.schema.d.ts +1491 -97
  151. package/dist/schema/radio-profile.schema.d.ts.map +1 -1
  152. package/dist/schema/radio-profile.schema.js +7 -0
  153. package/dist/schema/radio-profile.schema.js.map +1 -1
  154. package/dist/schema/radio.schema.d.ts +442 -48
  155. package/dist/schema/radio.schema.d.ts.map +1 -1
  156. package/dist/schema/radio.schema.js +75 -7
  157. package/dist/schema/radio.schema.js.map +1 -1
  158. package/dist/schema/realtime.schema.d.ts +60 -52
  159. package/dist/schema/realtime.schema.d.ts.map +1 -1
  160. package/dist/schema/realtime.schema.js +9 -1
  161. package/dist/schema/realtime.schema.js.map +1 -1
  162. package/dist/schema/rigctld.schema.d.ts +6 -6
  163. package/dist/schema/slot-info.schema.d.ts +28 -9
  164. package/dist/schema/slot-info.schema.d.ts.map +1 -1
  165. package/dist/schema/slot-info.schema.js +17 -10
  166. package/dist/schema/slot-info.schema.js.map +1 -1
  167. package/dist/schema/spectrum-config.schema.d.ts +638 -0
  168. package/dist/schema/spectrum-config.schema.d.ts.map +1 -0
  169. package/dist/schema/spectrum-config.schema.js +129 -0
  170. package/dist/schema/spectrum-config.schema.js.map +1 -0
  171. package/dist/schema/spectrum.schema.d.ts +1323 -30
  172. package/dist/schema/spectrum.schema.d.ts.map +1 -1
  173. package/dist/schema/spectrum.schema.js +72 -0
  174. package/dist/schema/spectrum.schema.js.map +1 -1
  175. package/dist/schema/station-info.schema.d.ts +5 -0
  176. package/dist/schema/station-info.schema.d.ts.map +1 -1
  177. package/dist/schema/station-info.schema.js +5 -0
  178. package/dist/schema/station-info.schema.js.map +1 -1
  179. package/dist/schema/system.schema.d.ts +56 -6
  180. package/dist/schema/system.schema.d.ts.map +1 -1
  181. package/dist/schema/system.schema.js +22 -0
  182. package/dist/schema/system.schema.js.map +1 -1
  183. package/dist/schema/transmission.schema.d.ts +8 -7
  184. package/dist/schema/transmission.schema.d.ts.map +1 -1
  185. package/dist/schema/transmission.schema.js +2 -7
  186. package/dist/schema/transmission.schema.js.map +1 -1
  187. package/dist/schema/tx-audio-input.schema.d.ts +8 -0
  188. package/dist/schema/tx-audio-input.schema.d.ts.map +1 -0
  189. package/dist/schema/tx-audio-input.schema.js +19 -0
  190. package/dist/schema/tx-audio-input.schema.js.map +1 -0
  191. package/dist/schema/voice-keyer.schema.d.ts +16 -16
  192. package/dist/schema/voice.schema.d.ts +1 -1
  193. package/dist/schema/voice.schema.d.ts.map +1 -1
  194. package/dist/schema/voice.schema.js +1 -1
  195. package/dist/schema/voice.schema.js.map +1 -1
  196. package/dist/schema/websocket.schema.d.ts +35811 -7829
  197. package/dist/schema/websocket.schema.d.ts.map +1 -1
  198. package/dist/schema/websocket.schema.js +453 -9
  199. package/dist/schema/websocket.schema.js.map +1 -1
  200. package/package.json +6 -1
  201. package/src/index.ts +7 -0
  202. package/src/schema/__tests__/android-operator-audio.schema.test.ts +31 -0
  203. package/src/schema/__tests__/assisted-queue.schema.test.ts +122 -0
  204. package/src/schema/__tests__/audio-sidecar.schema.test.ts +48 -0
  205. package/src/schema/__tests__/audio.schema.test.ts +102 -0
  206. package/src/schema/__tests__/diagnostics.schema.test.ts +32 -0
  207. package/src/schema/__tests__/logbook-health.schema.test.ts +117 -0
  208. package/src/schema/__tests__/meter.schema.test.ts +28 -0
  209. package/src/schema/__tests__/observability.schema.test.ts +15 -0
  210. package/src/schema/__tests__/operator-context-report.schema.test.ts +77 -0
  211. package/src/schema/__tests__/operator.schema.test.ts +11 -3
  212. package/src/schema/__tests__/plugin-market.schema.test.ts +165 -2
  213. package/src/schema/__tests__/qso.schema.test.ts +91 -0
  214. package/src/schema/__tests__/radio-power-support.test.ts +17 -0
  215. package/src/schema/__tests__/radio-profile.schema.test.ts +44 -0
  216. package/src/schema/__tests__/radio.schema.test.ts +108 -1
  217. package/src/schema/__tests__/realtime-settings.schema.test.ts +2 -1
  218. package/src/schema/__tests__/remote-access.schema.test.ts +22 -0
  219. package/src/schema/__tests__/spectrum.schema.test.ts +119 -0
  220. package/src/schema/__tests__/strategy-transmission.schema.test.ts +106 -0
  221. package/src/schema/android-operator-audio.schema.ts +49 -0
  222. package/src/schema/api-response.schema.ts +11 -0
  223. package/src/schema/audio-sidecar.schema.ts +35 -0
  224. package/src/schema/audio.schema.ts +115 -2
  225. package/src/schema/auth.schema.ts +79 -1
  226. package/src/schema/cw-keyer.schema.ts +5 -0
  227. package/src/schema/diagnostics.schema.ts +55 -0
  228. package/src/schema/ft8.schema.ts +8 -0
  229. package/src/schema/image-radio.schema.ts +342 -0
  230. package/src/schema/logbook.schema.ts +205 -1
  231. package/src/schema/mode.schema.ts +18 -6
  232. package/src/schema/observability.schema.ts +26 -0
  233. package/src/schema/operator.schema.ts +11 -20
  234. package/src/schema/plugin.schema.ts +186 -15
  235. package/src/schema/pskreporter.schema.ts +1 -3
  236. package/src/schema/qso.schema.ts +78 -0
  237. package/src/schema/radio-capability.schema.ts +8 -15
  238. package/src/schema/radio-power-support.ts +3 -0
  239. package/src/schema/radio-power.schema.ts +15 -8
  240. package/src/schema/radio-profile.schema.ts +7 -0
  241. package/src/schema/radio.schema.ts +90 -7
  242. package/src/schema/realtime.schema.ts +9 -1
  243. package/src/schema/slot-info.schema.ts +18 -11
  244. package/src/schema/spectrum-config.schema.ts +156 -0
  245. package/src/schema/spectrum.schema.ts +89 -0
  246. package/src/schema/station-info.schema.ts +5 -0
  247. package/src/schema/system.schema.ts +29 -0
  248. package/src/schema/transmission.schema.ts +2 -7
  249. package/src/schema/tx-audio-input.schema.ts +22 -0
  250. package/src/schema/voice.schema.ts +1 -1
  251. package/src/schema/websocket.schema.ts +601 -13
  252. package/test/image-radio-schema.test.ts +107 -0
  253. package/test/plugin-slot-schema.test.ts +31 -0
  254. package/test/radio-capability-schema.test.ts +44 -0
  255. package/CLAUDE.md +0 -41
@@ -2,16 +2,17 @@ import { z } from 'zod';
2
2
  import { SlotPackSchema, SlotInfoSchema, SlotPackFrequencyContextSchema } from './slot-info.schema.js';
3
3
  import { PluginDataPayloadSchema, PluginLogEntrySchema, PluginRuntimeLogEntrySchema, PluginRuntimeLogHistoryPayloadSchema, PluginSystemSnapshotSchema, PluginStatusSchema, PluginUserActionPayloadSchema, } from './plugin.schema.js';
4
4
  import { ModeDescriptorSchema } from './mode.schema.js';
5
- import { QSORecordSchema } from './qso.schema.js';
6
- import { LogBookStatisticsSchema } from './logbook.schema.js';
5
+ import { QSORecordSchema, } from './qso.schema.js';
6
+ import { LogBookStatisticsSchema, LogbookHealthSchema, LogbookOperationErrorCodeSchema, } from './logbook.schema.js';
7
7
  import { RadioInfoSchema, HamlibConfigSchema, TunerCapabilitiesSchema, RadioConnectionStatusSchema, ReconnectProgressSchema, CoreRadioCapabilitiesSchema, CoreCapabilityDiagnosticsSchema } from './radio.schema.js';
8
8
  import { UserRole } from './auth.schema.js';
9
9
  import { CWDecoderEventSchema, CWDecoderStatusSchema } from './cw-decoder.schema.js';
10
10
  import { CapabilityListSchema, CapabilityStateSchema, WriteCapabilityPayloadSchema } from './radio-capability.schema.js';
11
11
  import { RadioPowerStateEventSchema } from './radio-power.schema.js';
12
12
  import { AudioSidecarStatusPayloadSchema } from './audio-sidecar.schema.js';
13
- import { SpectrumCapabilitiesSchema, SpectrumFrameSchema, SpectrumKindSchema, SpectrumSessionControlActionSchema, SpectrumSessionControlIdSchema, SpectrumSessionStateSchema } from './spectrum.schema.js';
13
+ import { SpectrumCapabilitiesSchema, SpectrumFrameSchema, SpectrumKindSchema, SpectrumSessionControlActionSchema, SpectrumSessionControlIdSchema, SpectrumSessionStateSchema, SpectrumViewportSchema } from './spectrum.schema.js';
14
14
  import { ClockStatusSummarySchema } from './system.schema.js';
15
+ import { ImageRadioStatusSchema, ImageRxEventSchema, ImageRxSubscriptionSchema, FaxCalibrationCommandResultSchema, FaxCalibrationResetCommandSchema, FaxCalibrationSetCommandSchema, SstvTxCancelCommandSchema, SstvTxCommandResultSchema, SstvTxStartCommandSchema, SstvTxStatusSchema, } from './image-radio.schema.js';
15
16
  // WebSocket消息类型枚举
16
17
  export var WSMessageType;
17
18
  (function (WSMessageType) {
@@ -26,6 +27,16 @@ export var WSMessageType;
26
27
  WSMessageType["STOP_ENGINE"] = "stopEngine";
27
28
  WSMessageType["GET_STATUS"] = "getStatus";
28
29
  WSMessageType["SET_MODE"] = "setMode";
30
+ WSMessageType["SUBSCRIBE_IMAGE_RX"] = "subscribeImageRx";
31
+ WSMessageType["IMAGE_RADIO_STATUS"] = "imageRadioStatus";
32
+ WSMessageType["IMAGE_RX_EVENT"] = "imageRxEvent";
33
+ WSMessageType["SSTV_TX_START"] = "sstvTxStart";
34
+ WSMessageType["SSTV_TX_CANCEL"] = "sstvTxCancel";
35
+ WSMessageType["SSTV_TX_STATUS"] = "sstvTxStatus";
36
+ WSMessageType["SSTV_TX_COMMAND_RESULT"] = "sstvTxCommandResult";
37
+ WSMessageType["FAX_CALIBRATION_SET"] = "faxCalibrationSet";
38
+ WSMessageType["FAX_CALIBRATION_RESET"] = "faxCalibrationReset";
39
+ WSMessageType["FAX_CALIBRATION_COMMAND_RESULT"] = "faxCalibrationCommandResult";
29
40
  // ===== 引擎事件 =====
30
41
  WSMessageType["MODE_CHANGED"] = "modeChanged";
31
42
  WSMessageType["SLOT_START"] = "slotStart";
@@ -37,6 +48,7 @@ export var WSMessageType;
37
48
  WSMessageType["SPECTRUM_FRAME"] = "spectrumFrame";
38
49
  WSMessageType["SPECTRUM_SESSION_STATE_CHANGED"] = "spectrumSessionStateChanged";
39
50
  WSMessageType["INVOKE_SPECTRUM_CONTROL"] = "invokeSpectrumControl";
51
+ WSMessageType["SPECTRUM_VIEWPORT_CHANGED"] = "spectrumViewportChanged";
40
52
  WSMessageType["DECODE_ERROR"] = "decodeError";
41
53
  WSMessageType["SYSTEM_STATUS"] = "systemStatus";
42
54
  WSMessageType["BOOTSTRAP_STATUS_CHANGED"] = "bootstrapStatusChanged";
@@ -49,11 +61,18 @@ export var WSMessageType;
49
61
  WSMessageType["OPERATOR_STATUS_UPDATE"] = "operatorStatusUpdate";
50
62
  WSMessageType["SET_OPERATOR_CONTEXT"] = "setOperatorContext";
51
63
  WSMessageType["SET_OPERATOR_RUNTIME_STATE"] = "setOperatorRuntimeState";
64
+ WSMessageType["SET_OPERATOR_STREAM_STATE"] = "setOperatorStreamState";
65
+ WSMessageType["INVOKE_OPERATOR_STRATEGY_ACTION"] = "invokeOperatorStrategyAction";
52
66
  WSMessageType["SET_OPERATOR_RUNTIME_SLOT_CONTENT"] = "setOperatorRuntimeSlotContent";
53
67
  WSMessageType["SET_OPERATOR_TRANSMIT_CYCLES"] = "setOperatorTransmitCycles";
54
68
  WSMessageType["START_OPERATOR"] = "startOperator";
55
69
  WSMessageType["STOP_OPERATOR"] = "stopOperator";
56
70
  WSMessageType["OPERATOR_REQUEST_CALL"] = "operatorRequestCall";
71
+ WSMessageType["OPERATOR_QUEUE_ENQUEUE"] = "operatorQueueEnqueue";
72
+ WSMessageType["OPERATOR_QUEUE_REORDER"] = "operatorQueueReorder";
73
+ WSMessageType["OPERATOR_QUEUE_RETRY"] = "operatorQueueRetry";
74
+ WSMessageType["OPERATOR_QUEUE_REMOVE"] = "operatorQueueRemove";
75
+ WSMessageType["OPERATOR_QUEUE_CLEAR"] = "operatorQueueClear";
57
76
  // ===== 客户端操作员过滤 =====
58
77
  WSMessageType["SET_CLIENT_ENABLED_OPERATORS"] = "setClientEnabledOperators";
59
78
  WSMessageType["SET_CLIENT_SELECTED_OPERATOR"] = "setClientSelectedOperator";
@@ -71,6 +90,8 @@ export var WSMessageType;
71
90
  WSMessageType["QSO_RECORD_ADDED"] = "qsoRecordAdded";
72
91
  WSMessageType["QSO_RECORD_UPDATED"] = "qsoRecordUpdated";
73
92
  WSMessageType["LOGBOOK_UPDATED"] = "logbookUpdated";
93
+ WSMessageType["LOGBOOK_HEALTH_CHANGED"] = "logbookHealthChanged";
94
+ WSMessageType["LOGBOOK_WRITE_FAILED"] = "logbookWriteFailed";
74
95
  // 仅通知的日志本变更事件(专用于日志本WS)
75
96
  WSMessageType["LOGBOOK_CHANGE_NOTICE"] = "logbookChangeNotice";
76
97
  // ===== 电台连接管理 =====
@@ -105,6 +126,8 @@ export var WSMessageType;
105
126
  WSMessageType["WRITE_RADIO_CAPABILITY"] = "writeRadioCapability";
106
127
  /** 客户端请求刷新所有能力值(client → server) */
107
128
  WSMessageType["REFRESH_RADIO_CAPABILITIES"] = "refreshRadioCapabilities";
129
+ /** 客户端设置 Split TX 频率(client → server) */
130
+ WSMessageType["SET_SPLIT_FREQUENCY"] = "setSplitFrequency";
108
131
  // ===== 电台重连控制 =====
109
132
  WSMessageType["RADIO_STOP_RECONNECT"] = "radioStopReconnect";
110
133
  // ===== 音频旁路(sidecar) =====
@@ -125,6 +148,7 @@ export var WSMessageType;
125
148
  WSMessageType["AUTH_PUBLIC_VIEWER"] = "authPublicViewer";
126
149
  WSMessageType["AUTH_RESULT"] = "authResult";
127
150
  WSMessageType["AUTH_EXPIRED"] = "authExpired";
151
+ WSMessageType["ACCESS_DENIED"] = "accessDenied";
128
152
  // ===== 语音模式 =====
129
153
  WSMessageType["VOICE_PTT_REQUEST"] = "voicePttRequest";
130
154
  WSMessageType["VOICE_PTT_RELEASE"] = "voicePttRelease";
@@ -134,6 +158,7 @@ export var WSMessageType;
134
158
  WSMessageType["VOICE_KEYER_PLAY"] = "voiceKeyerPlay";
135
159
  WSMessageType["VOICE_KEYER_STOP"] = "voiceKeyerStop";
136
160
  WSMessageType["VOICE_KEYER_STATUS_CHANGED"] = "voiceKeyerStatusChanged";
161
+ WSMessageType["ANDROID_OPERATOR_AUDIO_STATUS_CHANGED"] = "androidOperatorAudioStatusChanged";
137
162
  // ===== CW 模式 =====
138
163
  /** CW 键控器状态变化(server → client) */
139
164
  WSMessageType["CW_KEYER_STATUS"] = "cwKeyerStatus";
@@ -188,7 +213,7 @@ export const SystemStatusSchema = z.object({
188
213
  connectionHealthy: z.boolean(),
189
214
  }).optional(),
190
215
  /** 引擎模式:digital(FT8/FT4)、voice(语音通联)或 cw(莫尔斯码) */
191
- engineMode: z.enum(['digital', 'voice', 'cw']).default('digital'),
216
+ engineMode: z.enum(['digital', 'voice', 'cw', 'image']).default('digital'),
192
217
  /** 当前电台调制模式(语音模式下使用,如 USB/LSB/FM/AM) */
193
218
  currentRadioMode: z.string().optional(),
194
219
  /** 引擎状态机当前状态 */
@@ -269,7 +294,15 @@ export const DecodeErrorInfoSchema = z.object({
269
294
  windowIdx: z.number(),
270
295
  }),
271
296
  });
272
- // 频率状态数据结构
297
+ /**
298
+ * Current dial-frequency projection broadcast to plugins and clients.
299
+ *
300
+ * `frequency` is the logical RF dial target in hertz; `mode` is the TX-5DR
301
+ * engine mode; `band` and `description` are display labels; `radioMode` is the
302
+ * underlying modulation when known. `observedFrequency` is the latest physical
303
+ * readback. `source` distinguishes application changes from radio observations;
304
+ * `revision` and `connectionGeneration` reject stale events.
305
+ */
273
306
  export const FrequencyStateSchema = z.object({
274
307
  frequency: z.number(),
275
308
  mode: z.string(),
@@ -278,6 +311,20 @@ export const FrequencyStateSchema = z.object({
278
311
  radioMode: z.string().optional(),
279
312
  radioConnected: z.boolean(),
280
313
  source: z.enum(['program', 'radio']).optional(),
314
+ /** Monotonic operating-state revision for stale-event suppression. */
315
+ revision: z.number().int().nonnegative().optional(),
316
+ /** Physical CAT session identity associated with this snapshot. */
317
+ connectionGeneration: z.number().int().nonnegative().optional(),
318
+ /** Physical confirmation status for the requested operating state. */
319
+ confirmation: z.enum(['confirmed', 'pending', 'mismatch', 'offline']).optional(),
320
+ /** Last frequency read back from the physical radio, when available. */
321
+ observedFrequency: z.number().optional(),
322
+ /** Requested logical frequency when it differs from the observed value. */
323
+ requestedFrequency: z.number().optional(),
324
+ /** Correlates a snapshot with one programmatic operating-state mutation. */
325
+ operationId: z.string().optional(),
326
+ /** Physical radio-mode confirmation status. */
327
+ modeConfirmation: z.enum(['confirmed', 'unconfirmed', 'unknown']).optional(),
281
328
  });
282
329
  export const SpectrumControlInvocationSchema = z.object({
283
330
  id: SpectrumSessionControlIdSchema,
@@ -287,6 +334,9 @@ export const SpectrumControlInvocationSchema = z.object({
287
334
  export const PTTStatusSchema = z.object({
288
335
  isTransmitting: z.boolean(),
289
336
  operatorIds: z.array(z.string()),
337
+ phase: z.enum(['idle', 'starting', 'on_air', 'draining', 'stopping', 'unknown']).optional(),
338
+ frameId: z.string().optional(),
339
+ source: z.enum(['digital', 'voice', 'voice-keyer', 'cw', 'sstv', 'tune-tone', 'manual', 'test']).optional(),
290
340
  });
291
341
  export const TuneToneStartPayloadSchema = z.object({
292
342
  operatorId: z.string().optional(),
@@ -314,6 +364,172 @@ export const StrategyRuntimeContextSchema = z.object({
314
364
  reportReceived: z.number().optional(),
315
365
  actualFrequency: z.number().optional(),
316
366
  });
367
+ export const StrategyStateOptionSchema = z.object({
368
+ id: z.string().min(1),
369
+ label: z.string().min(1).optional(),
370
+ transmitText: z.string().optional(),
371
+ });
372
+ export const StrategyActionInputSchema = z.discriminatedUnion('kind', [
373
+ z.object({
374
+ kind: z.literal('text'),
375
+ label: z.string().optional(),
376
+ value: z.string().optional(),
377
+ placeholder: z.string().optional(),
378
+ maxLength: z.number().int().positive().optional(),
379
+ }),
380
+ z.object({
381
+ kind: z.enum(['number', 'audio-frequency']),
382
+ label: z.string().optional(),
383
+ value: z.number().optional(),
384
+ min: z.number().optional(),
385
+ max: z.number().optional(),
386
+ step: z.number().positive().optional(),
387
+ unit: z.string().optional(),
388
+ spectrumPick: z.boolean().optional(),
389
+ }),
390
+ ]);
391
+ export const StrategyActionDescriptorSchema = z.object({
392
+ id: z.string().min(1),
393
+ label: z.string().min(1),
394
+ description: z.string().optional(),
395
+ icon: z.string().optional(),
396
+ tone: z.enum(['default', 'primary', 'success', 'warning', 'danger']).optional(),
397
+ presentation: z.enum(['primary', 'secondary', 'menu', 'segmented']).optional(),
398
+ groupId: z.string().optional(),
399
+ selected: z.boolean().optional(),
400
+ disabledReason: z.string().optional(),
401
+ previewText: z.string().optional(),
402
+ confirmation: z.object({
403
+ title: z.string().min(1),
404
+ description: z.string().optional(),
405
+ confirmLabel: z.string().optional(),
406
+ cancelLabel: z.string().optional(),
407
+ }).optional(),
408
+ input: StrategyActionInputSchema.optional(),
409
+ navigation: z.object({
410
+ kind: z.literal('plugin-page'),
411
+ pageId: z.string().min(1),
412
+ }).optional(),
413
+ });
414
+ export const StrategyAttentionSchema = z.object({
415
+ id: z.string().min(1),
416
+ tone: z.enum(['info', 'warning', 'danger', 'success']),
417
+ title: z.string().min(1),
418
+ description: z.string().optional(),
419
+ params: z.record(z.string(), z.union([z.string(), z.number()])).optional(),
420
+ notify: z.boolean().optional(),
421
+ expiresAt: z.number().optional(),
422
+ actionIds: z.array(z.string()).optional(),
423
+ });
424
+ export const StrategyCompletionProjectionSchema = z.object({
425
+ state: z.enum(['not-ready', 'ready', 'committing', 'committed', 'failed']),
426
+ label: z.string().optional(),
427
+ recordId: z.string().optional(),
428
+ });
429
+ export const StrategyStreamSnapshotSchema = z.object({
430
+ streamId: z.string().min(1),
431
+ currentState: z.string(),
432
+ targetCallsign: z.string().optional(),
433
+ targetGrid: z.string().optional(),
434
+ audioFrequencyHz: z.number().min(0).max(5000),
435
+ qsoLifecycleEpoch: z.number().int().nonnegative(),
436
+ stateOptions: z.array(StrategyStateOptionSchema).optional(),
437
+ actions: z.array(StrategyActionDescriptorSchema).optional(),
438
+ attentions: z.array(StrategyAttentionSchema).optional(),
439
+ completion: StrategyCompletionProjectionSchema.optional(),
440
+ lastReceivedText: z.string().optional(),
441
+ nextTransmitText: z.string().optional(),
442
+ });
443
+ export const StrategyTransmissionSchema = z.object({
444
+ streamId: z.string().min(1),
445
+ text: z.string().min(1),
446
+ audioFrequencyHz: z.number().min(0).max(5000),
447
+ });
448
+ export const AssistedQueueDisplayStateSchema = z.enum([
449
+ 'TX1', 'TX2', 'TX3', 'TX4', 'TX5', 'engaged', 'closing', 'paused', 'no-response', 'later', 'review',
450
+ 'candidate', 'authorized', 'dupe',
451
+ ]);
452
+ export const AssistedQueuePauseReasonSchema = z.enum(['target-busy', 'stale']);
453
+ export const AssistedQueueToneSchema = z.enum(['neutral', 'active', 'success', 'warning', 'danger']);
454
+ export const AssistedQueueIconSchema = z.enum([
455
+ 'circle', 'radio', 'check-circle', 'loader-circle', 'clock', 'pause', 'triangle-alert',
456
+ ]);
457
+ export const AssistedQueueRowSchema = z.object({
458
+ entryId: z.string(),
459
+ callsign: z.string(),
460
+ order: z.number().int().nonnegative(),
461
+ draggable: z.boolean(),
462
+ displayState: AssistedQueueDisplayStateSchema,
463
+ tone: AssistedQueueToneSchema,
464
+ icon: AssistedQueueIconSchema,
465
+ pauseReason: AssistedQueuePauseReasonSchema.optional(),
466
+ noResponseCycles: z.number().int().nonnegative().optional(),
467
+ targetGrid: z.string().optional(),
468
+ lastSnr: z.number().optional(),
469
+ lastHeardCyclesAgo: z.number().int().nonnegative().optional(),
470
+ lastHeardCycle: z.union([z.literal(0), z.literal(1)]).optional(),
471
+ streamId: z.string().optional(),
472
+ audioFrequencyHz: z.number().optional(),
473
+ authorizationId: z.string().optional(),
474
+ actions: z.array(StrategyActionDescriptorSchema).optional(),
475
+ });
476
+ export const AssistedQueueSnapshotSchema = z.object({
477
+ version: z.number().int().nonnegative(),
478
+ activeEntryId: z.string().optional(),
479
+ activeEntryIds: z.array(z.string()).optional(),
480
+ maxActiveStreams: z.number().int().min(1).max(5).optional(),
481
+ requestedMaxActiveStreams: z.number().int().min(1).max(5).optional(),
482
+ rows: z.array(AssistedQueueRowSchema),
483
+ });
484
+ /** Null clears an unsettable runtime report field over JSON/WebSocket. */
485
+ export const OperatorContextReportFieldSchema = z.number().nullish();
486
+ export const StrategyMessagePresentationToneSchema = z.enum([
487
+ 'neutral', 'primary', 'secondary', 'success', 'warning', 'danger',
488
+ ]);
489
+ export const StrategyMessagePresentationBadgeSchema = z.object({
490
+ label: z.string().min(1),
491
+ tone: StrategyMessagePresentationToneSchema,
492
+ });
493
+ export const StrategyMessagePresentationTokenMatchSchema = z.object({
494
+ firstTokenIn: z.array(z.string().min(1)).optional(),
495
+ anyTokenIn: z.array(z.string().min(1)).optional(),
496
+ });
497
+ export const StrategyMessagePresentationClassSchema = z.object({
498
+ badge: StrategyMessagePresentationBadgeSchema.optional(),
499
+ badges: z.array(StrategyMessagePresentationBadgeSchema).optional(),
500
+ row: z.object({
501
+ tone: StrategyMessagePresentationToneSchema,
502
+ background: z.enum(['none', 'soft']).optional(),
503
+ accent: z.boolean().optional(),
504
+ }).optional(),
505
+ emphasisWhen: z.array(StrategyMessagePresentationTokenMatchSchema).min(1).optional(),
506
+ textDecoration: z.literal('line-through').optional(),
507
+ opacity: z.enum(['normal', 'muted']).optional(),
508
+ });
509
+ export const StrategyMessagePresentationProjectionSchema = z.object({
510
+ revision: z.number().int().nonnegative(),
511
+ mode: z.enum(['replace-logbook', 'augment']),
512
+ subject: z.literal('sender-callsign'),
513
+ partitionBy: z.enum(['band', 'mode', 'none']),
514
+ eligiblePartitions: z.array(z.string()).optional(),
515
+ defaultClass: z.string().optional(),
516
+ classes: z.record(z.string(), StrategyMessagePresentationClassSchema),
517
+ assignments: z.array(z.object({
518
+ subject: z.string().min(1),
519
+ partition: z.string().optional(),
520
+ classId: z.string().min(1),
521
+ })),
522
+ noveltyRules: z.array(z.object({
523
+ fact: z.literal('grid-field-2'),
524
+ knownValuesByPartition: z.record(z.string(), z.array(z.string().min(1))),
525
+ classId: z.string().min(1),
526
+ })).optional(),
527
+ tagRules: z.array(z.object({
528
+ id: z.string().min(1),
529
+ match: StrategyMessagePresentationTokenMatchSchema,
530
+ badge: StrategyMessagePresentationBadgeSchema,
531
+ })).optional(),
532
+ });
317
533
  export const StrategyRuntimeSnapshotSchema = z.object({
318
534
  currentState: z.string(),
319
535
  slots: z.object({
@@ -326,7 +542,31 @@ export const StrategyRuntimeSnapshotSchema = z.object({
326
542
  }).optional(),
327
543
  context: StrategyRuntimeContextSchema.optional(),
328
544
  availableSlots: z.array(z.string()).optional(),
545
+ qsoLifecycleEpoch: z.number().int().nonnegative().optional(),
546
+ streams: z.array(StrategyStreamSnapshotSchema).optional(),
547
+ queue: AssistedQueueSnapshotSchema.optional(),
548
+ actions: z.array(StrategyActionDescriptorSchema).optional(),
549
+ attentions: z.array(StrategyAttentionSchema).optional(),
550
+ messagePresentation: StrategyMessagePresentationProjectionSchema.optional(),
551
+ transmitGate: z.object({
552
+ allowed: z.literal(false),
553
+ reason: z.string().min(1),
554
+ actionId: z.string().optional(),
555
+ }).optional(),
329
556
  });
557
+ export const StrategyActionTargetSchema = z.discriminatedUnion('kind', [
558
+ z.object({ kind: z.literal('runtime') }),
559
+ z.object({
560
+ kind: z.literal('stream'),
561
+ streamId: z.string().min(1),
562
+ lifecycleEpoch: z.number().int().nonnegative(),
563
+ }),
564
+ z.object({
565
+ kind: z.literal('queue-entry'),
566
+ entryId: z.string().min(1),
567
+ queueVersion: z.number().int().nonnegative(),
568
+ }),
569
+ ]);
330
570
  export const LevelMeterDisplayStyleSchema = z.enum([
331
571
  's-meter-dbm',
332
572
  's-meter',
@@ -375,11 +615,12 @@ export const MeterDataSchema = z.object({
375
615
  raw: z.number(),
376
616
  percent: z.number(),
377
617
  alert: z.boolean(),
618
+ unit: z.enum(['percent', 'dbfs']).optional(),
378
619
  }).nullable(),
379
620
  level: LevelMeterReadingSchema.nullable(),
380
621
  power: z.object({
381
622
  raw: z.number(),
382
- percent: z.number(),
623
+ percent: z.number().nullable(),
383
624
  watts: z.number().nullable(), // 绝对瓦数(仅当电台支持 RFPOWER_METER_WATTS 时非 null)
384
625
  maxWatts: z.number().nullable(), // 当前频率+模式对应的量程瓦数
385
626
  }).nullable(),
@@ -405,6 +646,46 @@ export const WSModeChangedMessageSchema = WSBaseMessageSchema.extend({
405
646
  type: z.literal(WSMessageType.MODE_CHANGED),
406
647
  data: ModeDescriptorSchema,
407
648
  });
649
+ export const WSSubscribeImageRxMessageSchema = WSBaseMessageSchema.extend({
650
+ type: z.literal(WSMessageType.SUBSCRIBE_IMAGE_RX),
651
+ data: ImageRxSubscriptionSchema,
652
+ });
653
+ export const WSImageRadioStatusMessageSchema = WSBaseMessageSchema.extend({
654
+ type: z.literal(WSMessageType.IMAGE_RADIO_STATUS),
655
+ data: ImageRadioStatusSchema,
656
+ });
657
+ export const WSImageRxEventMessageSchema = WSBaseMessageSchema.extend({
658
+ type: z.literal(WSMessageType.IMAGE_RX_EVENT),
659
+ data: ImageRxEventSchema,
660
+ });
661
+ export const WSSstvTxStartMessageSchema = WSBaseMessageSchema.extend({
662
+ type: z.literal(WSMessageType.SSTV_TX_START),
663
+ data: SstvTxStartCommandSchema,
664
+ });
665
+ export const WSSstvTxCancelMessageSchema = WSBaseMessageSchema.extend({
666
+ type: z.literal(WSMessageType.SSTV_TX_CANCEL),
667
+ data: SstvTxCancelCommandSchema,
668
+ });
669
+ export const WSSstvTxStatusMessageSchema = WSBaseMessageSchema.extend({
670
+ type: z.literal(WSMessageType.SSTV_TX_STATUS),
671
+ data: SstvTxStatusSchema,
672
+ });
673
+ export const WSSstvTxCommandResultMessageSchema = WSBaseMessageSchema.extend({
674
+ type: z.literal(WSMessageType.SSTV_TX_COMMAND_RESULT),
675
+ data: SstvTxCommandResultSchema,
676
+ });
677
+ export const WSFaxCalibrationSetMessageSchema = WSBaseMessageSchema.extend({
678
+ type: z.literal(WSMessageType.FAX_CALIBRATION_SET),
679
+ data: FaxCalibrationSetCommandSchema,
680
+ });
681
+ export const WSFaxCalibrationResetMessageSchema = WSBaseMessageSchema.extend({
682
+ type: z.literal(WSMessageType.FAX_CALIBRATION_RESET),
683
+ data: FaxCalibrationResetCommandSchema,
684
+ });
685
+ export const WSFaxCalibrationCommandResultMessageSchema = WSBaseMessageSchema.extend({
686
+ type: z.literal(WSMessageType.FAX_CALIBRATION_COMMAND_RESULT),
687
+ data: FaxCalibrationCommandResultSchema,
688
+ });
408
689
  export const WSSlotStartMessageSchema = WSBaseMessageSchema.extend({
409
690
  type: z.literal(WSMessageType.SLOT_START),
410
691
  data: SlotInfoSchema,
@@ -425,8 +706,13 @@ export const WSSubscribeSpectrumMessageSchema = WSBaseMessageSchema.extend({
425
706
  type: z.literal(WSMessageType.SUBSCRIBE_SPECTRUM),
426
707
  data: z.object({
427
708
  kind: SpectrumKindSchema.nullable(),
709
+ viewport: SpectrumViewportSchema.optional(),
428
710
  }),
429
711
  });
712
+ export const WSSpectrumViewportChangedMessageSchema = WSBaseMessageSchema.extend({
713
+ type: z.literal(WSMessageType.SPECTRUM_VIEWPORT_CHANGED),
714
+ data: SpectrumViewportSchema.nullable(),
715
+ });
430
716
  export const WSSpectrumSubscriptionChangedMessageSchema = WSBaseMessageSchema.extend({
431
717
  type: z.literal(WSMessageType.SPECTRUM_SUBSCRIPTION_CHANGED),
432
718
  data: z.object({
@@ -522,12 +808,16 @@ export const WSGetStatusMessageSchema = WSBaseMessageSchema.extend({
522
808
  export const OperatorStatusSchema = z.object({
523
809
  id: z.string(),
524
810
  isActive: z.boolean(),
525
- isTransmitting: z.boolean(), // 是否正在发射(发射开关状态)
811
+ isTransmitting: z.boolean(), // 是否已授予策略自动发射许可(发射开关状态)
526
812
  isInActivePTT: z.boolean().optional(), // 该操作员的音频是否正在被实际播放
813
+ hasTransmitIntent: z.boolean().optional(), // 当前策略是否有可在合法周期发射的有效内容
814
+ currentTransmissions: z.array(StrategyTransmissionSchema).optional(),
527
815
  currentSlot: z.string().optional(),
528
816
  context: z.object({
529
817
  myCall: z.string(),
530
818
  myGrid: z.string(),
819
+ /** Canonical active target set; `targetCall` remains the primary compatibility field. */
820
+ targetCalls: z.array(z.string()).optional(),
531
821
  targetCall: z.string(),
532
822
  targetGrid: z.string().optional(),
533
823
  frequency: z.number().optional(),
@@ -587,8 +877,8 @@ export const WSSetOperatorContextMessageSchema = WSBaseMessageSchema.extend({
587
877
  targetCallsign: z.string().optional(),
588
878
  targetGrid: z.string().optional(),
589
879
  frequency: z.number().optional(),
590
- reportSent: z.number().optional(),
591
- reportReceived: z.number().optional(),
880
+ reportSent: OperatorContextReportFieldSchema,
881
+ reportReceived: OperatorContextReportFieldSchema,
592
882
  }),
593
883
  }),
594
884
  });
@@ -602,6 +892,25 @@ export const WSSetOperatorRuntimeStateMessageSchema = WSBaseMessageSchema.extend
602
892
  state: OperatorRuntimeSlotSchema,
603
893
  }),
604
894
  });
895
+ /** Sets one strategy-owned stream to a protocol-approved state. */
896
+ export const WSSetOperatorStreamStateMessageSchema = WSBaseMessageSchema.extend({
897
+ type: z.literal(WSMessageType.SET_OPERATOR_STREAM_STATE),
898
+ data: z.object({
899
+ operatorId: z.string(),
900
+ streamId: z.string().min(1),
901
+ stateId: z.string().min(1),
902
+ expectedLifecycleEpoch: z.number().int().nonnegative(),
903
+ }),
904
+ });
905
+ export const WSInvokeOperatorStrategyActionMessageSchema = WSBaseMessageSchema.extend({
906
+ type: z.literal(WSMessageType.INVOKE_OPERATOR_STRATEGY_ACTION),
907
+ data: z.object({
908
+ operatorId: z.string().min(1),
909
+ target: StrategyActionTargetSchema,
910
+ actionId: z.string().min(1),
911
+ payload: z.unknown().optional(),
912
+ }),
913
+ });
605
914
  /**
606
915
  * 设置操作员运行时槽位内容消息
607
916
  */
@@ -662,6 +971,47 @@ export const WSOperatorRequestCallMessageSchema = WSBaseMessageSchema.extend({
662
971
  selectedFrame: WSSelectedFrameSchema.optional(),
663
972
  }),
664
973
  });
974
+ export const WSOperatorQueueEnqueueMessageSchema = WSBaseMessageSchema.extend({
975
+ type: z.literal(WSMessageType.OPERATOR_QUEUE_ENQUEUE),
976
+ data: z.object({
977
+ operatorId: z.string(),
978
+ callsign: z.string(),
979
+ selectedFrame: WSSelectedFrameSchema.optional(),
980
+ startIfIdle: z.boolean().optional(),
981
+ }),
982
+ });
983
+ export const WSOperatorQueueReorderMessageSchema = WSBaseMessageSchema.extend({
984
+ type: z.literal(WSMessageType.OPERATOR_QUEUE_REORDER),
985
+ data: z.object({
986
+ operatorId: z.string(),
987
+ entryId: z.string(),
988
+ beforeEntryId: z.string().nullable(),
989
+ expectedVersion: z.number().int().nonnegative(),
990
+ }),
991
+ });
992
+ export const WSOperatorQueueRetryMessageSchema = WSBaseMessageSchema.extend({
993
+ type: z.literal(WSMessageType.OPERATOR_QUEUE_RETRY),
994
+ data: z.object({
995
+ operatorId: z.string(),
996
+ entryId: z.string(),
997
+ expectedVersion: z.number().int().nonnegative(),
998
+ }),
999
+ });
1000
+ export const WSOperatorQueueRemoveMessageSchema = WSBaseMessageSchema.extend({
1001
+ type: z.literal(WSMessageType.OPERATOR_QUEUE_REMOVE),
1002
+ data: z.object({
1003
+ operatorId: z.string(),
1004
+ entryId: z.string(),
1005
+ expectedVersion: z.number().int().nonnegative(),
1006
+ }),
1007
+ });
1008
+ export const WSOperatorQueueClearMessageSchema = WSBaseMessageSchema.extend({
1009
+ type: z.literal(WSMessageType.OPERATOR_QUEUE_CLEAR),
1010
+ data: z.object({
1011
+ operatorId: z.string(),
1012
+ expectedVersion: z.number().int().nonnegative(),
1013
+ }),
1014
+ });
665
1015
  /**
666
1016
  * 设置客户端启用的操作员列表消息
667
1017
  */
@@ -718,6 +1068,11 @@ export const WSTransmissionLogMessageSchema = WSBaseMessageSchema.extend({
718
1068
  type: z.literal(WSMessageType.TRANSMISSION_LOG),
719
1069
  data: z.object({
720
1070
  operatorId: z.string(),
1071
+ frameId: z.string(),
1072
+ revision: z.number().int().nonnegative(),
1073
+ playbackGeneration: z.number().int().positive(),
1074
+ phase: z.literal('on_air'),
1075
+ physicalConfirmed: z.literal(true),
721
1076
  time: z.string(),
722
1077
  message: z.string(),
723
1078
  frequency: z.number(),
@@ -776,6 +1131,28 @@ export const WSLogbookUpdatedMessageSchema = WSBaseMessageSchema.extend({
776
1131
  statistics: LogBookStatisticsSchema,
777
1132
  }),
778
1133
  });
1134
+ export const WSLogbookHealthChangedMessageSchema = WSBaseMessageSchema.extend({
1135
+ type: z.literal(WSMessageType.LOGBOOK_HEALTH_CHANGED),
1136
+ data: z.object({
1137
+ logBookId: z.string(),
1138
+ health: LogbookHealthSchema,
1139
+ }),
1140
+ });
1141
+ export const WSLogbookWriteFailedMessageSchema = WSBaseMessageSchema.extend({
1142
+ type: z.literal(WSMessageType.LOGBOOK_WRITE_FAILED),
1143
+ data: z.object({
1144
+ logBookId: z.string(),
1145
+ operatorId: z.string().optional(),
1146
+ attemptId: z.string().min(8).max(128).regex(/^[A-Za-z0-9._:-]+$/).optional(),
1147
+ unsavedCount: z.number().int().positive().optional(),
1148
+ error: z.object({
1149
+ code: LogbookOperationErrorCodeSchema,
1150
+ message: z.string(),
1151
+ systemCode: z.string().optional(),
1152
+ occurredAt: z.number(),
1153
+ }),
1154
+ }).strict(),
1155
+ });
779
1156
  /**
780
1157
  * 电台状态变化消息
781
1158
  */
@@ -798,6 +1175,8 @@ export const WSRadioStatusChangedMessageSchema = WSBaseMessageSchema.extend({
798
1175
  meterCapabilities: MeterCapabilitiesSchema.optional(), // 电台数值表能力(connected=true 时应始终携带)
799
1176
  /** @deprecated Tuner capability is now in radioCapabilityList event. Kept for backward compat. */
800
1177
  tunerCapabilities: TunerCapabilitiesSchema.optional(),
1178
+ /** 虚拟频差实际生效状态(多op发射时为 false) */
1179
+ fakeFrequencyEffective: z.boolean().optional(),
801
1180
  }),
802
1181
  });
803
1182
  /**
@@ -966,6 +1345,8 @@ export const WSTextMessageSchema = WSBaseMessageSchema.extend({
966
1345
  text: z.string(),
967
1346
  color: z.enum(['success', 'warning', 'danger', 'default']).optional(),
968
1347
  timeout: z.number().nullable().optional(), // null 表示需要手动关闭,number 表示自动关闭的毫秒数
1348
+ /** 服务端创建消息的时间戳,用于前端识别后台积压消息 */
1349
+ createdAtMs: z.number().optional(),
969
1350
  /** i18n key,前端有此字段时优先翻译显示 */
970
1351
  key: z.string().optional(),
971
1352
  /** i18n 插值参数 */
@@ -1003,6 +1384,13 @@ export const WSWriteRadioCapabilityMessageSchema = WSBaseMessageSchema.extend({
1003
1384
  type: z.literal(WSMessageType.WRITE_RADIO_CAPABILITY),
1004
1385
  data: WriteCapabilityPayloadSchema,
1005
1386
  });
1387
+ export const SetSplitFrequencyPayloadSchema = z.object({
1388
+ txFrequency: z.number().finite().int().min(1_000_000).max(1_000_000_000),
1389
+ });
1390
+ export const WSSetSplitFrequencyMessageSchema = WSBaseMessageSchema.extend({
1391
+ type: z.literal(WSMessageType.SET_SPLIT_FREQUENCY),
1392
+ data: SetSplitFrequencyPayloadSchema,
1393
+ });
1006
1394
  // ===== 认证相关消息 =====
1007
1395
  /**
1008
1396
  * 服务端要求认证(连接建立后发送)
@@ -1029,6 +1417,18 @@ export const WSAuthPublicViewerMessageSchema = WSBaseMessageSchema.extend({
1029
1417
  type: z.literal(WSMessageType.AUTH_PUBLIC_VIEWER),
1030
1418
  data: z.object({}).optional(),
1031
1419
  });
1420
+ export const WSAccessDeniedDataSchema = z.object({
1421
+ reason: z.enum([
1422
+ 'capacity_reached',
1423
+ 'origin_not_allowed',
1424
+ 'authentication_timeout',
1425
+ 'handshake_timeout',
1426
+ 'ip_limit_reached',
1427
+ ]),
1428
+ current: z.number().int().nonnegative().optional(),
1429
+ limit: z.number().int().positive().optional(),
1430
+ retryAfterMs: z.number().int().nonnegative().optional(),
1431
+ });
1032
1432
  /**
1033
1433
  * 认证结果(服务端到客户端)
1034
1434
  */
@@ -1094,12 +1494,23 @@ export const WSMessageSchema = z.discriminatedUnion('type', [
1094
1494
  WSPongMessageSchema,
1095
1495
  // 服务端到客户端
1096
1496
  WSModeChangedMessageSchema,
1497
+ WSSubscribeImageRxMessageSchema,
1498
+ WSImageRadioStatusMessageSchema,
1499
+ WSImageRxEventMessageSchema,
1500
+ WSSstvTxStartMessageSchema,
1501
+ WSSstvTxCancelMessageSchema,
1502
+ WSSstvTxStatusMessageSchema,
1503
+ WSSstvTxCommandResultMessageSchema,
1504
+ WSFaxCalibrationSetMessageSchema,
1505
+ WSFaxCalibrationResetMessageSchema,
1506
+ WSFaxCalibrationCommandResultMessageSchema,
1097
1507
  WSSlotStartMessageSchema,
1098
1508
  WSSubWindowMessageSchema,
1099
1509
  WSSlotPackUpdatedMessageSchema,
1100
1510
  WSSpectrumCapabilitiesMessageSchema,
1101
1511
  WSSubscribeSpectrumMessageSchema,
1102
1512
  WSSpectrumSubscriptionChangedMessageSchema,
1513
+ WSSpectrumViewportChangedMessageSchema,
1103
1514
  WSSpectrumFrameMessageSchema,
1104
1515
  WSSpectrumSessionStateChangedMessageSchema,
1105
1516
  WSInvokeSpectrumControlMessageSchema,
@@ -1122,11 +1533,18 @@ export const WSMessageSchema = z.discriminatedUnion('type', [
1122
1533
  WSOperatorStatusUpdateMessageSchema,
1123
1534
  WSSetOperatorContextMessageSchema,
1124
1535
  WSSetOperatorRuntimeStateMessageSchema,
1536
+ WSSetOperatorStreamStateMessageSchema,
1537
+ WSInvokeOperatorStrategyActionMessageSchema,
1125
1538
  WSSetOperatorRuntimeSlotContentMessageSchema,
1126
1539
  WSSetOperatorTransmitCyclesMessageSchema,
1127
1540
  WSStartOperatorMessageSchema,
1128
1541
  WSStopOperatorMessageSchema,
1129
1542
  WSOperatorRequestCallMessageSchema,
1543
+ WSOperatorQueueEnqueueMessageSchema,
1544
+ WSOperatorQueueReorderMessageSchema,
1545
+ WSOperatorQueueRetryMessageSchema,
1546
+ WSOperatorQueueRemoveMessageSchema,
1547
+ WSOperatorQueueClearMessageSchema,
1130
1548
  // 音量控制消息
1131
1549
  WSSetVolumeGainMessageSchema,
1132
1550
  WSSetVolumeGainDbMessageSchema,
@@ -1134,6 +1552,8 @@ export const WSMessageSchema = z.discriminatedUnion('type', [
1134
1552
  WSQSORecordAddedMessageSchema,
1135
1553
  WSQSORecordUpdatedMessageSchema,
1136
1554
  WSLogbookUpdatedMessageSchema,
1555
+ WSLogbookHealthChangedMessageSchema,
1556
+ WSLogbookWriteFailedMessageSchema,
1137
1557
  // 客户端启用操作员列表消息
1138
1558
  WSSetClientEnabledOperatorsMessageSchema,
1139
1559
  WSSetClientSelectedOperatorMessageSchema,
@@ -1153,6 +1573,7 @@ export const WSMessageSchema = z.discriminatedUnion('type', [
1153
1573
  WSAudioRetryNowMessageSchema,
1154
1574
  // 频率管理消息
1155
1575
  WSFrequencyChangedMessageSchema,
1576
+ WSSetSplitFrequencyMessageSchema,
1156
1577
  // PTT状态管理消息
1157
1578
  WSPTTStatusChangedMessageSchema,
1158
1579
  WSForceStopTransmissionMessageSchema,
@@ -1186,9 +1607,27 @@ export const WSMessageSchema = z.discriminatedUnion('type', [
1186
1607
  ]);
1187
1608
  export const TransmitRequestSchema = z.object({
1188
1609
  operatorId: z.string(),
1610
+ streamId: z.string().min(1).optional(),
1189
1611
  transmission: z.string(),
1612
+ audioFrequencyHz: z.number().min(0).max(5000).optional(),
1190
1613
  /** 是否覆盖同一操作员在同一时隙的现有 TX 帧(自动重决策时为 true) */
1191
1614
  replaceExisting: z.boolean().optional(),
1615
+ source: z.enum(['standard-qso', 'plugin', 'late-decode', 'operator-edit', 'manual']).optional(),
1616
+ reason: z.string().optional(),
1617
+ /** Host command epoch used to tombstone stale encode/mix callbacks. */
1618
+ decisionEpoch: z.number().int().nonnegative().optional(),
1619
+ });
1620
+ export const TransmitBatchRequestSchema = z.object({
1621
+ operatorId: z.string(),
1622
+ transmissions: z.array(z.object({
1623
+ streamId: z.string().min(1),
1624
+ transmission: z.string(),
1625
+ audioFrequencyHz: z.number().min(0).max(5000),
1626
+ })).max(5),
1627
+ replaceExisting: z.boolean().optional(),
1628
+ source: z.enum(['standard-qso', 'plugin', 'late-decode', 'operator-edit', 'manual']).optional(),
1629
+ reason: z.string().optional(),
1630
+ decisionEpoch: z.number().int().nonnegative().optional(),
1192
1631
  });
1193
1632
  // ===== 前端应用事件接口 =====
1194
1633
  /**
@@ -1196,7 +1635,12 @@ export const TransmitRequestSchema = z.object({
1196
1635
  */
1197
1636
  export const TransmissionCompleteInfoSchema = z.object({
1198
1637
  operatorId: z.string(),
1638
+ streamId: z.string().optional(),
1639
+ trackId: z.string().optional(),
1199
1640
  success: z.boolean(),
1641
+ frameId: z.string().optional(),
1642
+ physicalConfirmed: z.boolean().optional(),
1643
+ terminalReason: z.string().optional(),
1200
1644
  duration: z.number().optional(),
1201
1645
  error: z.string().optional(),
1202
1646
  mixedWith: z.array(z.string()).optional(), // 与其他操作员混音的ID列表