@tx5dr/contracts 2.0.0 → 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.
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/schema/__tests__/assisted-queue.schema.test.js +1 -0
- package/dist/schema/__tests__/assisted-queue.schema.test.js.map +1 -1
- package/dist/schema/__tests__/meter.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/meter.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/meter.schema.test.js +27 -0
- package/dist/schema/__tests__/meter.schema.test.js.map +1 -0
- package/dist/schema/__tests__/operator-context-report.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/operator-context-report.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/operator-context-report.schema.test.js +70 -0
- package/dist/schema/__tests__/operator-context-report.schema.test.js.map +1 -0
- package/dist/schema/__tests__/plugin-market.schema.test.js +107 -3
- package/dist/schema/__tests__/plugin-market.schema.test.js.map +1 -1
- package/dist/schema/__tests__/qso.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/qso.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/qso.schema.test.js +70 -0
- package/dist/schema/__tests__/qso.schema.test.js.map +1 -0
- package/dist/schema/__tests__/radio-power-support.test.js +4 -1
- package/dist/schema/__tests__/radio-power-support.test.js.map +1 -1
- package/dist/schema/__tests__/radio.schema.test.js +52 -1
- package/dist/schema/__tests__/radio.schema.test.js.map +1 -1
- package/dist/schema/__tests__/remote-access.schema.test.js +1 -1
- package/dist/schema/__tests__/remote-access.schema.test.js.map +1 -1
- package/dist/schema/__tests__/spectrum.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/spectrum.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/spectrum.schema.test.js +107 -0
- package/dist/schema/__tests__/spectrum.schema.test.js.map +1 -0
- package/dist/schema/__tests__/strategy-transmission.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/strategy-transmission.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/strategy-transmission.schema.test.js +95 -0
- package/dist/schema/__tests__/strategy-transmission.schema.test.js.map +1 -0
- package/dist/schema/api-response.schema.d.ts +235 -0
- package/dist/schema/api-response.schema.d.ts.map +1 -1
- package/dist/schema/api-response.schema.js +9 -0
- package/dist/schema/api-response.schema.js.map +1 -1
- package/dist/schema/auth.schema.d.ts +2 -2
- package/dist/schema/cpu-profile.schema.d.ts +2 -2
- package/dist/schema/device-ui.schema.d.ts +10 -10
- package/dist/schema/image-radio.schema.d.ts +2597 -0
- package/dist/schema/image-radio.schema.d.ts.map +1 -0
- package/dist/schema/image-radio.schema.js +283 -0
- package/dist/schema/image-radio.schema.js.map +1 -0
- package/dist/schema/logbook.schema.d.ts +203 -15
- package/dist/schema/logbook.schema.d.ts.map +1 -1
- package/dist/schema/logbook.schema.js +1 -0
- package/dist/schema/logbook.schema.js.map +1 -1
- package/dist/schema/mode.schema.d.ts +2 -0
- package/dist/schema/mode.schema.d.ts.map +1 -1
- package/dist/schema/mode.schema.js +16 -0
- package/dist/schema/mode.schema.js.map +1 -1
- package/dist/schema/openwebrx.schema.d.ts +2 -2
- package/dist/schema/operator.schema.d.ts +2676 -0
- package/dist/schema/operator.schema.d.ts.map +1 -1
- package/dist/schema/operator.schema.js +4 -19
- package/dist/schema/operator.schema.js.map +1 -1
- package/dist/schema/plugin.schema.d.ts +1780 -475
- package/dist/schema/plugin.schema.d.ts.map +1 -1
- package/dist/schema/plugin.schema.js +108 -12
- package/dist/schema/plugin.schema.js.map +1 -1
- package/dist/schema/qso.schema.d.ts +239 -1
- package/dist/schema/qso.schema.d.ts.map +1 -1
- package/dist/schema/qso.schema.js +61 -0
- package/dist/schema/qso.schema.js.map +1 -1
- package/dist/schema/radio-capability.schema.d.ts +1 -1
- package/dist/schema/radio-capability.schema.d.ts.map +1 -1
- package/dist/schema/radio-capability.schema.js +1 -0
- package/dist/schema/radio-capability.schema.js.map +1 -1
- package/dist/schema/radio-power.schema.d.ts +15 -0
- package/dist/schema/radio-power.schema.d.ts.map +1 -1
- package/dist/schema/radio-profile.schema.d.ts +251 -0
- package/dist/schema/radio-profile.schema.d.ts.map +1 -1
- package/dist/schema/radio-profile.schema.js +7 -0
- package/dist/schema/radio-profile.schema.js.map +1 -1
- package/dist/schema/radio.schema.d.ts +174 -3
- package/dist/schema/radio.schema.d.ts.map +1 -1
- package/dist/schema/radio.schema.js +31 -2
- package/dist/schema/radio.schema.js.map +1 -1
- package/dist/schema/rigctld.schema.d.ts +6 -6
- package/dist/schema/slot-info.schema.d.ts +13 -0
- package/dist/schema/slot-info.schema.d.ts.map +1 -1
- package/dist/schema/slot-info.schema.js +2 -1
- package/dist/schema/slot-info.schema.js.map +1 -1
- package/dist/schema/spectrum-config.schema.d.ts +638 -0
- package/dist/schema/spectrum-config.schema.d.ts.map +1 -0
- package/dist/schema/spectrum-config.schema.js +129 -0
- package/dist/schema/spectrum-config.schema.js.map +1 -0
- package/dist/schema/spectrum.schema.d.ts +1313 -20
- package/dist/schema/spectrum.schema.d.ts.map +1 -1
- package/dist/schema/spectrum.schema.js +72 -0
- package/dist/schema/spectrum.schema.js.map +1 -1
- package/dist/schema/transmission.schema.d.ts +7 -0
- package/dist/schema/transmission.schema.d.ts.map +1 -1
- package/dist/schema/tx-audio-input.schema.d.ts +8 -0
- package/dist/schema/tx-audio-input.schema.d.ts.map +1 -0
- package/dist/schema/tx-audio-input.schema.js +19 -0
- package/dist/schema/tx-audio-input.schema.js.map +1 -0
- package/dist/schema/voice.schema.d.ts +1 -1
- package/dist/schema/voice.schema.d.ts.map +1 -1
- package/dist/schema/voice.schema.js +1 -1
- package/dist/schema/voice.schema.js.map +1 -1
- package/dist/schema/websocket.schema.d.ts +27480 -2525
- package/dist/schema/websocket.schema.d.ts.map +1 -1
- package/dist/schema/websocket.schema.js +298 -11
- package/dist/schema/websocket.schema.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +4 -0
- package/src/schema/__tests__/assisted-queue.schema.test.ts +1 -0
- package/src/schema/__tests__/meter.schema.test.ts +28 -0
- package/src/schema/__tests__/operator-context-report.schema.test.ts +77 -0
- package/src/schema/__tests__/plugin-market.schema.test.ts +116 -2
- package/src/schema/__tests__/qso.schema.test.ts +91 -0
- package/src/schema/__tests__/radio-power-support.test.ts +4 -1
- package/src/schema/__tests__/radio.schema.test.ts +60 -1
- package/src/schema/__tests__/remote-access.schema.test.ts +1 -1
- package/src/schema/__tests__/spectrum.schema.test.ts +119 -0
- package/src/schema/__tests__/strategy-transmission.schema.test.ts +106 -0
- package/src/schema/api-response.schema.ts +11 -0
- package/src/schema/image-radio.schema.ts +342 -0
- package/src/schema/logbook.schema.ts +1 -0
- package/src/schema/mode.schema.ts +16 -0
- package/src/schema/operator.schema.ts +4 -19
- package/src/schema/plugin.schema.ts +119 -13
- package/src/schema/qso.schema.ts +71 -0
- package/src/schema/radio-capability.schema.ts +1 -0
- package/src/schema/radio-profile.schema.ts +7 -0
- package/src/schema/radio.schema.ts +35 -2
- package/src/schema/slot-info.schema.ts +2 -1
- package/src/schema/spectrum-config.schema.ts +156 -0
- package/src/schema/spectrum.schema.ts +89 -0
- package/src/schema/tx-audio-input.schema.ts +22 -0
- package/src/schema/voice.schema.ts +1 -1
- package/src/schema/websocket.schema.ts +383 -12
- package/test/image-radio-schema.test.ts +107 -0
- package/test/plugin-slot-schema.test.ts +31 -0
- package/CLAUDE.md +0 -41
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const ImageFamilySchema = z.enum(['sstv', 'fax']);
|
|
4
|
+
export type ImageFamily = z.infer<typeof ImageFamilySchema>;
|
|
5
|
+
|
|
6
|
+
export const ImagePixelFormatSchema = z.enum(['rgb8', 'gray8']);
|
|
7
|
+
export type ImagePixelFormat = z.infer<typeof ImagePixelFormatSchema>;
|
|
8
|
+
|
|
9
|
+
export const ImageSstvReceiveProfileSchema = z.discriminatedUnion('strategy', [
|
|
10
|
+
z.object({ family: z.literal('sstv'), strategy: z.literal('auto') }),
|
|
11
|
+
z.object({ family: z.literal('sstv'), strategy: z.literal('manual'), mode: z.string().min(1) }),
|
|
12
|
+
]);
|
|
13
|
+
export type ImageSstvReceiveProfile = z.infer<typeof ImageSstvReceiveProfileSchema>;
|
|
14
|
+
|
|
15
|
+
export const ImageFaxReceiveProfileSchema = z.discriminatedUnion('strategy', [
|
|
16
|
+
z.object({ family: z.literal('fax'), strategy: z.literal('auto') }),
|
|
17
|
+
z.object({
|
|
18
|
+
family: z.literal('fax'), strategy: z.literal('manual'),
|
|
19
|
+
ioc: z.enum(['ioc288', 'ioc576']), lpm: z.number().int().positive(),
|
|
20
|
+
modulation: z.enum(['fm', 'am']), centerHz: z.number().positive(),
|
|
21
|
+
deviationHz: z.number().positive(),
|
|
22
|
+
}),
|
|
23
|
+
]);
|
|
24
|
+
export type ImageFaxReceiveProfile = z.infer<typeof ImageFaxReceiveProfileSchema>;
|
|
25
|
+
|
|
26
|
+
export const ImageReceiveProfileSchema = z.union([
|
|
27
|
+
ImageSstvReceiveProfileSchema,
|
|
28
|
+
ImageFaxReceiveProfileSchema,
|
|
29
|
+
]);
|
|
30
|
+
export type ImageReceiveProfile = z.infer<typeof ImageReceiveProfileSchema>;
|
|
31
|
+
|
|
32
|
+
export const ImageSstvModeInfoSchema = z.object({
|
|
33
|
+
mode: z.string(), name: z.string(), visCode: z.number().int().nonnegative(),
|
|
34
|
+
width: z.number().int().positive(), height: z.number().int().positive(),
|
|
35
|
+
colorLayout: z.enum(['monochrome', 'rgb', 'yuv']),
|
|
36
|
+
scanLayout: z.enum(['monochrome', 'martin', 'scottie', 'robot', 'pd', 'wraase', 'pasokon']),
|
|
37
|
+
lineSeconds: z.number().positive(), rowsPerLine: z.number().int().positive(),
|
|
38
|
+
status: z.enum(['canonical', 'compatibility']),
|
|
39
|
+
});
|
|
40
|
+
export type ImageSstvModeInfo = z.infer<typeof ImageSstvModeInfoSchema>;
|
|
41
|
+
|
|
42
|
+
export const ImageRadioCapabilitySchema = z.object({
|
|
43
|
+
available: z.boolean(),
|
|
44
|
+
reason: z.string().optional(),
|
|
45
|
+
sstv: z.object({ rx: z.literal(true), tx: z.literal(true) }),
|
|
46
|
+
fax: z.object({ rx: z.literal(true), tx: z.literal(false) }),
|
|
47
|
+
});
|
|
48
|
+
export type ImageRadioCapability = z.infer<typeof ImageRadioCapabilitySchema>;
|
|
49
|
+
|
|
50
|
+
export const ImageRadioServiceStateSchema = z.enum(['stopped', 'starting', 'ready', 'degraded', 'unavailable']);
|
|
51
|
+
export const ImageRxStateSchema = z.enum(['off', 'searching', 'acquiring', 'receiving', 'completed', 'aborted', 'error']);
|
|
52
|
+
export const SstvTxPhaseSchema = z.enum([
|
|
53
|
+
'idle', 'preparing', 'waiting_for_lease', 'keying', 'on_air', 'draining',
|
|
54
|
+
'completed', 'cancelled', 'error', 'ptt_unknown',
|
|
55
|
+
]);
|
|
56
|
+
export const SstvStationIdModeSchema = z.enum(['fsk', 'cw', 'none']);
|
|
57
|
+
export type SstvStationIdMode = z.infer<typeof SstvStationIdModeSchema>;
|
|
58
|
+
export const SstvTxEnvelopeSelectionSchema = z.object({
|
|
59
|
+
enhancedPreamble: z.boolean().default(true),
|
|
60
|
+
stationIdMode: SstvStationIdModeSchema.default('fsk'),
|
|
61
|
+
});
|
|
62
|
+
export type SstvTxEnvelopeSelection = z.infer<typeof SstvTxEnvelopeSelectionSchema>;
|
|
63
|
+
export const SstvTxEnvelopeSnapshotSchema = SstvTxEnvelopeSelectionSchema.extend({
|
|
64
|
+
callsign: z.string().optional(),
|
|
65
|
+
postImageGapMs: z.literal(500),
|
|
66
|
+
endGuardMs: z.literal(300),
|
|
67
|
+
cwWpm: z.literal(20),
|
|
68
|
+
cwToneHz: z.literal(800),
|
|
69
|
+
});
|
|
70
|
+
export type SstvTxEnvelopeSnapshot = z.infer<typeof SstvTxEnvelopeSnapshotSchema>;
|
|
71
|
+
export const SstvTxPreferencesSchema = SstvTxEnvelopeSelectionSchema.extend({
|
|
72
|
+
operatorId: z.string().min(1),
|
|
73
|
+
updatedAt: z.number(),
|
|
74
|
+
});
|
|
75
|
+
export type SstvTxPreferences = z.infer<typeof SstvTxPreferencesSchema>;
|
|
76
|
+
|
|
77
|
+
export const ImageSessionSummarySchema = z.object({
|
|
78
|
+
sessionId: z.string(),
|
|
79
|
+
family: ImageFamilySchema,
|
|
80
|
+
generation: z.number().int().nonnegative(),
|
|
81
|
+
revision: z.number().int().nonnegative(),
|
|
82
|
+
codecMode: z.string().optional(),
|
|
83
|
+
width: z.number().int().positive().optional(),
|
|
84
|
+
height: z.number().int().positive().optional(),
|
|
85
|
+
receivedLines: z.number().int().nonnegative().default(0),
|
|
86
|
+
firstAvailableLine: z.number().int().nonnegative().default(0),
|
|
87
|
+
startedAt: z.number(),
|
|
88
|
+
});
|
|
89
|
+
export type ImageSessionSummary = z.infer<typeof ImageSessionSummarySchema>;
|
|
90
|
+
|
|
91
|
+
export const SstvTxStatusSchema = z.object({
|
|
92
|
+
phase: SstvTxPhaseSchema,
|
|
93
|
+
sessionId: z.string().optional(),
|
|
94
|
+
requestId: z.string().optional(),
|
|
95
|
+
operatorId: z.string().optional(),
|
|
96
|
+
artifactId: z.string().optional(),
|
|
97
|
+
historyId: z.string().optional(),
|
|
98
|
+
mode: z.string().optional(),
|
|
99
|
+
encoderStage: z.enum(['preamble', 'vis', 'raster', 'stationId', 'guard', 'finished']).optional(),
|
|
100
|
+
envelope: SstvTxEnvelopeSnapshotSchema.optional(),
|
|
101
|
+
revision: z.number().int().nonnegative().default(0),
|
|
102
|
+
samplesEmitted: z.number().int().nonnegative().default(0),
|
|
103
|
+
estimatedTotalSamples: z.number().int().nonnegative().default(0),
|
|
104
|
+
currentRow: z.number().int().nonnegative().optional(),
|
|
105
|
+
startedAt: z.number().optional(),
|
|
106
|
+
errorCode: z.string().optional(),
|
|
107
|
+
});
|
|
108
|
+
export type SstvTxStatus = z.infer<typeof SstvTxStatusSchema>;
|
|
109
|
+
|
|
110
|
+
export const ImageRadioStatusSchema = z.object({
|
|
111
|
+
serviceState: ImageRadioServiceStateSchema,
|
|
112
|
+
family: ImageFamilySchema.nullable(),
|
|
113
|
+
receiveProfile: ImageReceiveProfileSchema.nullable(),
|
|
114
|
+
rxState: ImageRxStateSchema,
|
|
115
|
+
rxCaptureActive: z.boolean().default(false),
|
|
116
|
+
capability: ImageRadioCapabilitySchema,
|
|
117
|
+
currentSession: ImageSessionSummarySchema.nullable(),
|
|
118
|
+
tx: SstvTxStatusSchema,
|
|
119
|
+
nativeQueuedSamples: z.number().int().nonnegative().default(0),
|
|
120
|
+
jsBacklogSamples: z.number().int().nonnegative().default(0),
|
|
121
|
+
discontinuities: z.number().int().nonnegative().default(0),
|
|
122
|
+
updatedAt: z.number(),
|
|
123
|
+
});
|
|
124
|
+
export type ImageRadioStatus = z.infer<typeof ImageRadioStatusSchema>;
|
|
125
|
+
|
|
126
|
+
export const ImageRowPatchSchema = z.object({
|
|
127
|
+
rowIndex: z.number().int().nonnegative(),
|
|
128
|
+
width: z.number().int().positive(),
|
|
129
|
+
rowRevision: z.number().int().nonnegative(),
|
|
130
|
+
completeness: z.enum(['provisional', 'final']).optional(),
|
|
131
|
+
dataBase64: z.string(),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
export const ImagePaperBoundaryKindSchema = z.enum([
|
|
135
|
+
'initial', 'vis', 'syncTiming', 'aptPhasing', 'protocolEnd',
|
|
136
|
+
'manualMode', 'discontinuity', 'reset', 'truncated', 'protocolObserved',
|
|
137
|
+
'localTxStart', 'localTxEnd',
|
|
138
|
+
]);
|
|
139
|
+
export type ImagePaperBoundaryKind = z.infer<typeof ImagePaperBoundaryKindSchema>;
|
|
140
|
+
export const ImagePaperSourceSchema = z.enum(['rx', 'localTx']);
|
|
141
|
+
export type ImagePaperSource = z.infer<typeof ImagePaperSourceSchema>;
|
|
142
|
+
|
|
143
|
+
export const ImagePaperBoundarySchema = z.object({
|
|
144
|
+
boundaryId: z.string(), lineIndex: z.number().int().nonnegative(),
|
|
145
|
+
kind: ImagePaperBoundaryKindSchema, trusted: z.boolean(),
|
|
146
|
+
codecMode: z.string(), width: z.number().int().positive(),
|
|
147
|
+
pixelFormat: ImagePixelFormatSchema, timestamp: z.number(),
|
|
148
|
+
detection: z.string().optional(), nominalHeight: z.number().int().positive().optional(),
|
|
149
|
+
source: ImagePaperSourceSchema.optional(),
|
|
150
|
+
txSessionId: z.string().optional(),
|
|
151
|
+
txOutcome: z.enum(['completed', 'interrupted']).optional(),
|
|
152
|
+
});
|
|
153
|
+
export type ImagePaperBoundary = z.infer<typeof ImagePaperBoundarySchema>;
|
|
154
|
+
|
|
155
|
+
export const ImageFaxCalibrationPointSchema = z.object({
|
|
156
|
+
revision: z.number().int().nonnegative(),
|
|
157
|
+
referenceLine: z.number().int().nonnegative(),
|
|
158
|
+
phasePixels: z.number().finite(),
|
|
159
|
+
clockPpm: z.number().finite(),
|
|
160
|
+
confidence: z.number().min(0).max(1),
|
|
161
|
+
source: z.enum(['nominal', 'phasing', 'imageContent', 'manual']),
|
|
162
|
+
status: z.enum(['nominal', 'acquiring', 'locked', 'tracking', 'degraded']),
|
|
163
|
+
});
|
|
164
|
+
export type ImageFaxCalibrationPoint = z.infer<typeof ImageFaxCalibrationPointSchema>;
|
|
165
|
+
|
|
166
|
+
export const ImageFaxCalibrationSchema = z.object({
|
|
167
|
+
boundaryId: z.string().min(1),
|
|
168
|
+
revision: z.number().int().nonnegative(),
|
|
169
|
+
autoEnabled: z.boolean(),
|
|
170
|
+
autoPoints: z.array(ImageFaxCalibrationPointSchema).max(256),
|
|
171
|
+
manualPhasePixels: z.number().finite(),
|
|
172
|
+
manualClockPpm: z.number().finite(),
|
|
173
|
+
updatedAt: z.number(),
|
|
174
|
+
});
|
|
175
|
+
export type ImageFaxCalibration = z.infer<typeof ImageFaxCalibrationSchema>;
|
|
176
|
+
|
|
177
|
+
export const ImageRxEventSchema = z.discriminatedUnion('type', [
|
|
178
|
+
z.object({ type: z.literal('paperStarted'), session: ImageSessionSummarySchema, pixelFormat: ImagePixelFormatSchema }),
|
|
179
|
+
z.object({ type: z.literal('boundary'), sessionId: z.string(), generation: z.number().int().nonnegative(), revision: z.number().int().nonnegative(), boundary: ImagePaperBoundarySchema }),
|
|
180
|
+
z.object({ type: z.literal('faxCalibration'), sessionId: z.string(), generation: z.number().int().nonnegative(), revision: z.number().int().nonnegative(), calibration: ImageFaxCalibrationSchema }),
|
|
181
|
+
z.object({ type: z.literal('signalDetected'), family: ImageFamilySchema, confidence: z.number().min(0).max(1), candidates: z.array(z.string()), timestamp: z.number() }),
|
|
182
|
+
z.object({ type: z.literal('imageStarted'), session: ImageSessionSummarySchema, pixelFormat: ImagePixelFormatSchema, detection: z.string().optional(), confidence: z.number().min(0).max(1).optional() }),
|
|
183
|
+
z.object({ type: z.literal('rows'), sessionId: z.string(), generation: z.number().int().nonnegative(), revision: z.number().int().nonnegative(), pixelFormat: ImagePixelFormatSchema, rows: z.array(ImageRowPatchSchema).min(1).max(8) }),
|
|
184
|
+
z.object({ type: z.literal('imageCompleted'), sessionId: z.string(), generation: z.number().int().nonnegative(), revision: z.number().int().nonnegative(), artifactId: z.string(), previewUrl: z.string(), partial: z.boolean() }),
|
|
185
|
+
z.object({ type: z.literal('imageAborted'), sessionId: z.string(), generation: z.number().int().nonnegative(), revision: z.number().int().nonnegative(), reason: z.string(), lastRow: z.number().int().nonnegative().optional(), temporary: z.boolean() }),
|
|
186
|
+
z.object({ type: z.literal('snapshotRequired'), sessionId: z.string(), generation: z.number().int().nonnegative(), revision: z.number().int().nonnegative(), snapshotUrl: z.string() }),
|
|
187
|
+
z.object({ type: z.literal('captureSaved'), sessionId: z.string(), generation: z.number().int().nonnegative(), revision: z.number().int().nonnegative(), artifactId: z.string(), previewUrl: z.string(), saveReason: z.enum(['manual', 'protocolEnd']), complete: z.boolean(), startLine: z.number().int().nonnegative(), endLine: z.number().int().positive() }),
|
|
188
|
+
]);
|
|
189
|
+
export type ImageRxEvent = z.infer<typeof ImageRxEventSchema>;
|
|
190
|
+
|
|
191
|
+
export const ImageArtifactSchema = z.object({
|
|
192
|
+
id: z.string(),
|
|
193
|
+
family: ImageFamilySchema,
|
|
194
|
+
direction: z.enum(['rx', 'tx']),
|
|
195
|
+
operatorId: z.string().optional(),
|
|
196
|
+
codecMode: z.string(),
|
|
197
|
+
pixelFormat: ImagePixelFormatSchema,
|
|
198
|
+
width: z.number().int().positive(),
|
|
199
|
+
height: z.number().int().positive(),
|
|
200
|
+
frequency: z.number().positive(),
|
|
201
|
+
radioMode: z.string().optional(),
|
|
202
|
+
complete: z.boolean(),
|
|
203
|
+
saveReason: z.enum(['manual', 'protocolEnd']).optional(),
|
|
204
|
+
captureStartedAt: z.number().optional(),
|
|
205
|
+
captureEndedAt: z.number().optional(),
|
|
206
|
+
truncated: z.boolean().default(false),
|
|
207
|
+
pinned: z.boolean().default(false),
|
|
208
|
+
qsoId: z.string().optional(),
|
|
209
|
+
contentHash: z.string(),
|
|
210
|
+
createdAt: z.number(),
|
|
211
|
+
imageUrl: z.string(),
|
|
212
|
+
faxCalibration: ImageFaxCalibrationSchema.optional(),
|
|
213
|
+
});
|
|
214
|
+
export type ImageArtifact = z.infer<typeof ImageArtifactSchema>;
|
|
215
|
+
|
|
216
|
+
const ImageHistoryRecordBaseSchema = z.object({
|
|
217
|
+
id: z.string(),
|
|
218
|
+
artifactId: z.string(),
|
|
219
|
+
family: ImageFamilySchema,
|
|
220
|
+
operatorId: z.string().optional(),
|
|
221
|
+
occurredAt: z.number(),
|
|
222
|
+
qsoId: z.string().optional(),
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
export const ImageHistoryRecordSchema = z.discriminatedUnion('direction', [
|
|
226
|
+
ImageHistoryRecordBaseSchema.extend({
|
|
227
|
+
direction: z.literal('rx'),
|
|
228
|
+
saveReason: z.enum(['manual', 'protocolEnd']),
|
|
229
|
+
complete: z.boolean(),
|
|
230
|
+
truncated: z.boolean().default(false),
|
|
231
|
+
}),
|
|
232
|
+
ImageHistoryRecordBaseSchema.extend({
|
|
233
|
+
direction: z.literal('tx'),
|
|
234
|
+
operatorId: z.string().min(1),
|
|
235
|
+
sessionId: z.string().min(1),
|
|
236
|
+
startedAt: z.number(),
|
|
237
|
+
endedAt: z.number().optional(),
|
|
238
|
+
outcome: z.enum(['transmitting', 'completed', 'interrupted']),
|
|
239
|
+
errorCode: z.string().optional(),
|
|
240
|
+
envelope: SstvTxEnvelopeSnapshotSchema.optional(),
|
|
241
|
+
sampleRate: z.number().int().positive().optional(),
|
|
242
|
+
estimatedTotalSamples: z.number().int().nonnegative().optional(),
|
|
243
|
+
}),
|
|
244
|
+
]);
|
|
245
|
+
export type ImageHistoryRecord = z.infer<typeof ImageHistoryRecordSchema>;
|
|
246
|
+
|
|
247
|
+
export const ImageHistoryEntrySchema = z.object({
|
|
248
|
+
record: ImageHistoryRecordSchema,
|
|
249
|
+
artifact: ImageArtifactSchema,
|
|
250
|
+
});
|
|
251
|
+
export type ImageHistoryEntry = z.infer<typeof ImageHistoryEntrySchema>;
|
|
252
|
+
|
|
253
|
+
export const ImageTemplateTextLayerSchema = z.object({
|
|
254
|
+
id: z.string().min(1).max(64),
|
|
255
|
+
text: z.string().max(256),
|
|
256
|
+
x: z.number().min(-2).max(2),
|
|
257
|
+
y: z.number().min(-2).max(2),
|
|
258
|
+
width: z.number().positive().max(4),
|
|
259
|
+
height: z.number().positive().max(4),
|
|
260
|
+
fontSize: z.number().positive().max(1),
|
|
261
|
+
color: z.string().regex(/^#[0-9a-fA-F]{6}$/),
|
|
262
|
+
strokeColor: z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
|
|
263
|
+
strokeWidth: z.number().min(0).max(0.5).default(0.12),
|
|
264
|
+
align: z.enum(['left', 'center', 'right']).default('center'),
|
|
265
|
+
rotation: z.number().min(-180).max(180).default(0),
|
|
266
|
+
});
|
|
267
|
+
export type ImageTemplateTextLayer = z.infer<typeof ImageTemplateTextLayerSchema>;
|
|
268
|
+
|
|
269
|
+
export const ImageTemplateSchema = z.object({
|
|
270
|
+
id: z.string(),
|
|
271
|
+
operatorId: z.string().optional(),
|
|
272
|
+
name: z.string().min(1).max(80),
|
|
273
|
+
builtIn: z.boolean().default(false),
|
|
274
|
+
backgroundArtifactId: z.string().optional(),
|
|
275
|
+
layers: z.array(ImageTemplateTextLayerSchema).max(16),
|
|
276
|
+
createdAt: z.number(),
|
|
277
|
+
updatedAt: z.number(),
|
|
278
|
+
});
|
|
279
|
+
export type ImageTemplate = z.infer<typeof ImageTemplateSchema>;
|
|
280
|
+
|
|
281
|
+
export const ImageComposerBackgroundSchema = z.object({
|
|
282
|
+
operatorId: z.string().min(1),
|
|
283
|
+
width: z.number().int().positive(),
|
|
284
|
+
height: z.number().int().positive(),
|
|
285
|
+
updatedAt: z.number(),
|
|
286
|
+
imageUrl: z.string(),
|
|
287
|
+
});
|
|
288
|
+
export type ImageComposerBackground = z.infer<typeof ImageComposerBackgroundSchema>;
|
|
289
|
+
|
|
290
|
+
export const ImageRxSubscriptionSchema = z.object({ enabled: z.boolean() });
|
|
291
|
+
export const SstvTxStartCommandSchema = z.object({
|
|
292
|
+
requestId: z.string().min(1).max(128),
|
|
293
|
+
operatorId: z.string().min(1),
|
|
294
|
+
artifactId: z.string().min(1),
|
|
295
|
+
mode: z.string().min(1),
|
|
296
|
+
expectedFrequency: z.number().positive(),
|
|
297
|
+
interruptActiveCapture: z.boolean().optional(),
|
|
298
|
+
envelope: SstvTxEnvelopeSelectionSchema.default({ enhancedPreamble: true, stationIdMode: 'fsk' }),
|
|
299
|
+
});
|
|
300
|
+
export type SstvTxStartCommand = z.infer<typeof SstvTxStartCommandSchema>;
|
|
301
|
+
export const SstvTxCancelCommandSchema = z.object({
|
|
302
|
+
requestId: z.string().min(1).max(128),
|
|
303
|
+
operatorId: z.string().min(1),
|
|
304
|
+
sessionId: z.string().min(1),
|
|
305
|
+
expectedRevision: z.number().int().nonnegative(),
|
|
306
|
+
});
|
|
307
|
+
export type SstvTxCancelCommand = z.infer<typeof SstvTxCancelCommandSchema>;
|
|
308
|
+
export const SstvTxCommandResultSchema = z.object({
|
|
309
|
+
requestId: z.string(),
|
|
310
|
+
accepted: z.boolean(),
|
|
311
|
+
sessionId: z.string().optional(),
|
|
312
|
+
errorCode: z.string().optional(),
|
|
313
|
+
});
|
|
314
|
+
export type SstvTxCommandResult = z.infer<typeof SstvTxCommandResultSchema>;
|
|
315
|
+
|
|
316
|
+
export const ImagePaperSaveCommandSchema = z.object({
|
|
317
|
+
requestId: z.string().min(1).max(128),
|
|
318
|
+
operatorId: z.string().min(1),
|
|
319
|
+
expectedRevision: z.number().int().nonnegative(),
|
|
320
|
+
});
|
|
321
|
+
export type ImagePaperSaveCommand = z.infer<typeof ImagePaperSaveCommandSchema>;
|
|
322
|
+
|
|
323
|
+
const FaxCalibrationCommandBaseSchema = z.object({
|
|
324
|
+
requestId: z.string().min(1).max(128),
|
|
325
|
+
operatorId: z.string().min(1),
|
|
326
|
+
sessionId: z.string().min(1),
|
|
327
|
+
boundaryId: z.string().min(1),
|
|
328
|
+
expectedRevision: z.number().int().nonnegative(),
|
|
329
|
+
});
|
|
330
|
+
export const FaxCalibrationSetCommandSchema = FaxCalibrationCommandBaseSchema.extend({
|
|
331
|
+
autoEnabled: z.boolean(),
|
|
332
|
+
phasePixels: z.number().finite(),
|
|
333
|
+
clockPpm: z.number().finite().min(-5000).max(5000),
|
|
334
|
+
});
|
|
335
|
+
export type FaxCalibrationSetCommand = z.infer<typeof FaxCalibrationSetCommandSchema>;
|
|
336
|
+
export const FaxCalibrationResetCommandSchema = FaxCalibrationCommandBaseSchema;
|
|
337
|
+
export type FaxCalibrationResetCommand = z.infer<typeof FaxCalibrationResetCommandSchema>;
|
|
338
|
+
export const FaxCalibrationCommandResultSchema = z.object({
|
|
339
|
+
requestId: z.string(), accepted: z.boolean(),
|
|
340
|
+
calibration: ImageFaxCalibrationSchema.optional(), errorCode: z.string().optional(),
|
|
341
|
+
});
|
|
342
|
+
export type FaxCalibrationCommandResult = z.infer<typeof FaxCalibrationCommandResultSchema>;
|
|
@@ -12,6 +12,7 @@ export const LOGBOOK_OPERATION_ERROR_CODES = [
|
|
|
12
12
|
'LOGBOOK_BACKUP_UNAVAILABLE',
|
|
13
13
|
'LOGBOOK_BACKUP_CHANGED',
|
|
14
14
|
'LOGBOOK_MAINTENANCE',
|
|
15
|
+
'LOGBOOK_REVISION_CONFLICT',
|
|
15
16
|
'LOGBOOK_REVISION_MISMATCH',
|
|
16
17
|
'LOGBOOK_RESTORE_PRECONDITION_FAILED',
|
|
17
18
|
'LOGBOOK_PRECONDITION_REQUIRED',
|
|
@@ -69,6 +69,22 @@ export const MODES = {
|
|
|
69
69
|
transmitTiming: 0,
|
|
70
70
|
encodeAdvance: 0,
|
|
71
71
|
} as ModeDescriptor,
|
|
72
|
+
SSTV: {
|
|
73
|
+
name: 'SSTV',
|
|
74
|
+
slotMs: 0,
|
|
75
|
+
toleranceMs: 0,
|
|
76
|
+
windowTiming: [],
|
|
77
|
+
transmitTiming: 0,
|
|
78
|
+
encodeAdvance: 0,
|
|
79
|
+
} as ModeDescriptor,
|
|
80
|
+
FAX: {
|
|
81
|
+
name: 'FAX',
|
|
82
|
+
slotMs: 0,
|
|
83
|
+
toleranceMs: 0,
|
|
84
|
+
windowTiming: [],
|
|
85
|
+
transmitTiming: 0,
|
|
86
|
+
encodeAdvance: 0,
|
|
87
|
+
} as ModeDescriptor,
|
|
72
88
|
} as const;
|
|
73
89
|
|
|
74
90
|
/**
|
|
@@ -2,6 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { ModeDescriptorSchema } from './mode.schema.js';
|
|
3
3
|
import { sanitizeCallsignInput } from '../utils/callsign.js';
|
|
4
4
|
import { sanitizeGridInput } from '../utils/grid.js';
|
|
5
|
+
import { StrategyRuntimeSnapshotSchema } from './websocket.schema.js';
|
|
5
6
|
|
|
6
7
|
const OperatorCallsignSchema = z
|
|
7
8
|
.string()
|
|
@@ -20,6 +21,7 @@ export const RadioOperatorConfigSchema = z.object({
|
|
|
20
21
|
myCallsign: OperatorCallsignSchema,
|
|
21
22
|
myGrid: OperatorGridSchema.optional(),
|
|
22
23
|
frequency: z.number().min(0).max(1000000000, '频率必须在0-1GHz之间').default(1000), // 音频偏移频率(Hz),默认1000Hz,创建时自动分配不重复值
|
|
24
|
+
maxConcurrentStreams: z.number().int().min(1).max(5).optional(),
|
|
23
25
|
transmitCycles: z.array(z.number().min(0).max(1)).default([0]), // 0=偶数周期,1=奇数周期
|
|
24
26
|
mode: ModeDescriptorSchema.optional(),
|
|
25
27
|
logBookId: z.string().optional(), // 连接的日志本ID,如果未指定则使用默认日志本
|
|
@@ -67,6 +69,7 @@ export const RadioOperatorStatusResponseSchema = z.object({
|
|
|
67
69
|
context: z.object({
|
|
68
70
|
myCall: z.string(),
|
|
69
71
|
myGrid: z.string(),
|
|
72
|
+
targetCalls: z.array(z.string()).optional(),
|
|
70
73
|
targetCall: z.string(),
|
|
71
74
|
targetGrid: z.string().optional(),
|
|
72
75
|
frequency: z.number().optional(),
|
|
@@ -78,25 +81,7 @@ export const RadioOperatorStatusResponseSchema = z.object({
|
|
|
78
81
|
state: z.string(),
|
|
79
82
|
availableSlots: z.array(z.string()),
|
|
80
83
|
}),
|
|
81
|
-
runtime:
|
|
82
|
-
currentState: z.string(),
|
|
83
|
-
slots: z.object({
|
|
84
|
-
TX1: z.string().optional(),
|
|
85
|
-
TX2: z.string().optional(),
|
|
86
|
-
TX3: z.string().optional(),
|
|
87
|
-
TX4: z.string().optional(),
|
|
88
|
-
TX5: z.string().optional(),
|
|
89
|
-
TX6: z.string().optional(),
|
|
90
|
-
}).optional(),
|
|
91
|
-
context: z.object({
|
|
92
|
-
targetCallsign: z.string().optional(),
|
|
93
|
-
targetGrid: z.string().optional(),
|
|
94
|
-
reportSent: z.number().optional(),
|
|
95
|
-
reportReceived: z.number().optional(),
|
|
96
|
-
actualFrequency: z.number().optional(),
|
|
97
|
-
}).optional(),
|
|
98
|
-
availableSlots: z.array(z.string()).optional(),
|
|
99
|
-
}).optional(),
|
|
84
|
+
runtime: StrategyRuntimeSnapshotSchema.optional(),
|
|
100
85
|
slots: z.object({
|
|
101
86
|
TX1: z.string().optional(),
|
|
102
87
|
TX2: z.string().optional(),
|
|
@@ -19,6 +19,11 @@ export type PluginType = z.infer<typeof PluginTypeSchema>;
|
|
|
19
19
|
|
|
20
20
|
export const StrategyFeaturesSchema = z.object({
|
|
21
21
|
targetQueue: z.literal(1).optional(),
|
|
22
|
+
parallelTargetQueue: z.literal(1).optional(),
|
|
23
|
+
queueActivation: z.enum(['immediate', 'operator-toggle']).optional(),
|
|
24
|
+
manualInitiation: z.literal(1).optional(),
|
|
25
|
+
maxConcurrentStreams: z.number().int().min(1).max(5).optional(),
|
|
26
|
+
maxSimultaneousSignals: z.number().int().min(1).max(5).optional(),
|
|
22
27
|
}).optional();
|
|
23
28
|
export type StrategyFeatures = z.infer<typeof StrategyFeaturesSchema>;
|
|
24
29
|
|
|
@@ -52,6 +57,7 @@ export const PluginPermissionSchema = z.enum([
|
|
|
52
57
|
'radio:power',
|
|
53
58
|
'logbook:read',
|
|
54
59
|
'logbook:write',
|
|
60
|
+
'logbook:session',
|
|
55
61
|
'logbook:sync',
|
|
56
62
|
'settings:ft8',
|
|
57
63
|
'settings:decode-windows',
|
|
@@ -299,6 +305,7 @@ export type PluginCapability = z.infer<typeof PluginCapabilitySchema>;
|
|
|
299
305
|
*
|
|
300
306
|
* - `operator`: shown in the expanded operator card's live-panel area (default).
|
|
301
307
|
* - `automation`: shown inside the top-right automation quick-action popover.
|
|
308
|
+
* - `operator-action`: shown beside the built-in logbook action on an operator card.
|
|
302
309
|
* - `main-right`: shown in the optional main layout plugin pane on the far right.
|
|
303
310
|
* - `voice-left-top`: shown above the voice frequency control card.
|
|
304
311
|
* - `voice-right-top`: shown in the tabbed top area of the voice right panel.
|
|
@@ -308,6 +315,7 @@ export type PluginCapability = z.infer<typeof PluginCapabilitySchema>;
|
|
|
308
315
|
export const PluginPanelSlotSchema = z.enum([
|
|
309
316
|
'operator',
|
|
310
317
|
'automation',
|
|
318
|
+
'operator-action',
|
|
311
319
|
'main-right',
|
|
312
320
|
'voice-left-top',
|
|
313
321
|
'voice-right-top',
|
|
@@ -336,12 +344,15 @@ export const PluginPanelWidthSchema = z.enum(['half', 'full']);
|
|
|
336
344
|
export type PluginPanelWidth = z.infer<typeof PluginPanelWidthSchema>;
|
|
337
345
|
|
|
338
346
|
/**
|
|
339
|
-
* How an iframe panel is opened when rendered as
|
|
347
|
+
* How an iframe panel is opened when rendered as an action entry.
|
|
348
|
+
*
|
|
349
|
+
* `page` opens the referenced custom UI in the host's standalone plugin-page
|
|
350
|
+
* route instead of embedding it in the radio workspace.
|
|
340
351
|
*/
|
|
341
|
-
export const PluginPanelOpenModeSchema = z.enum(['popover', 'modal']);
|
|
352
|
+
export const PluginPanelOpenModeSchema = z.enum(['popover', 'modal', 'page']);
|
|
342
353
|
|
|
343
354
|
/**
|
|
344
|
-
* How an iframe panel is opened when rendered as
|
|
355
|
+
* How an iframe panel is opened when rendered as an action entry.
|
|
345
356
|
*/
|
|
346
357
|
export type PluginPanelOpenMode = z.infer<typeof PluginPanelOpenModeSchema>;
|
|
347
358
|
|
|
@@ -382,21 +393,28 @@ export const PluginPanelDescriptorSchema = z.object({
|
|
|
382
393
|
/** Optional controlled UI size hint for toolbar popovers/modals. */
|
|
383
394
|
uiSize: PluginPanelUISizeSchema.optional(),
|
|
384
395
|
}).superRefine((panel, ctx) => {
|
|
385
|
-
if (panel.slot !== 'radio-control-toolbar') {
|
|
396
|
+
if (panel.slot !== 'radio-control-toolbar' && panel.slot !== 'operator-action') {
|
|
386
397
|
return;
|
|
387
398
|
}
|
|
388
399
|
if (panel.component !== 'iframe') {
|
|
389
400
|
ctx.addIssue({
|
|
390
401
|
code: z.ZodIssueCode.custom,
|
|
391
402
|
path: ['component'],
|
|
392
|
-
message:
|
|
403
|
+
message: `${panel.slot} panels must use iframe component`,
|
|
393
404
|
});
|
|
394
405
|
}
|
|
395
406
|
if (!panel.pageId) {
|
|
396
407
|
ctx.addIssue({
|
|
397
408
|
code: z.ZodIssueCode.custom,
|
|
398
409
|
path: ['pageId'],
|
|
399
|
-
message:
|
|
410
|
+
message: `${panel.slot} panels must declare pageId`,
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
if (panel.slot === 'operator-action' && panel.openMode !== 'page') {
|
|
414
|
+
ctx.addIssue({
|
|
415
|
+
code: z.ZodIssueCode.custom,
|
|
416
|
+
path: ['openMode'],
|
|
417
|
+
message: 'operator-action panels must use page openMode',
|
|
400
418
|
});
|
|
401
419
|
}
|
|
402
420
|
});
|
|
@@ -504,6 +522,11 @@ export type PluginStorageConfig = z.infer<typeof PluginStorageConfigSchema>;
|
|
|
504
522
|
|
|
505
523
|
// ===== 插件清单 =====
|
|
506
524
|
|
|
525
|
+
const SemanticVersionSchema = z.string().regex(
|
|
526
|
+
/^v?(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/,
|
|
527
|
+
'must be a semantic version',
|
|
528
|
+
);
|
|
529
|
+
|
|
507
530
|
/**
|
|
508
531
|
* Normalized manifest describing a plugin's static metadata and declarations.
|
|
509
532
|
*
|
|
@@ -514,6 +537,7 @@ export const PluginManifestSchema = z.object({
|
|
|
514
537
|
apiVersion: z.literal(2).optional(),
|
|
515
538
|
name: z.string(),
|
|
516
539
|
version: z.string(),
|
|
540
|
+
minPluginApiVersion: SemanticVersionSchema.optional(),
|
|
517
541
|
type: PluginTypeSchema,
|
|
518
542
|
strategyFeatures: StrategyFeaturesSchema,
|
|
519
543
|
instanceScope: PluginInstanceScopeSchema.optional().default('operator'),
|
|
@@ -647,6 +671,8 @@ export const PluginDistributionSchema = z.enum([
|
|
|
647
671
|
export type PluginDistribution = z.infer<typeof PluginDistributionSchema>;
|
|
648
672
|
|
|
649
673
|
export const PluginRuntimeInfoSchema = z.object({
|
|
674
|
+
hostVersion: z.string(),
|
|
675
|
+
pluginApiVersion: SemanticVersionSchema,
|
|
650
676
|
pluginDir: z.string(),
|
|
651
677
|
pluginDataDir: z.string(),
|
|
652
678
|
dataDir: z.string(),
|
|
@@ -677,7 +703,7 @@ export const PluginMarketScreenshotSchema = z.object({
|
|
|
677
703
|
});
|
|
678
704
|
export type PluginMarketScreenshot = z.infer<typeof PluginMarketScreenshotSchema>;
|
|
679
705
|
|
|
680
|
-
|
|
706
|
+
const PluginMarketCatalogEntryInputSchema = z.object({
|
|
681
707
|
name: z.string(),
|
|
682
708
|
title: z.string(),
|
|
683
709
|
description: z.string(),
|
|
@@ -685,7 +711,9 @@ export const PluginMarketCatalogEntrySchema = z.object({
|
|
|
685
711
|
readmeSourceUrl: z.string().url().optional(),
|
|
686
712
|
locales: PluginLocalesSchema.optional(),
|
|
687
713
|
latestVersion: z.string(),
|
|
688
|
-
|
|
714
|
+
minPluginApiVersion: SemanticVersionSchema.optional(),
|
|
715
|
+
/** Catalog schema v1 compatibility alias; normalized on read. */
|
|
716
|
+
minHostVersion: SemanticVersionSchema.optional(),
|
|
689
717
|
author: z.string().optional(),
|
|
690
718
|
license: z.string().optional(),
|
|
691
719
|
repository: z.string().url().optional(),
|
|
@@ -698,15 +726,93 @@ export const PluginMarketCatalogEntrySchema = z.object({
|
|
|
698
726
|
sha256: z.string().regex(/^[a-f0-9]{64}$/i),
|
|
699
727
|
size: z.number().int().nonnegative(),
|
|
700
728
|
publishedAt: z.string(),
|
|
729
|
+
artifactManifestVersion: z.literal(1).optional(),
|
|
730
|
+
}).superRefine((value, context) => {
|
|
731
|
+
if (!value.minPluginApiVersion && !value.minHostVersion) {
|
|
732
|
+
context.addIssue({
|
|
733
|
+
code: z.ZodIssueCode.custom,
|
|
734
|
+
path: ['minPluginApiVersion'],
|
|
735
|
+
message: 'minPluginApiVersion is required',
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
if (value.minPluginApiVersion && value.minHostVersion
|
|
739
|
+
&& value.minPluginApiVersion !== value.minHostVersion) {
|
|
740
|
+
context.addIssue({
|
|
741
|
+
code: z.ZodIssueCode.custom,
|
|
742
|
+
path: ['minPluginApiVersion'],
|
|
743
|
+
message: 'minPluginApiVersion conflicts with legacy minHostVersion',
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
export const PluginMarketCatalogEntrySchema = PluginMarketCatalogEntryInputSchema.transform((value) => {
|
|
749
|
+
const { minHostVersion: _legacyMinimum, ...entry } = value;
|
|
750
|
+
return {
|
|
751
|
+
...entry,
|
|
752
|
+
minPluginApiVersion: value.minPluginApiVersion ?? value.minHostVersion!,
|
|
753
|
+
};
|
|
701
754
|
});
|
|
702
755
|
export type PluginMarketCatalogEntry = z.infer<typeof PluginMarketCatalogEntrySchema>;
|
|
703
756
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
757
|
+
const PluginMarketCatalogV2EntrySchema = PluginMarketCatalogEntryInputSchema.superRefine(
|
|
758
|
+
(value, context) => {
|
|
759
|
+
if (!value.minPluginApiVersion) {
|
|
760
|
+
context.addIssue({
|
|
761
|
+
code: z.ZodIssueCode.custom,
|
|
762
|
+
path: ['minPluginApiVersion'],
|
|
763
|
+
message: 'catalog schema v2 requires minPluginApiVersion',
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
if (value.minHostVersion) {
|
|
767
|
+
context.addIssue({
|
|
768
|
+
code: z.ZodIssueCode.custom,
|
|
769
|
+
path: ['minHostVersion'],
|
|
770
|
+
message: 'catalog schema v2 does not support legacy minHostVersion',
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
if (value.artifactManifestVersion !== 1) {
|
|
774
|
+
context.addIssue({
|
|
775
|
+
code: z.ZodIssueCode.custom,
|
|
776
|
+
path: ['artifactManifestVersion'],
|
|
777
|
+
message: 'catalog schema v2 requires artifactManifestVersion 1',
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
},
|
|
781
|
+
).transform((value) => {
|
|
782
|
+
const { minHostVersion: _legacyMinimum, ...entry } = value;
|
|
783
|
+
return {
|
|
784
|
+
...entry,
|
|
785
|
+
minPluginApiVersion: value.minPluginApiVersion!,
|
|
786
|
+
};
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
export const PluginArtifactManifestSchema = z.object({
|
|
790
|
+
schemaVersion: z.literal(1),
|
|
791
|
+
name: z.string(),
|
|
792
|
+
version: z.string(),
|
|
793
|
+
minPluginApiVersion: SemanticVersionSchema,
|
|
794
|
+
apiVersion: z.literal(2).optional(),
|
|
795
|
+
type: PluginTypeSchema,
|
|
796
|
+
instanceScope: PluginInstanceScopeSchema.optional().default('operator'),
|
|
797
|
+
permissions: z.array(PluginPermissionSchema).optional().default([]),
|
|
798
|
+
strategyFeatures: StrategyFeaturesSchema,
|
|
709
799
|
});
|
|
800
|
+
export type PluginArtifactManifest = z.infer<typeof PluginArtifactManifestSchema>;
|
|
801
|
+
|
|
802
|
+
export const PluginMarketCatalogSchema = z.discriminatedUnion('schemaVersion', [
|
|
803
|
+
z.object({
|
|
804
|
+
schemaVersion: z.literal(1),
|
|
805
|
+
generatedAt: z.string(),
|
|
806
|
+
channel: PluginMarketChannelSchema,
|
|
807
|
+
plugins: z.array(PluginMarketCatalogEntrySchema),
|
|
808
|
+
}),
|
|
809
|
+
z.object({
|
|
810
|
+
schemaVersion: z.literal(2),
|
|
811
|
+
generatedAt: z.string(),
|
|
812
|
+
channel: PluginMarketChannelSchema,
|
|
813
|
+
plugins: z.array(PluginMarketCatalogV2EntrySchema),
|
|
814
|
+
}),
|
|
815
|
+
]);
|
|
710
816
|
export type PluginMarketCatalog = z.infer<typeof PluginMarketCatalogSchema>;
|
|
711
817
|
|
|
712
818
|
export const PluginMarketCatalogResponseSchema = z.object({
|