@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
@@ -20,8 +20,16 @@ import type {
20
20
  PluginSystemSnapshot,
21
21
  } from './plugin.schema.js';
22
22
  import { ModeDescriptorSchema } from './mode.schema.js';
23
- import { QSORecordSchema, TargetSelectionPriorityModeSchema } from './qso.schema.js';
24
- import { LogBookStatisticsSchema } from './logbook.schema.js';
23
+ import {
24
+ QSORecordSchema,
25
+ QSOPersistencePolicySchema,
26
+ TargetSelectionPriorityModeSchema,
27
+ } from './qso.schema.js';
28
+ import {
29
+ LogBookStatisticsSchema,
30
+ LogbookHealthSchema,
31
+ LogbookOperationErrorCodeSchema,
32
+ } from './logbook.schema.js';
25
33
  import { RadioInfoSchema, HamlibConfigSchema, TunerStatusSchema, TunerCapabilitiesSchema, RadioConnectionStatusSchema, ReconnectProgressSchema, CoreRadioCapabilitiesSchema, CoreCapabilityDiagnosticsSchema } from './radio.schema.js';
26
34
  import { RadioProfileSchema, ProfileChangedEventSchema } from './radio-profile.schema.js';
27
35
  import { UserRole } from './auth.schema.js';
@@ -32,9 +40,27 @@ import { CWDecoderEventSchema, CWDecoderStatusSchema, type CWDecoderEvent, type
32
40
  import { CapabilityListSchema, CapabilityStateSchema, WriteCapabilityPayloadSchema } from './radio-capability.schema.js';
33
41
  import { RadioPowerStateEventSchema } from './radio-power.schema.js';
34
42
  import { AudioSidecarStatusPayloadSchema } from './audio-sidecar.schema.js';
35
- import { SpectrumCapabilitiesSchema, SpectrumFrameSchema, SpectrumKindSchema, SpectrumSessionControlActionSchema, SpectrumSessionControlIdSchema, SpectrumSessionStateSchema } from './spectrum.schema.js';
43
+ import { SpectrumCapabilitiesSchema, SpectrumFrameSchema, SpectrumKindSchema, SpectrumSessionControlActionSchema, SpectrumSessionControlIdSchema, SpectrumSessionStateSchema, SpectrumViewportSchema } from './spectrum.schema.js';
36
44
  import type { RealtimeSettingsResponseData } from './realtime.schema.js';
45
+ import type { AndroidOperatorAudioStatus } from './android-operator-audio.schema.js';
37
46
  import { ClockStatusSummarySchema } from './system.schema.js';
47
+ import {
48
+ ImageRadioStatusSchema,
49
+ ImageRxEventSchema,
50
+ ImageRxSubscriptionSchema,
51
+ FaxCalibrationCommandResultSchema,
52
+ FaxCalibrationResetCommandSchema,
53
+ FaxCalibrationSetCommandSchema,
54
+ SstvTxCancelCommandSchema,
55
+ SstvTxCommandResultSchema,
56
+ SstvTxStartCommandSchema,
57
+ SstvTxStatusSchema,
58
+ type ImageRadioStatus,
59
+ type ImageRxEvent,
60
+ type FaxCalibrationCommandResult,
61
+ type SstvTxCommandResult,
62
+ type SstvTxStatus,
63
+ } from './image-radio.schema.js';
38
64
 
39
65
  // WebSocket消息类型枚举
40
66
  export enum WSMessageType {
@@ -50,6 +76,16 @@ export enum WSMessageType {
50
76
  STOP_ENGINE = 'stopEngine',
51
77
  GET_STATUS = 'getStatus',
52
78
  SET_MODE = 'setMode',
79
+ SUBSCRIBE_IMAGE_RX = 'subscribeImageRx',
80
+ IMAGE_RADIO_STATUS = 'imageRadioStatus',
81
+ IMAGE_RX_EVENT = 'imageRxEvent',
82
+ SSTV_TX_START = 'sstvTxStart',
83
+ SSTV_TX_CANCEL = 'sstvTxCancel',
84
+ SSTV_TX_STATUS = 'sstvTxStatus',
85
+ SSTV_TX_COMMAND_RESULT = 'sstvTxCommandResult',
86
+ FAX_CALIBRATION_SET = 'faxCalibrationSet',
87
+ FAX_CALIBRATION_RESET = 'faxCalibrationReset',
88
+ FAX_CALIBRATION_COMMAND_RESULT = 'faxCalibrationCommandResult',
53
89
 
54
90
  // ===== 引擎事件 =====
55
91
  MODE_CHANGED = 'modeChanged',
@@ -62,6 +98,7 @@ export enum WSMessageType {
62
98
  SPECTRUM_FRAME = 'spectrumFrame',
63
99
  SPECTRUM_SESSION_STATE_CHANGED = 'spectrumSessionStateChanged',
64
100
  INVOKE_SPECTRUM_CONTROL = 'invokeSpectrumControl',
101
+ SPECTRUM_VIEWPORT_CHANGED = 'spectrumViewportChanged',
65
102
  DECODE_ERROR = 'decodeError',
66
103
  SYSTEM_STATUS = 'systemStatus',
67
104
  BOOTSTRAP_STATUS_CHANGED = 'bootstrapStatusChanged',
@@ -75,11 +112,18 @@ export enum WSMessageType {
75
112
  OPERATOR_STATUS_UPDATE = 'operatorStatusUpdate',
76
113
  SET_OPERATOR_CONTEXT = 'setOperatorContext',
77
114
  SET_OPERATOR_RUNTIME_STATE = 'setOperatorRuntimeState',
115
+ SET_OPERATOR_STREAM_STATE = 'setOperatorStreamState',
116
+ INVOKE_OPERATOR_STRATEGY_ACTION = 'invokeOperatorStrategyAction',
78
117
  SET_OPERATOR_RUNTIME_SLOT_CONTENT = 'setOperatorRuntimeSlotContent',
79
118
  SET_OPERATOR_TRANSMIT_CYCLES = 'setOperatorTransmitCycles',
80
119
  START_OPERATOR = 'startOperator',
81
120
  STOP_OPERATOR = 'stopOperator',
82
121
  OPERATOR_REQUEST_CALL = 'operatorRequestCall',
122
+ OPERATOR_QUEUE_ENQUEUE = 'operatorQueueEnqueue',
123
+ OPERATOR_QUEUE_REORDER = 'operatorQueueReorder',
124
+ OPERATOR_QUEUE_RETRY = 'operatorQueueRetry',
125
+ OPERATOR_QUEUE_REMOVE = 'operatorQueueRemove',
126
+ OPERATOR_QUEUE_CLEAR = 'operatorQueueClear',
83
127
 
84
128
  // ===== 客户端操作员过滤 =====
85
129
  SET_CLIENT_ENABLED_OPERATORS = 'setClientEnabledOperators',
@@ -102,6 +146,8 @@ export enum WSMessageType {
102
146
  QSO_RECORD_ADDED = 'qsoRecordAdded',
103
147
  QSO_RECORD_UPDATED = 'qsoRecordUpdated',
104
148
  LOGBOOK_UPDATED = 'logbookUpdated',
149
+ LOGBOOK_HEALTH_CHANGED = 'logbookHealthChanged',
150
+ LOGBOOK_WRITE_FAILED = 'logbookWriteFailed',
105
151
  // 仅通知的日志本变更事件(专用于日志本WS)
106
152
  LOGBOOK_CHANGE_NOTICE = 'logbookChangeNotice',
107
153
 
@@ -143,6 +189,8 @@ export enum WSMessageType {
143
189
  WRITE_RADIO_CAPABILITY = 'writeRadioCapability',
144
190
  /** 客户端请求刷新所有能力值(client → server) */
145
191
  REFRESH_RADIO_CAPABILITIES = 'refreshRadioCapabilities',
192
+ /** 客户端设置 Split TX 频率(client → server) */
193
+ SET_SPLIT_FREQUENCY = 'setSplitFrequency',
146
194
 
147
195
  // ===== 电台重连控制 =====
148
196
  RADIO_STOP_RECONNECT = 'radioStopReconnect',
@@ -168,6 +216,7 @@ export enum WSMessageType {
168
216
  AUTH_PUBLIC_VIEWER = 'authPublicViewer',
169
217
  AUTH_RESULT = 'authResult',
170
218
  AUTH_EXPIRED = 'authExpired',
219
+ ACCESS_DENIED = 'accessDenied',
171
220
 
172
221
  // ===== 语音模式 =====
173
222
  VOICE_PTT_REQUEST = 'voicePttRequest',
@@ -178,6 +227,7 @@ export enum WSMessageType {
178
227
  VOICE_KEYER_PLAY = 'voiceKeyerPlay',
179
228
  VOICE_KEYER_STOP = 'voiceKeyerStop',
180
229
  VOICE_KEYER_STATUS_CHANGED = 'voiceKeyerStatusChanged',
230
+ ANDROID_OPERATOR_AUDIO_STATUS_CHANGED = 'androidOperatorAudioStatusChanged',
181
231
 
182
232
  // ===== CW 模式 =====
183
233
  /** CW 键控器状态变化(server → client) */
@@ -238,7 +288,7 @@ export const SystemStatusSchema = z.object({
238
288
  connectionHealthy: z.boolean(),
239
289
  }).optional(),
240
290
  /** 引擎模式:digital(FT8/FT4)、voice(语音通联)或 cw(莫尔斯码) */
241
- engineMode: z.enum(['digital', 'voice', 'cw']).default('digital'),
291
+ engineMode: z.enum(['digital', 'voice', 'cw', 'image']).default('digital'),
242
292
  /** 当前电台调制模式(语音模式下使用,如 USB/LSB/FM/AM) */
243
293
  currentRadioMode: z.string().optional(),
244
294
  /** 引擎状态机当前状态 */
@@ -325,7 +375,15 @@ export const DecodeErrorInfoSchema = z.object({
325
375
  }),
326
376
  });
327
377
 
328
- // 频率状态数据结构
378
+ /**
379
+ * Current dial-frequency projection broadcast to plugins and clients.
380
+ *
381
+ * `frequency` is the logical RF dial target in hertz; `mode` is the TX-5DR
382
+ * engine mode; `band` and `description` are display labels; `radioMode` is the
383
+ * underlying modulation when known. `observedFrequency` is the latest physical
384
+ * readback. `source` distinguishes application changes from radio observations;
385
+ * `revision` and `connectionGeneration` reject stale events.
386
+ */
329
387
  export const FrequencyStateSchema = z.object({
330
388
  frequency: z.number(),
331
389
  mode: z.string(),
@@ -334,6 +392,20 @@ export const FrequencyStateSchema = z.object({
334
392
  radioMode: z.string().optional(),
335
393
  radioConnected: z.boolean(),
336
394
  source: z.enum(['program', 'radio']).optional(),
395
+ /** Monotonic operating-state revision for stale-event suppression. */
396
+ revision: z.number().int().nonnegative().optional(),
397
+ /** Physical CAT session identity associated with this snapshot. */
398
+ connectionGeneration: z.number().int().nonnegative().optional(),
399
+ /** Physical confirmation status for the requested operating state. */
400
+ confirmation: z.enum(['confirmed', 'pending', 'mismatch', 'offline']).optional(),
401
+ /** Last frequency read back from the physical radio, when available. */
402
+ observedFrequency: z.number().optional(),
403
+ /** Requested logical frequency when it differs from the observed value. */
404
+ requestedFrequency: z.number().optional(),
405
+ /** Correlates a snapshot with one programmatic operating-state mutation. */
406
+ operationId: z.string().optional(),
407
+ /** Physical radio-mode confirmation status. */
408
+ modeConfirmation: z.enum(['confirmed', 'unconfirmed', 'unknown']).optional(),
337
409
  });
338
410
 
339
411
  export const SpectrumControlInvocationSchema = z.object({
@@ -346,6 +418,9 @@ export type SpectrumControlInvocation = z.infer<typeof SpectrumControlInvocation
346
418
  export const PTTStatusSchema = z.object({
347
419
  isTransmitting: z.boolean(),
348
420
  operatorIds: z.array(z.string()),
421
+ phase: z.enum(['idle', 'starting', 'on_air', 'draining', 'stopping', 'unknown']).optional(),
422
+ frameId: z.string().optional(),
423
+ source: z.enum(['digital', 'voice', 'voice-keyer', 'cw', 'sstv', 'tune-tone', 'manual', 'test']).optional(),
349
424
  });
350
425
 
351
426
  export const TuneToneStartPayloadSchema = z.object({
@@ -383,6 +458,200 @@ export const StrategyRuntimeContextSchema = z.object({
383
458
  });
384
459
  export type StrategyRuntimeContext = z.infer<typeof StrategyRuntimeContextSchema>;
385
460
 
461
+ export const StrategyStateOptionSchema = z.object({
462
+ id: z.string().min(1),
463
+ label: z.string().min(1).optional(),
464
+ transmitText: z.string().optional(),
465
+ });
466
+ export type StrategyStateOption = z.infer<typeof StrategyStateOptionSchema>;
467
+
468
+ export const StrategyActionInputSchema = z.discriminatedUnion('kind', [
469
+ z.object({
470
+ kind: z.literal('text'),
471
+ label: z.string().optional(),
472
+ value: z.string().optional(),
473
+ placeholder: z.string().optional(),
474
+ maxLength: z.number().int().positive().optional(),
475
+ }),
476
+ z.object({
477
+ kind: z.enum(['number', 'audio-frequency']),
478
+ label: z.string().optional(),
479
+ value: z.number().optional(),
480
+ min: z.number().optional(),
481
+ max: z.number().optional(),
482
+ step: z.number().positive().optional(),
483
+ unit: z.string().optional(),
484
+ spectrumPick: z.boolean().optional(),
485
+ }),
486
+ ]);
487
+
488
+ export const StrategyActionDescriptorSchema = z.object({
489
+ id: z.string().min(1),
490
+ label: z.string().min(1),
491
+ description: z.string().optional(),
492
+ icon: z.string().optional(),
493
+ tone: z.enum(['default', 'primary', 'success', 'warning', 'danger']).optional(),
494
+ presentation: z.enum(['primary', 'secondary', 'menu', 'segmented']).optional(),
495
+ groupId: z.string().optional(),
496
+ selected: z.boolean().optional(),
497
+ disabledReason: z.string().optional(),
498
+ previewText: z.string().optional(),
499
+ confirmation: z.object({
500
+ title: z.string().min(1),
501
+ description: z.string().optional(),
502
+ confirmLabel: z.string().optional(),
503
+ cancelLabel: z.string().optional(),
504
+ }).optional(),
505
+ input: StrategyActionInputSchema.optional(),
506
+ navigation: z.object({
507
+ kind: z.literal('plugin-page'),
508
+ pageId: z.string().min(1),
509
+ }).optional(),
510
+ });
511
+ export type StrategyActionDescriptor = z.infer<typeof StrategyActionDescriptorSchema>;
512
+
513
+ export const StrategyAttentionSchema = z.object({
514
+ id: z.string().min(1),
515
+ tone: z.enum(['info', 'warning', 'danger', 'success']),
516
+ title: z.string().min(1),
517
+ description: z.string().optional(),
518
+ params: z.record(z.string(), z.union([z.string(), z.number()])).optional(),
519
+ notify: z.boolean().optional(),
520
+ expiresAt: z.number().optional(),
521
+ actionIds: z.array(z.string()).optional(),
522
+ });
523
+ export type StrategyAttention = z.infer<typeof StrategyAttentionSchema>;
524
+
525
+ export const StrategyCompletionProjectionSchema = z.object({
526
+ state: z.enum(['not-ready', 'ready', 'committing', 'committed', 'failed']),
527
+ label: z.string().optional(),
528
+ recordId: z.string().optional(),
529
+ });
530
+ export type StrategyCompletionProjection = z.infer<typeof StrategyCompletionProjectionSchema>;
531
+
532
+ export const StrategyStreamSnapshotSchema = z.object({
533
+ streamId: z.string().min(1),
534
+ currentState: z.string(),
535
+ targetCallsign: z.string().optional(),
536
+ targetGrid: z.string().optional(),
537
+ audioFrequencyHz: z.number().min(0).max(5000),
538
+ qsoLifecycleEpoch: z.number().int().nonnegative(),
539
+ stateOptions: z.array(StrategyStateOptionSchema).optional(),
540
+ actions: z.array(StrategyActionDescriptorSchema).optional(),
541
+ attentions: z.array(StrategyAttentionSchema).optional(),
542
+ completion: StrategyCompletionProjectionSchema.optional(),
543
+ lastReceivedText: z.string().optional(),
544
+ nextTransmitText: z.string().optional(),
545
+ });
546
+ export type StrategyStreamSnapshot = z.infer<typeof StrategyStreamSnapshotSchema>;
547
+
548
+ export const StrategyTransmissionSchema = z.object({
549
+ streamId: z.string().min(1),
550
+ text: z.string().min(1),
551
+ audioFrequencyHz: z.number().min(0).max(5000),
552
+ });
553
+ export type StrategyTransmission = z.infer<typeof StrategyTransmissionSchema>;
554
+
555
+ export const AssistedQueueDisplayStateSchema = z.enum([
556
+ 'TX1', 'TX2', 'TX3', 'TX4', 'TX5', 'engaged', 'closing', 'paused', 'no-response', 'later', 'review',
557
+ 'candidate', 'authorized', 'dupe',
558
+ ]);
559
+ export const AssistedQueuePauseReasonSchema = z.enum(['target-busy', 'stale']);
560
+ export const AssistedQueueToneSchema = z.enum(['neutral', 'active', 'success', 'warning', 'danger']);
561
+ export const AssistedQueueIconSchema = z.enum([
562
+ 'circle', 'radio', 'check-circle', 'loader-circle', 'clock', 'pause', 'triangle-alert',
563
+ ]);
564
+ export const AssistedQueueRowSchema = z.object({
565
+ entryId: z.string(),
566
+ callsign: z.string(),
567
+ order: z.number().int().nonnegative(),
568
+ draggable: z.boolean(),
569
+ displayState: AssistedQueueDisplayStateSchema,
570
+ tone: AssistedQueueToneSchema,
571
+ icon: AssistedQueueIconSchema,
572
+ pauseReason: AssistedQueuePauseReasonSchema.optional(),
573
+ noResponseCycles: z.number().int().nonnegative().optional(),
574
+ targetGrid: z.string().optional(),
575
+ lastSnr: z.number().optional(),
576
+ lastHeardCyclesAgo: z.number().int().nonnegative().optional(),
577
+ lastHeardCycle: z.union([z.literal(0), z.literal(1)]).optional(),
578
+ streamId: z.string().optional(),
579
+ audioFrequencyHz: z.number().optional(),
580
+ authorizationId: z.string().optional(),
581
+ actions: z.array(StrategyActionDescriptorSchema).optional(),
582
+ });
583
+ export const AssistedQueueSnapshotSchema = z.object({
584
+ version: z.number().int().nonnegative(),
585
+ activeEntryId: z.string().optional(),
586
+ activeEntryIds: z.array(z.string()).optional(),
587
+ maxActiveStreams: z.number().int().min(1).max(5).optional(),
588
+ requestedMaxActiveStreams: z.number().int().min(1).max(5).optional(),
589
+ rows: z.array(AssistedQueueRowSchema),
590
+ });
591
+ export type AssistedQueueDisplayState = z.infer<typeof AssistedQueueDisplayStateSchema>;
592
+ export type AssistedQueuePauseReason = z.infer<typeof AssistedQueuePauseReasonSchema>;
593
+ export type AssistedQueueTone = z.infer<typeof AssistedQueueToneSchema>;
594
+ export type AssistedQueueIcon = z.infer<typeof AssistedQueueIconSchema>;
595
+ export type AssistedQueueRow = z.infer<typeof AssistedQueueRowSchema>;
596
+ export type AssistedQueueSnapshot = z.infer<typeof AssistedQueueSnapshotSchema>;
597
+
598
+ /** Null clears an unsettable runtime report field over JSON/WebSocket. */
599
+ export const OperatorContextReportFieldSchema = z.number().nullish();
600
+
601
+ export const StrategyMessagePresentationToneSchema = z.enum([
602
+ 'neutral', 'primary', 'secondary', 'success', 'warning', 'danger',
603
+ ]);
604
+ export const StrategyMessagePresentationBadgeSchema = z.object({
605
+ label: z.string().min(1),
606
+ tone: StrategyMessagePresentationToneSchema,
607
+ });
608
+ export const StrategyMessagePresentationTokenMatchSchema = z.object({
609
+ firstTokenIn: z.array(z.string().min(1)).optional(),
610
+ anyTokenIn: z.array(z.string().min(1)).optional(),
611
+ });
612
+ export const StrategyMessagePresentationClassSchema = z.object({
613
+ badge: StrategyMessagePresentationBadgeSchema.optional(),
614
+ badges: z.array(StrategyMessagePresentationBadgeSchema).optional(),
615
+ row: z.object({
616
+ tone: StrategyMessagePresentationToneSchema,
617
+ background: z.enum(['none', 'soft']).optional(),
618
+ accent: z.boolean().optional(),
619
+ }).optional(),
620
+ emphasisWhen: z.array(StrategyMessagePresentationTokenMatchSchema).min(1).optional(),
621
+ textDecoration: z.literal('line-through').optional(),
622
+ opacity: z.enum(['normal', 'muted']).optional(),
623
+ });
624
+ export const StrategyMessagePresentationProjectionSchema = z.object({
625
+ revision: z.number().int().nonnegative(),
626
+ mode: z.enum(['replace-logbook', 'augment']),
627
+ subject: z.literal('sender-callsign'),
628
+ partitionBy: z.enum(['band', 'mode', 'none']),
629
+ eligiblePartitions: z.array(z.string()).optional(),
630
+ defaultClass: z.string().optional(),
631
+ classes: z.record(z.string(), StrategyMessagePresentationClassSchema),
632
+ assignments: z.array(z.object({
633
+ subject: z.string().min(1),
634
+ partition: z.string().optional(),
635
+ classId: z.string().min(1),
636
+ })),
637
+ noveltyRules: z.array(z.object({
638
+ fact: z.literal('grid-field-2'),
639
+ knownValuesByPartition: z.record(z.string(), z.array(z.string().min(1))),
640
+ classId: z.string().min(1),
641
+ })).optional(),
642
+ tagRules: z.array(z.object({
643
+ id: z.string().min(1),
644
+ match: StrategyMessagePresentationTokenMatchSchema,
645
+ badge: StrategyMessagePresentationBadgeSchema,
646
+ })).optional(),
647
+ });
648
+
649
+ export type StrategyMessagePresentationTone = z.infer<typeof StrategyMessagePresentationToneSchema>;
650
+ export type StrategyMessagePresentationBadge = z.infer<typeof StrategyMessagePresentationBadgeSchema>;
651
+ export type StrategyMessagePresentationTokenMatch = z.infer<typeof StrategyMessagePresentationTokenMatchSchema>;
652
+ export type StrategyMessagePresentationClass = z.infer<typeof StrategyMessagePresentationClassSchema>;
653
+ export type StrategyMessagePresentationProjection = z.infer<typeof StrategyMessagePresentationProjectionSchema>;
654
+
386
655
  export const StrategyRuntimeSnapshotSchema = z.object({
387
656
  currentState: z.string(),
388
657
  slots: z.object({
@@ -395,7 +664,33 @@ export const StrategyRuntimeSnapshotSchema = z.object({
395
664
  }).optional(),
396
665
  context: StrategyRuntimeContextSchema.optional(),
397
666
  availableSlots: z.array(z.string()).optional(),
667
+ qsoLifecycleEpoch: z.number().int().nonnegative().optional(),
668
+ streams: z.array(StrategyStreamSnapshotSchema).optional(),
669
+ queue: AssistedQueueSnapshotSchema.optional(),
670
+ actions: z.array(StrategyActionDescriptorSchema).optional(),
671
+ attentions: z.array(StrategyAttentionSchema).optional(),
672
+ messagePresentation: StrategyMessagePresentationProjectionSchema.optional(),
673
+ transmitGate: z.object({
674
+ allowed: z.literal(false),
675
+ reason: z.string().min(1),
676
+ actionId: z.string().optional(),
677
+ }).optional(),
398
678
  });
679
+
680
+ export const StrategyActionTargetSchema = z.discriminatedUnion('kind', [
681
+ z.object({ kind: z.literal('runtime') }),
682
+ z.object({
683
+ kind: z.literal('stream'),
684
+ streamId: z.string().min(1),
685
+ lifecycleEpoch: z.number().int().nonnegative(),
686
+ }),
687
+ z.object({
688
+ kind: z.literal('queue-entry'),
689
+ entryId: z.string().min(1),
690
+ queueVersion: z.number().int().nonnegative(),
691
+ }),
692
+ ]);
693
+ export type StrategyActionTarget = z.infer<typeof StrategyActionTargetSchema>;
399
694
  export type StrategyRuntimeSnapshot = z.infer<typeof StrategyRuntimeSnapshotSchema>;
400
695
 
401
696
  export const LevelMeterDisplayStyleSchema = z.enum([
@@ -453,11 +748,12 @@ export const MeterDataSchema = z.object({
453
748
  raw: z.number(),
454
749
  percent: z.number(),
455
750
  alert: z.boolean(),
751
+ unit: z.enum(['percent', 'dbfs']).optional(),
456
752
  }).nullable(),
457
753
  level: LevelMeterReadingSchema.nullable(),
458
754
  power: z.object({
459
755
  raw: z.number(),
460
- percent: z.number(),
756
+ percent: z.number().nullable(),
461
757
  watts: z.number().nullable(), // 绝对瓦数(仅当电台支持 RFPOWER_METER_WATTS 时非 null)
462
758
  maxWatts: z.number().nullable(), // 当前频率+模式对应的量程瓦数
463
759
  }).nullable(),
@@ -504,6 +800,56 @@ export const WSModeChangedMessageSchema = WSBaseMessageSchema.extend({
504
800
  data: ModeDescriptorSchema,
505
801
  });
506
802
 
803
+ export const WSSubscribeImageRxMessageSchema = WSBaseMessageSchema.extend({
804
+ type: z.literal(WSMessageType.SUBSCRIBE_IMAGE_RX),
805
+ data: ImageRxSubscriptionSchema,
806
+ });
807
+
808
+ export const WSImageRadioStatusMessageSchema = WSBaseMessageSchema.extend({
809
+ type: z.literal(WSMessageType.IMAGE_RADIO_STATUS),
810
+ data: ImageRadioStatusSchema,
811
+ });
812
+
813
+ export const WSImageRxEventMessageSchema = WSBaseMessageSchema.extend({
814
+ type: z.literal(WSMessageType.IMAGE_RX_EVENT),
815
+ data: ImageRxEventSchema,
816
+ });
817
+
818
+ export const WSSstvTxStartMessageSchema = WSBaseMessageSchema.extend({
819
+ type: z.literal(WSMessageType.SSTV_TX_START),
820
+ data: SstvTxStartCommandSchema,
821
+ });
822
+
823
+ export const WSSstvTxCancelMessageSchema = WSBaseMessageSchema.extend({
824
+ type: z.literal(WSMessageType.SSTV_TX_CANCEL),
825
+ data: SstvTxCancelCommandSchema,
826
+ });
827
+
828
+ export const WSSstvTxStatusMessageSchema = WSBaseMessageSchema.extend({
829
+ type: z.literal(WSMessageType.SSTV_TX_STATUS),
830
+ data: SstvTxStatusSchema,
831
+ });
832
+
833
+ export const WSSstvTxCommandResultMessageSchema = WSBaseMessageSchema.extend({
834
+ type: z.literal(WSMessageType.SSTV_TX_COMMAND_RESULT),
835
+ data: SstvTxCommandResultSchema,
836
+ });
837
+
838
+ export const WSFaxCalibrationSetMessageSchema = WSBaseMessageSchema.extend({
839
+ type: z.literal(WSMessageType.FAX_CALIBRATION_SET),
840
+ data: FaxCalibrationSetCommandSchema,
841
+ });
842
+
843
+ export const WSFaxCalibrationResetMessageSchema = WSBaseMessageSchema.extend({
844
+ type: z.literal(WSMessageType.FAX_CALIBRATION_RESET),
845
+ data: FaxCalibrationResetCommandSchema,
846
+ });
847
+
848
+ export const WSFaxCalibrationCommandResultMessageSchema = WSBaseMessageSchema.extend({
849
+ type: z.literal(WSMessageType.FAX_CALIBRATION_COMMAND_RESULT),
850
+ data: FaxCalibrationCommandResultSchema,
851
+ });
852
+
507
853
  export const WSSlotStartMessageSchema = WSBaseMessageSchema.extend({
508
854
  type: z.literal(WSMessageType.SLOT_START),
509
855
  data: SlotInfoSchema,
@@ -528,9 +874,15 @@ export const WSSubscribeSpectrumMessageSchema = WSBaseMessageSchema.extend({
528
874
  type: z.literal(WSMessageType.SUBSCRIBE_SPECTRUM),
529
875
  data: z.object({
530
876
  kind: SpectrumKindSchema.nullable(),
877
+ viewport: SpectrumViewportSchema.optional(),
531
878
  }),
532
879
  });
533
880
 
881
+ export const WSSpectrumViewportChangedMessageSchema = WSBaseMessageSchema.extend({
882
+ type: z.literal(WSMessageType.SPECTRUM_VIEWPORT_CHANGED),
883
+ data: SpectrumViewportSchema.nullable(),
884
+ });
885
+
534
886
  export const WSSpectrumSubscriptionChangedMessageSchema = WSBaseMessageSchema.extend({
535
887
  type: z.literal(WSMessageType.SPECTRUM_SUBSCRIPTION_CHANGED),
536
888
  data: z.object({
@@ -642,12 +994,16 @@ export const WSGetStatusMessageSchema = WSBaseMessageSchema.extend({
642
994
  export const OperatorStatusSchema = z.object({
643
995
  id: z.string(),
644
996
  isActive: z.boolean(),
645
- isTransmitting: z.boolean(), // 是否正在发射(发射开关状态)
997
+ isTransmitting: z.boolean(), // 是否已授予策略自动发射许可(发射开关状态)
646
998
  isInActivePTT: z.boolean().optional(), // 该操作员的音频是否正在被实际播放
999
+ hasTransmitIntent: z.boolean().optional(), // 当前策略是否有可在合法周期发射的有效内容
1000
+ currentTransmissions: z.array(StrategyTransmissionSchema).optional(),
647
1001
  currentSlot: z.string().optional(),
648
1002
  context: z.object({
649
1003
  myCall: z.string(),
650
1004
  myGrid: z.string(),
1005
+ /** Canonical active target set; `targetCall` remains the primary compatibility field. */
1006
+ targetCalls: z.array(z.string()).optional(),
651
1007
  targetCall: z.string(),
652
1008
  targetGrid: z.string().optional(),
653
1009
  frequency: z.number().optional(),
@@ -713,8 +1069,8 @@ export const WSSetOperatorContextMessageSchema = WSBaseMessageSchema.extend({
713
1069
  targetCallsign: z.string().optional(),
714
1070
  targetGrid: z.string().optional(),
715
1071
  frequency: z.number().optional(),
716
- reportSent: z.number().optional(),
717
- reportReceived: z.number().optional(),
1072
+ reportSent: OperatorContextReportFieldSchema,
1073
+ reportReceived: OperatorContextReportFieldSchema,
718
1074
  }),
719
1075
  }),
720
1076
  });
@@ -730,6 +1086,27 @@ export const WSSetOperatorRuntimeStateMessageSchema = WSBaseMessageSchema.extend
730
1086
  }),
731
1087
  });
732
1088
 
1089
+ /** Sets one strategy-owned stream to a protocol-approved state. */
1090
+ export const WSSetOperatorStreamStateMessageSchema = WSBaseMessageSchema.extend({
1091
+ type: z.literal(WSMessageType.SET_OPERATOR_STREAM_STATE),
1092
+ data: z.object({
1093
+ operatorId: z.string(),
1094
+ streamId: z.string().min(1),
1095
+ stateId: z.string().min(1),
1096
+ expectedLifecycleEpoch: z.number().int().nonnegative(),
1097
+ }),
1098
+ });
1099
+
1100
+ export const WSInvokeOperatorStrategyActionMessageSchema = WSBaseMessageSchema.extend({
1101
+ type: z.literal(WSMessageType.INVOKE_OPERATOR_STRATEGY_ACTION),
1102
+ data: z.object({
1103
+ operatorId: z.string().min(1),
1104
+ target: StrategyActionTargetSchema,
1105
+ actionId: z.string().min(1),
1106
+ payload: z.unknown().optional(),
1107
+ }),
1108
+ });
1109
+
733
1110
  /**
734
1111
  * 设置操作员运行时槽位内容消息
735
1112
  */
@@ -796,6 +1173,52 @@ export const WSOperatorRequestCallMessageSchema = WSBaseMessageSchema.extend({
796
1173
  }),
797
1174
  });
798
1175
 
1176
+ export const WSOperatorQueueEnqueueMessageSchema = WSBaseMessageSchema.extend({
1177
+ type: z.literal(WSMessageType.OPERATOR_QUEUE_ENQUEUE),
1178
+ data: z.object({
1179
+ operatorId: z.string(),
1180
+ callsign: z.string(),
1181
+ selectedFrame: WSSelectedFrameSchema.optional(),
1182
+ startIfIdle: z.boolean().optional(),
1183
+ }),
1184
+ });
1185
+
1186
+ export const WSOperatorQueueReorderMessageSchema = WSBaseMessageSchema.extend({
1187
+ type: z.literal(WSMessageType.OPERATOR_QUEUE_REORDER),
1188
+ data: z.object({
1189
+ operatorId: z.string(),
1190
+ entryId: z.string(),
1191
+ beforeEntryId: z.string().nullable(),
1192
+ expectedVersion: z.number().int().nonnegative(),
1193
+ }),
1194
+ });
1195
+
1196
+ export const WSOperatorQueueRetryMessageSchema = WSBaseMessageSchema.extend({
1197
+ type: z.literal(WSMessageType.OPERATOR_QUEUE_RETRY),
1198
+ data: z.object({
1199
+ operatorId: z.string(),
1200
+ entryId: z.string(),
1201
+ expectedVersion: z.number().int().nonnegative(),
1202
+ }),
1203
+ });
1204
+
1205
+ export const WSOperatorQueueRemoveMessageSchema = WSBaseMessageSchema.extend({
1206
+ type: z.literal(WSMessageType.OPERATOR_QUEUE_REMOVE),
1207
+ data: z.object({
1208
+ operatorId: z.string(),
1209
+ entryId: z.string(),
1210
+ expectedVersion: z.number().int().nonnegative(),
1211
+ }),
1212
+ });
1213
+
1214
+ export const WSOperatorQueueClearMessageSchema = WSBaseMessageSchema.extend({
1215
+ type: z.literal(WSMessageType.OPERATOR_QUEUE_CLEAR),
1216
+ data: z.object({
1217
+ operatorId: z.string(),
1218
+ expectedVersion: z.number().int().nonnegative(),
1219
+ }),
1220
+ });
1221
+
799
1222
  /**
800
1223
  * 设置客户端启用的操作员列表消息
801
1224
  */
@@ -856,6 +1279,8 @@ export type WSOperatorsListMessage = z.infer<typeof WSOperatorsListMessageSchema
856
1279
  export type WSOperatorStatusUpdateMessage = z.infer<typeof WSOperatorStatusUpdateMessageSchema>;
857
1280
  export type WSSetOperatorContextMessage = z.infer<typeof WSSetOperatorContextMessageSchema>;
858
1281
  export type WSSetOperatorRuntimeStateMessage = z.infer<typeof WSSetOperatorRuntimeStateMessageSchema>;
1282
+ export type WSSetOperatorStreamStateMessage = z.infer<typeof WSSetOperatorStreamStateMessageSchema>;
1283
+ export type WSInvokeOperatorStrategyActionMessage = z.infer<typeof WSInvokeOperatorStrategyActionMessageSchema>;
859
1284
  export type WSSetOperatorRuntimeSlotContentMessage = z.infer<typeof WSSetOperatorRuntimeSlotContentMessageSchema>;
860
1285
  export type WSSetOperatorTransmitCyclesMessage = z.infer<typeof WSSetOperatorTransmitCyclesMessageSchema>;
861
1286
  export type WSStartOperatorMessage = z.infer<typeof WSStartOperatorMessageSchema>;
@@ -875,6 +1300,11 @@ export const WSTransmissionLogMessageSchema = WSBaseMessageSchema.extend({
875
1300
  type: z.literal(WSMessageType.TRANSMISSION_LOG),
876
1301
  data: z.object({
877
1302
  operatorId: z.string(),
1303
+ frameId: z.string(),
1304
+ revision: z.number().int().nonnegative(),
1305
+ playbackGeneration: z.number().int().positive(),
1306
+ phase: z.literal('on_air'),
1307
+ physicalConfirmed: z.literal(true),
878
1308
  time: z.string(),
879
1309
  message: z.string(),
880
1310
  frequency: z.number(),
@@ -951,6 +1381,34 @@ export const WSLogbookUpdatedMessageSchema = WSBaseMessageSchema.extend({
951
1381
 
952
1382
  export type WSLogbookUpdatedMessage = z.infer<typeof WSLogbookUpdatedMessageSchema>;
953
1383
 
1384
+ export const WSLogbookHealthChangedMessageSchema = WSBaseMessageSchema.extend({
1385
+ type: z.literal(WSMessageType.LOGBOOK_HEALTH_CHANGED),
1386
+ data: z.object({
1387
+ logBookId: z.string(),
1388
+ health: LogbookHealthSchema,
1389
+ }),
1390
+ });
1391
+
1392
+ export type WSLogbookHealthChangedMessage = z.infer<typeof WSLogbookHealthChangedMessageSchema>;
1393
+
1394
+ export const WSLogbookWriteFailedMessageSchema = WSBaseMessageSchema.extend({
1395
+ type: z.literal(WSMessageType.LOGBOOK_WRITE_FAILED),
1396
+ data: z.object({
1397
+ logBookId: z.string(),
1398
+ operatorId: z.string().optional(),
1399
+ attemptId: z.string().min(8).max(128).regex(/^[A-Za-z0-9._:-]+$/).optional(),
1400
+ unsavedCount: z.number().int().positive().optional(),
1401
+ error: z.object({
1402
+ code: LogbookOperationErrorCodeSchema,
1403
+ message: z.string(),
1404
+ systemCode: z.string().optional(),
1405
+ occurredAt: z.number(),
1406
+ }),
1407
+ }).strict(),
1408
+ });
1409
+
1410
+ export type WSLogbookWriteFailedMessage = z.infer<typeof WSLogbookWriteFailedMessageSchema>;
1411
+
954
1412
  /**
955
1413
  * 电台状态变化消息
956
1414
  */
@@ -973,6 +1431,8 @@ export const WSRadioStatusChangedMessageSchema = WSBaseMessageSchema.extend({
973
1431
  meterCapabilities: MeterCapabilitiesSchema.optional(), // 电台数值表能力(connected=true 时应始终携带)
974
1432
  /** @deprecated Tuner capability is now in radioCapabilityList event. Kept for backward compat. */
975
1433
  tunerCapabilities: TunerCapabilitiesSchema.optional(),
1434
+ /** 虚拟频差实际生效状态(多op发射时为 false) */
1435
+ fakeFrequencyEffective: z.boolean().optional(),
976
1436
  }),
977
1437
  });
978
1438
 
@@ -1199,6 +1659,8 @@ export const WSTextMessageSchema = WSBaseMessageSchema.extend({
1199
1659
  text: z.string(),
1200
1660
  color: z.enum(['success', 'warning', 'danger', 'default']).optional(),
1201
1661
  timeout: z.number().nullable().optional(), // null 表示需要手动关闭,number 表示自动关闭的毫秒数
1662
+ /** 服务端创建消息的时间戳,用于前端识别后台积压消息 */
1663
+ createdAtMs: z.number().optional(),
1202
1664
  /** i18n key,前端有此字段时优先翻译显示 */
1203
1665
  key: z.string().optional(),
1204
1666
  /** i18n 插值参数 */
@@ -1255,6 +1717,19 @@ export const WSWriteRadioCapabilityMessageSchema = WSBaseMessageSchema.extend({
1255
1717
 
1256
1718
  export type WSWriteRadioCapabilityMessage = z.infer<typeof WSWriteRadioCapabilityMessageSchema>;
1257
1719
 
1720
+ export const SetSplitFrequencyPayloadSchema = z.object({
1721
+ txFrequency: z.number().finite().int().min(1_000_000).max(1_000_000_000),
1722
+ });
1723
+
1724
+ export type SetSplitFrequencyPayload = z.infer<typeof SetSplitFrequencyPayloadSchema>;
1725
+
1726
+ export const WSSetSplitFrequencyMessageSchema = WSBaseMessageSchema.extend({
1727
+ type: z.literal(WSMessageType.SET_SPLIT_FREQUENCY),
1728
+ data: SetSplitFrequencyPayloadSchema,
1729
+ });
1730
+
1731
+ export type WSSetSplitFrequencyMessage = z.infer<typeof WSSetSplitFrequencyMessageSchema>;
1732
+
1258
1733
  // ===== 认证相关消息 =====
1259
1734
 
1260
1735
  /**
@@ -1291,6 +1766,20 @@ export const WSAuthPublicViewerMessageSchema = WSBaseMessageSchema.extend({
1291
1766
 
1292
1767
  export type WSAuthPublicViewerMessage = z.infer<typeof WSAuthPublicViewerMessageSchema>;
1293
1768
 
1769
+ export const WSAccessDeniedDataSchema = z.object({
1770
+ reason: z.enum([
1771
+ 'capacity_reached',
1772
+ 'origin_not_allowed',
1773
+ 'authentication_timeout',
1774
+ 'handshake_timeout',
1775
+ 'ip_limit_reached',
1776
+ ]),
1777
+ current: z.number().int().nonnegative().optional(),
1778
+ limit: z.number().int().positive().optional(),
1779
+ retryAfterMs: z.number().int().nonnegative().optional(),
1780
+ });
1781
+ export type WSAccessDeniedData = z.infer<typeof WSAccessDeniedDataSchema>;
1782
+
1294
1783
  /**
1295
1784
  * 认证结果(服务端到客户端)
1296
1785
  */
@@ -1378,12 +1867,23 @@ export const WSMessageSchema = z.discriminatedUnion('type', [
1378
1867
  WSPongMessageSchema,
1379
1868
  // 服务端到客户端
1380
1869
  WSModeChangedMessageSchema,
1870
+ WSSubscribeImageRxMessageSchema,
1871
+ WSImageRadioStatusMessageSchema,
1872
+ WSImageRxEventMessageSchema,
1873
+ WSSstvTxStartMessageSchema,
1874
+ WSSstvTxCancelMessageSchema,
1875
+ WSSstvTxStatusMessageSchema,
1876
+ WSSstvTxCommandResultMessageSchema,
1877
+ WSFaxCalibrationSetMessageSchema,
1878
+ WSFaxCalibrationResetMessageSchema,
1879
+ WSFaxCalibrationCommandResultMessageSchema,
1381
1880
  WSSlotStartMessageSchema,
1382
1881
  WSSubWindowMessageSchema,
1383
1882
  WSSlotPackUpdatedMessageSchema,
1384
1883
  WSSpectrumCapabilitiesMessageSchema,
1385
1884
  WSSubscribeSpectrumMessageSchema,
1386
1885
  WSSpectrumSubscriptionChangedMessageSchema,
1886
+ WSSpectrumViewportChangedMessageSchema,
1387
1887
  WSSpectrumFrameMessageSchema,
1388
1888
  WSSpectrumSessionStateChangedMessageSchema,
1389
1889
  WSInvokeSpectrumControlMessageSchema,
@@ -1408,11 +1908,18 @@ export const WSMessageSchema = z.discriminatedUnion('type', [
1408
1908
  WSOperatorStatusUpdateMessageSchema,
1409
1909
  WSSetOperatorContextMessageSchema,
1410
1910
  WSSetOperatorRuntimeStateMessageSchema,
1911
+ WSSetOperatorStreamStateMessageSchema,
1912
+ WSInvokeOperatorStrategyActionMessageSchema,
1411
1913
  WSSetOperatorRuntimeSlotContentMessageSchema,
1412
1914
  WSSetOperatorTransmitCyclesMessageSchema,
1413
1915
  WSStartOperatorMessageSchema,
1414
1916
  WSStopOperatorMessageSchema,
1415
1917
  WSOperatorRequestCallMessageSchema,
1918
+ WSOperatorQueueEnqueueMessageSchema,
1919
+ WSOperatorQueueReorderMessageSchema,
1920
+ WSOperatorQueueRetryMessageSchema,
1921
+ WSOperatorQueueRemoveMessageSchema,
1922
+ WSOperatorQueueClearMessageSchema,
1416
1923
 
1417
1924
  // 音量控制消息
1418
1925
  WSSetVolumeGainMessageSchema,
@@ -1422,6 +1929,8 @@ export const WSMessageSchema = z.discriminatedUnion('type', [
1422
1929
  WSQSORecordAddedMessageSchema,
1423
1930
  WSQSORecordUpdatedMessageSchema,
1424
1931
  WSLogbookUpdatedMessageSchema,
1932
+ WSLogbookHealthChangedMessageSchema,
1933
+ WSLogbookWriteFailedMessageSchema,
1425
1934
 
1426
1935
  // 客户端启用操作员列表消息
1427
1936
  WSSetClientEnabledOperatorsMessageSchema,
@@ -1446,6 +1955,7 @@ export const WSMessageSchema = z.discriminatedUnion('type', [
1446
1955
 
1447
1956
  // 频率管理消息
1448
1957
  WSFrequencyChangedMessageSchema,
1958
+ WSSetSplitFrequencyMessageSchema,
1449
1959
 
1450
1960
  // PTT状态管理消息
1451
1961
  WSPTTStatusChangedMessageSchema,
@@ -1498,6 +2008,7 @@ export type WSSlotPackUpdatedMessage = z.infer<typeof WSSlotPackUpdatedMessageSc
1498
2008
  export type WSSpectrumCapabilitiesMessage = z.infer<typeof WSSpectrumCapabilitiesMessageSchema>;
1499
2009
  export type WSSubscribeSpectrumMessage = z.infer<typeof WSSubscribeSpectrumMessageSchema>;
1500
2010
  export type WSSpectrumSubscriptionChangedMessage = z.infer<typeof WSSpectrumSubscriptionChangedMessageSchema>;
2011
+ export type WSSpectrumViewportChangedMessage = z.infer<typeof WSSpectrumViewportChangedMessageSchema>;
1501
2012
  export type WSSpectrumFrameMessage = z.infer<typeof WSSpectrumFrameMessageSchema>;
1502
2013
  export type WSSpectrumSessionStateChangedMessage = z.infer<typeof WSSpectrumSessionStateChangedMessageSchema>;
1503
2014
  export type WSInvokeSpectrumControlMessage = z.infer<typeof WSInvokeSpectrumControlMessageSchema>;
@@ -1515,13 +2026,33 @@ export type WSGetStatusMessage = z.infer<typeof WSGetStatusMessageSchema>;
1515
2026
 
1516
2027
  export const TransmitRequestSchema = z.object({
1517
2028
  operatorId: z.string(),
2029
+ streamId: z.string().min(1).optional(),
1518
2030
  transmission: z.string(),
2031
+ audioFrequencyHz: z.number().min(0).max(5000).optional(),
1519
2032
  /** 是否覆盖同一操作员在同一时隙的现有 TX 帧(自动重决策时为 true) */
1520
2033
  replaceExisting: z.boolean().optional(),
2034
+ source: z.enum(['standard-qso', 'plugin', 'late-decode', 'operator-edit', 'manual']).optional(),
2035
+ reason: z.string().optional(),
2036
+ /** Host command epoch used to tombstone stale encode/mix callbacks. */
2037
+ decisionEpoch: z.number().int().nonnegative().optional(),
1521
2038
  });
1522
2039
 
1523
2040
  export type TransmitRequest = z.infer<typeof TransmitRequestSchema>;
1524
2041
 
2042
+ export const TransmitBatchRequestSchema = z.object({
2043
+ operatorId: z.string(),
2044
+ transmissions: z.array(z.object({
2045
+ streamId: z.string().min(1),
2046
+ transmission: z.string(),
2047
+ audioFrequencyHz: z.number().min(0).max(5000),
2048
+ })).max(5),
2049
+ replaceExisting: z.boolean().optional(),
2050
+ source: z.enum(['standard-qso', 'plugin', 'late-decode', 'operator-edit', 'manual']).optional(),
2051
+ reason: z.string().optional(),
2052
+ decisionEpoch: z.number().int().nonnegative().optional(),
2053
+ });
2054
+ export type TransmitBatchRequest = z.infer<typeof TransmitBatchRequestSchema>;
2055
+
1525
2056
  // ===== 前端应用事件接口 =====
1526
2057
 
1527
2058
  /**
@@ -1529,7 +2060,12 @@ export type TransmitRequest = z.infer<typeof TransmitRequestSchema>;
1529
2060
  */
1530
2061
  export const TransmissionCompleteInfoSchema = z.object({
1531
2062
  operatorId: z.string(),
2063
+ streamId: z.string().optional(),
2064
+ trackId: z.string().optional(),
1532
2065
  success: z.boolean(),
2066
+ frameId: z.string().optional(),
2067
+ physicalConfirmed: z.boolean().optional(),
2068
+ terminalReason: z.string().optional(),
1533
2069
  duration: z.number().optional(),
1534
2070
  error: z.string().optional(),
1535
2071
  mixedWith: z.array(z.string()).optional(), // 与其他操作员混音的ID列表
@@ -1559,9 +2095,16 @@ export interface DigitalRadioEngineEvents {
1559
2095
 
1560
2096
  // 发射相关事件
1561
2097
  requestTransmit: (request: TransmitRequest) => void;
2098
+ requestTransmitBatch: (request: TransmitBatchRequest) => void;
1562
2099
  transmissionComplete: (info: TransmissionCompleteInfo) => void;
1563
2100
  transmissionLog: (data: {
1564
2101
  operatorId: string;
2102
+ streamId: string;
2103
+ frameId: string;
2104
+ revision: number;
2105
+ playbackGeneration: number;
2106
+ phase: 'on_air';
2107
+ physicalConfirmed: true;
1565
2108
  time: string;
1566
2109
  message: string;
1567
2110
  frequency: number;
@@ -1584,7 +2127,7 @@ export interface DigitalRadioEngineEvents {
1584
2127
  // 连接事件
1585
2128
  connected: () => void;
1586
2129
  reconnecting: (data: { attempt: number; delayMs: number }) => void;
1587
- disconnected: () => void;
2130
+ disconnected: (data?: WSAccessDeniedData) => void;
1588
2131
  handshakeComplete: (data: z.infer<typeof WSServerHandshakeCompleteMessageSchema>['data']) => void;
1589
2132
  connectionReplaced: (data: { reason: string }) => void;
1590
2133
  error: (error: Error) => void;
@@ -1598,6 +2141,11 @@ export interface DigitalRadioEngineEvents {
1598
2141
  // PTT状态控制事件
1599
2142
  pttStatusChanged: (data: PTTStatus) => void;
1600
2143
  tuneToneStatusChanged: (data: TuneToneStatus) => void;
2144
+ imageRadioStatus: (data: ImageRadioStatus) => void;
2145
+ imageRxEvent: (data: ImageRxEvent) => void;
2146
+ sstvTxStatus: (data: SstvTxStatus) => void;
2147
+ sstvTxCommandResult: (data: SstvTxCommandResult) => void;
2148
+ faxCalibrationCommandResult: (data: FaxCalibrationCommandResult) => void;
1601
2149
 
1602
2150
  // 电台数值表事件
1603
2151
  meterData: (data: MeterData) => void;
@@ -1609,6 +2157,8 @@ export interface DigitalRadioEngineEvents {
1609
2157
  qsoRecordAdded: (data: { operatorId: string; logBookId: string; qsoRecord: z.infer<typeof QSORecordSchema> }) => void;
1610
2158
  qsoRecordUpdated: (data: { operatorId: string; logBookId: string; qsoRecord: z.infer<typeof QSORecordSchema> }) => void;
1611
2159
  logbookUpdated: (data: { logBookId: string; statistics: z.infer<typeof LogBookStatisticsSchema>; operatorId?: string }) => void;
2160
+ logbookHealthChanged: (data: { logBookId: string; health: z.infer<typeof LogbookHealthSchema> }) => void;
2161
+ logbookWriteFailed: (data: z.infer<typeof WSLogbookWriteFailedMessageSchema>['data']) => void;
1612
2162
  textMessage: (data: z.infer<typeof WSTextMessageSchema>['data']) => void;
1613
2163
 
1614
2164
  /** @deprecated Tuner state is now delivered via radioCapabilityChanged event (id='tuner_switch') */
@@ -1629,18 +2179,20 @@ export interface DigitalRadioEngineEvents {
1629
2179
 
1630
2180
  // Profile 管理事件
1631
2181
  profileChanged: (data: z.infer<typeof ProfileChangedEventSchema>) => void;
1632
- profileListUpdated: (data: { profiles: z.infer<typeof RadioProfileSchema>[]; activeProfileId: string | null }) => void;
2182
+ profileListUpdated: (data: { profiles: z.infer<typeof RadioProfileSchema>[]; activeProfileId: string | null; hasConfiguredProfiles?: boolean }) => void;
1633
2183
  realtimeSettingsChanged: (data: RealtimeSettingsResponseData) => void;
1634
2184
 
1635
2185
  // 认证事件
1636
2186
  authRequired: (data: { allowPublicViewing: boolean }) => void;
1637
2187
  authResult: (data: { success: boolean; role?: UserRole; label?: string; operatorIds?: string[]; error?: string }) => void;
1638
2188
  authExpired: (data: { reason?: string }) => void;
2189
+ accessDenied: (data: WSAccessDeniedData) => void;
1639
2190
 
1640
2191
  // 语音模式事件
1641
2192
  voicePttLockChanged: (data: VoicePTTLock) => void;
1642
2193
  voiceRadioModeChanged: (data: { radioMode: string }) => void;
1643
2194
  voiceKeyerStatusChanged: (data: VoiceKeyerStatus) => void;
2195
+ androidOperatorAudioStatusChanged: (data: AndroidOperatorAudioStatus) => void;
1644
2196
 
1645
2197
  // CW 模式事件
1646
2198
  cwKeyerStatusChanged: (data: CWKeyerStatus) => void;
@@ -1693,10 +2245,46 @@ export interface DigitalRadioEngineEvents {
1693
2245
  transmitStart: (slotInfo: z.infer<typeof SlotInfoSchema>) => void;
1694
2246
  timingWarning: (data: { title: string; text: string }) => void;
1695
2247
  operatorSlotChanged: (data: { operatorId: string; slot: string }) => void;
2248
+ operatorStreamStateChanged: (data: {
2249
+ operatorId: string;
2250
+ streamId: string;
2251
+ state: string;
2252
+ commandEpoch?: number;
2253
+ source?: 'manual' | 'plugin' | 'late-decode' | 'slot-auto';
2254
+ }) => void;
1696
2255
  operatorSlotContentChanged: (data: { operatorId: string; slot: string; content: string }) => void;
1697
2256
  operatorFrequencyChanged: (data: { operatorId: string; frequency: number }) => void;
1698
- operatorTransmitCyclesChanged: (data: { operatorId: string; transmitCycles: number[] }) => void;
1699
- recordQSO: (data: { operatorId: string; qsoRecord: z.infer<typeof QSORecordSchema> }) => void;
2257
+ operatorTransmitCyclesChanged: (data: {
2258
+ operatorId: string;
2259
+ previousTransmitCycles?: number[];
2260
+ transmitCycles: number[];
2261
+ commandEpoch?: number;
2262
+ source?: 'manual' | 'plugin' | 'late-decode' | 'slot-auto';
2263
+ reason?: string;
2264
+ }) => void;
2265
+ qsoLifecycleChanged: (data: {
2266
+ operatorId: string;
2267
+ streamId?: string;
2268
+ lifecycleEpoch: number;
2269
+ runtimeGeneration?: number;
2270
+ }) => void;
2271
+ recordQSO: (data: {
2272
+ operatorId: string;
2273
+ streamId?: string;
2274
+ qsoLifecycleId?: string;
2275
+ qsoLifecycleEpoch?: number;
2276
+ qsoRuntimeGeneration?: number;
2277
+ qsoRecord: z.infer<typeof QSORecordSchema>;
2278
+ persistencePolicy?: z.infer<typeof QSOPersistencePolicySchema>;
2279
+ destination?:
2280
+ | { kind: 'plugin-session'; sessionId: string }
2281
+ | { kind: 'plugin-session-key'; sessionKey: string };
2282
+ sourcePluginName?: string;
2283
+ metadata?: Record<string, unknown>;
2284
+ retryAttemptId?: string;
2285
+ resolve?: (record: z.infer<typeof QSORecordSchema>) => void;
2286
+ reject?: (error: unknown) => void;
2287
+ }) => void;
1700
2288
  checkHasWorkedCallsign: (data: { operatorId: string; callsign: string; requestId: string }) => void;
1701
2289
  hasWorkedCallsignResponse: (data: { requestId: string; hasWorked: boolean }) => void;
1702
2290
  }