@tapflowio/protocol 0.18.0 → 0.19.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 +748 -92
- package/dist/index.d.ts.map +1 -1
- package/dist/validate/assert.d.ts +68 -0
- package/dist/validate/assert.d.ts.map +1 -0
- package/dist/validate/assert.js +2 -0
- package/dist/validate/assert.js.map +1 -0
- package/dist/validate/index.d.ts +563 -0
- package/dist/validate/index.d.ts.map +1 -0
- package/dist/validate/index.js +364 -0
- package/dist/validate/index.js.map +1 -0
- package/package.json +16 -4
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime validation for everything the relay receives — the half of the contract types cannot hold.
|
|
3
|
+
*
|
|
4
|
+
* `../index.ts` is types only, and deliberately so: the dashboard consumes it with `import type`, so it
|
|
5
|
+
* must erase completely. This entry point is where the runtime lives, reached as
|
|
6
|
+
* `@tapflowio/protocol/validate`, and only the relay imports it. `../AGENTS.md` reserved this spot.
|
|
7
|
+
*
|
|
8
|
+
* ## Why this exists at all
|
|
9
|
+
*
|
|
10
|
+
* The outbound direction has been compile-checked since #419 — `sendTo` refuses a message outside its
|
|
11
|
+
* union. Nothing checked the inbound direction, so the relay reached for `msg.sessionId!` and
|
|
12
|
+
* `msg.payload as X` on values that arrived over a network. #550 asked for `RelayMessage` (a flat
|
|
13
|
+
* interface where `type` is the only required member) to become a discriminated union, and doing that
|
|
14
|
+
* with a bare `as` at the door would have been a **downgrade**: the visible cast at
|
|
15
|
+
* `RelayServer.ts:753` would have become an invisible `msg.payload`, with the compiler now vouching
|
|
16
|
+
* for an attacker's JSON. So the union has to be the product of a parse, and this is that parse.
|
|
17
|
+
*
|
|
18
|
+
* ## The rule the two tiers come from
|
|
19
|
+
*
|
|
20
|
+
* **A field that was not validated must not appear in the type.** Anything else reintroduces the lie
|
|
21
|
+
* in a quieter place.
|
|
22
|
+
*
|
|
23
|
+
* - **Validated** — the full schema; parsing yields the interface. Used where the relay reads or acts
|
|
24
|
+
* on the message.
|
|
25
|
+
* - **Envelope** — `type` plus whichever of `sessionId` / `requestId` the interface declares; parsing
|
|
26
|
+
* yields `EnvelopeOf<I>`, so the relay **cannot** read a payload it did not check. Used where the
|
|
27
|
+
* relay only forwards.
|
|
28
|
+
*
|
|
29
|
+
* ## Why the whole agent direction is Envelope except the six it consumes
|
|
30
|
+
*
|
|
31
|
+
* Not laziness, and not a deferral: agent-payload conformance is a property the protocol deliberately
|
|
32
|
+
* does not have. `AgentRegister.platform` is `string` — open, because a third-party platform registers
|
|
33
|
+
* through `AgentRegistry.register()` and the root AGENTS.md's OCP rule says that must work without
|
|
34
|
+
* modifying existing code — while `ChromePayload` is a **closed two-member union**. So a platform this
|
|
35
|
+
* repo promises to support has no valid `session:chrome` variant to send. Rejecting one would cost
|
|
36
|
+
* that platform its bezel and buttons permanently: the message arrives once per boot, a rejection
|
|
37
|
+
* skips `setChromeData` and therefore empties the re-join replay too, and there is no
|
|
38
|
+
* `session:chrome-error` for anyone to be told through.
|
|
39
|
+
*
|
|
40
|
+
* The six the relay consumes (`agent:register`, `agent:resources`, the two screenshot replies and the
|
|
41
|
+
* two ui-tree replies) forward nowhere, so rejecting them breaks no forward path — and their schemas
|
|
42
|
+
* carry a `.default()` for every field the relay currently reads through a `??`, which keeps today's
|
|
43
|
+
* tolerance for an older agent exactly as it is. `UIElement` is safe to validate where `ChromePayload`
|
|
44
|
+
* is not, for a reason worth stating: it is not a per-platform union but the normalized shape every
|
|
45
|
+
* platform maps *into*, so a third-party agent conforms by construction.
|
|
46
|
+
*
|
|
47
|
+
* ## What is not checked here, and where it is
|
|
48
|
+
*
|
|
49
|
+
* Role authorisation. `directionOf` answers which socket may send a type; deciding what to do about a
|
|
50
|
+
* mismatch (the relay closes a browser socket with 1008) stays in `RelayServer`, because it is a
|
|
51
|
+
* policy about a connection rather than a fact about a message.
|
|
52
|
+
*/
|
|
53
|
+
import * as z from 'zod';
|
|
54
|
+
declare const INBOUND: {
|
|
55
|
+
readonly 'stream:register': z.ZodObject<{
|
|
56
|
+
type: z.ZodLiteral<"stream:register">;
|
|
57
|
+
sessionId: z.ZodString;
|
|
58
|
+
}, z.core.$strip>;
|
|
59
|
+
readonly 'session:chrome': z.ZodObject<{
|
|
60
|
+
type: z.ZodLiteral<"session:chrome">;
|
|
61
|
+
sessionId: z.ZodString;
|
|
62
|
+
}, z.core.$strip>;
|
|
63
|
+
readonly 'session:deviceInfo': z.ZodObject<{
|
|
64
|
+
type: z.ZodLiteral<"session:deviceInfo">;
|
|
65
|
+
sessionId: z.ZodString;
|
|
66
|
+
}, z.core.$strip>;
|
|
67
|
+
readonly 'device:ready': z.ZodObject<{
|
|
68
|
+
type: z.ZodLiteral<"device:ready">;
|
|
69
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
70
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
71
|
+
}, z.core.$strip>;
|
|
72
|
+
readonly 'device:booting': z.ZodObject<{
|
|
73
|
+
type: z.ZodLiteral<"device:booting">;
|
|
74
|
+
sessionId: z.ZodString;
|
|
75
|
+
}, z.core.$strip>;
|
|
76
|
+
readonly 'device:shutdown-done': z.ZodObject<{
|
|
77
|
+
type: z.ZodLiteral<"device:shutdown-done">;
|
|
78
|
+
sessionId: z.ZodString;
|
|
79
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
80
|
+
}, z.core.$strip>;
|
|
81
|
+
readonly 'device:boot-error': z.ZodObject<{
|
|
82
|
+
type: z.ZodLiteral<"device:boot-error">;
|
|
83
|
+
sessionId: z.ZodString;
|
|
84
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
85
|
+
}, z.core.$strip>;
|
|
86
|
+
readonly 'app:install-done': z.ZodObject<{
|
|
87
|
+
type: z.ZodLiteral<"app:install-done">;
|
|
88
|
+
sessionId: z.ZodString;
|
|
89
|
+
requestId: z.ZodString;
|
|
90
|
+
}, z.core.$strip>;
|
|
91
|
+
readonly 'app:install-error': z.ZodObject<{
|
|
92
|
+
type: z.ZodLiteral<"app:install-error">;
|
|
93
|
+
sessionId: z.ZodString;
|
|
94
|
+
requestId: z.ZodString;
|
|
95
|
+
}, z.core.$strip>;
|
|
96
|
+
readonly 'app:launch-done': z.ZodObject<{
|
|
97
|
+
type: z.ZodLiteral<"app:launch-done">;
|
|
98
|
+
sessionId: z.ZodString;
|
|
99
|
+
requestId: z.ZodString;
|
|
100
|
+
}, z.core.$strip>;
|
|
101
|
+
readonly 'app:launch-error': z.ZodObject<{
|
|
102
|
+
type: z.ZodLiteral<"app:launch-error">;
|
|
103
|
+
sessionId: z.ZodString;
|
|
104
|
+
requestId: z.ZodString;
|
|
105
|
+
}, z.core.$strip>;
|
|
106
|
+
readonly 'app:clear-state-done': z.ZodObject<{
|
|
107
|
+
type: z.ZodLiteral<"app:clear-state-done">;
|
|
108
|
+
sessionId: z.ZodString;
|
|
109
|
+
requestId: z.ZodString;
|
|
110
|
+
}, z.core.$strip>;
|
|
111
|
+
readonly 'app:clear-state-error': z.ZodObject<{
|
|
112
|
+
type: z.ZodLiteral<"app:clear-state-error">;
|
|
113
|
+
sessionId: z.ZodString;
|
|
114
|
+
requestId: z.ZodString;
|
|
115
|
+
}, z.core.$strip>;
|
|
116
|
+
readonly 'open-url:done': z.ZodObject<{
|
|
117
|
+
type: z.ZodLiteral<"open-url:done">;
|
|
118
|
+
sessionId: z.ZodString;
|
|
119
|
+
requestId: z.ZodString;
|
|
120
|
+
}, z.core.$strip>;
|
|
121
|
+
readonly 'open-url:error': z.ZodObject<{
|
|
122
|
+
type: z.ZodLiteral<"open-url:error">;
|
|
123
|
+
sessionId: z.ZodString;
|
|
124
|
+
requestId: z.ZodString;
|
|
125
|
+
}, z.core.$strip>;
|
|
126
|
+
readonly 'input:done': z.ZodObject<{
|
|
127
|
+
type: z.ZodLiteral<"input:done">;
|
|
128
|
+
sessionId: z.ZodString;
|
|
129
|
+
requestId: z.ZodString;
|
|
130
|
+
}, z.core.$strip>;
|
|
131
|
+
readonly 'input:error': z.ZodObject<{
|
|
132
|
+
type: z.ZodLiteral<"input:error">;
|
|
133
|
+
sessionId: z.ZodString;
|
|
134
|
+
requestId: z.ZodString;
|
|
135
|
+
}, z.core.$strip>;
|
|
136
|
+
readonly 'input:type-done': z.ZodObject<{
|
|
137
|
+
type: z.ZodLiteral<"input:type-done">;
|
|
138
|
+
sessionId: z.ZodString;
|
|
139
|
+
requestId: z.ZodString;
|
|
140
|
+
}, z.core.$strip>;
|
|
141
|
+
readonly 'input:type-error': z.ZodObject<{
|
|
142
|
+
type: z.ZodLiteral<"input:type-error">;
|
|
143
|
+
sessionId: z.ZodString;
|
|
144
|
+
requestId: z.ZodString;
|
|
145
|
+
}, z.core.$strip>;
|
|
146
|
+
readonly 'keyboard:toggled': z.ZodObject<{
|
|
147
|
+
type: z.ZodLiteral<"keyboard:toggled">;
|
|
148
|
+
sessionId: z.ZodString;
|
|
149
|
+
}, z.core.$strip>;
|
|
150
|
+
readonly 'clipboard:data': z.ZodObject<{
|
|
151
|
+
type: z.ZodLiteral<"clipboard:data">;
|
|
152
|
+
sessionId: z.ZodString;
|
|
153
|
+
requestId: z.ZodString;
|
|
154
|
+
}, z.core.$strip>;
|
|
155
|
+
readonly 'clipboard:write-done': z.ZodObject<{
|
|
156
|
+
type: z.ZodLiteral<"clipboard:write-done">;
|
|
157
|
+
sessionId: z.ZodString;
|
|
158
|
+
requestId: z.ZodString;
|
|
159
|
+
}, z.core.$strip>;
|
|
160
|
+
readonly 'clipboard:error': z.ZodObject<{
|
|
161
|
+
type: z.ZodLiteral<"clipboard:error">;
|
|
162
|
+
sessionId: z.ZodString;
|
|
163
|
+
requestId: z.ZodString;
|
|
164
|
+
}, z.core.$strip>;
|
|
165
|
+
readonly 'agent:register': z.ZodObject<{
|
|
166
|
+
type: z.ZodLiteral<"agent:register">;
|
|
167
|
+
platform: z.ZodDefault<z.ZodString>;
|
|
168
|
+
capabilities: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
169
|
+
agentId: z.ZodOptional<z.ZodString>;
|
|
170
|
+
agentName: z.ZodDefault<z.ZodString>;
|
|
171
|
+
devices: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
172
|
+
id: z.ZodString;
|
|
173
|
+
name: z.ZodString;
|
|
174
|
+
platform: z.ZodString;
|
|
175
|
+
status: z.ZodString;
|
|
176
|
+
osVersion: z.ZodOptional<z.ZodString>;
|
|
177
|
+
}, z.core.$strip>>>;
|
|
178
|
+
}, z.core.$strip>;
|
|
179
|
+
readonly 'agent:resources': z.ZodObject<{
|
|
180
|
+
type: z.ZodLiteral<"agent:resources">;
|
|
181
|
+
resources: z.ZodObject<{
|
|
182
|
+
cpuPercent: z.ZodNumber;
|
|
183
|
+
memUsedMB: z.ZodNumber;
|
|
184
|
+
memTotalMB: z.ZodNumber;
|
|
185
|
+
slotsAvailable: z.ZodNumber;
|
|
186
|
+
slotsTotal: z.ZodNumber;
|
|
187
|
+
reportedAt: z.ZodNumber;
|
|
188
|
+
}, z.core.$strip>;
|
|
189
|
+
}, z.core.$strip>;
|
|
190
|
+
readonly 'screenshot:done': z.ZodObject<{
|
|
191
|
+
type: z.ZodLiteral<"screenshot:done">;
|
|
192
|
+
sessionId: z.ZodString;
|
|
193
|
+
requestId: z.ZodString;
|
|
194
|
+
format: z.ZodDefault<z.ZodEnum<{
|
|
195
|
+
png: "png";
|
|
196
|
+
jpeg: "jpeg";
|
|
197
|
+
}>>;
|
|
198
|
+
data: z.ZodDefault<z.ZodString>;
|
|
199
|
+
}, z.core.$strip>;
|
|
200
|
+
readonly 'screenshot:error': z.ZodObject<{
|
|
201
|
+
type: z.ZodLiteral<"screenshot:error">;
|
|
202
|
+
sessionId: z.ZodString;
|
|
203
|
+
requestId: z.ZodString;
|
|
204
|
+
message: z.ZodDefault<z.ZodString>;
|
|
205
|
+
}, z.core.$strip>;
|
|
206
|
+
readonly 'ui:tree:response': z.ZodObject<{
|
|
207
|
+
type: z.ZodLiteral<"ui:tree:response">;
|
|
208
|
+
sessionId: z.ZodString;
|
|
209
|
+
requestId: z.ZodString;
|
|
210
|
+
elements: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
211
|
+
role: z.ZodEnum<{
|
|
212
|
+
button: "button";
|
|
213
|
+
text: "text";
|
|
214
|
+
input: "input";
|
|
215
|
+
image: "image";
|
|
216
|
+
checkbox: "checkbox";
|
|
217
|
+
switch: "switch";
|
|
218
|
+
slider: "slider";
|
|
219
|
+
list: "list";
|
|
220
|
+
cell: "cell";
|
|
221
|
+
tab: "tab";
|
|
222
|
+
other: "other";
|
|
223
|
+
}>;
|
|
224
|
+
label: z.ZodString;
|
|
225
|
+
identifier: z.ZodOptional<z.ZodString>;
|
|
226
|
+
frame: z.ZodObject<{
|
|
227
|
+
x: z.ZodNumber;
|
|
228
|
+
y: z.ZodNumber;
|
|
229
|
+
width: z.ZodNumber;
|
|
230
|
+
height: z.ZodNumber;
|
|
231
|
+
}, z.core.$strip>;
|
|
232
|
+
enabled: z.ZodBoolean;
|
|
233
|
+
rawRole: z.ZodOptional<z.ZodString>;
|
|
234
|
+
}, z.core.$strip>>>;
|
|
235
|
+
}, z.core.$strip>;
|
|
236
|
+
readonly 'ui:tree:error': z.ZodObject<{
|
|
237
|
+
type: z.ZodLiteral<"ui:tree:error">;
|
|
238
|
+
sessionId: z.ZodString;
|
|
239
|
+
requestId: z.ZodString;
|
|
240
|
+
message: z.ZodDefault<z.ZodString>;
|
|
241
|
+
}, z.core.$strip>;
|
|
242
|
+
readonly 'agents:list': z.ZodObject<{
|
|
243
|
+
type: z.ZodLiteral<"agents:list">;
|
|
244
|
+
}, z.core.$strip>;
|
|
245
|
+
readonly 'session:start': z.ZodObject<{
|
|
246
|
+
type: z.ZodLiteral<"session:start">;
|
|
247
|
+
sessionId: z.ZodString;
|
|
248
|
+
}, z.core.$strip>;
|
|
249
|
+
readonly 'session:end': z.ZodObject<{
|
|
250
|
+
type: z.ZodLiteral<"session:end">;
|
|
251
|
+
sessionId: z.ZodString;
|
|
252
|
+
}, z.core.$strip>;
|
|
253
|
+
readonly 'session:leave': z.ZodObject<{
|
|
254
|
+
type: z.ZodLiteral<"session:leave">;
|
|
255
|
+
sessionId: z.ZodString;
|
|
256
|
+
}, z.core.$strip>;
|
|
257
|
+
readonly 'device:boot': z.ZodObject<{
|
|
258
|
+
type: z.ZodLiteral<"device:boot">;
|
|
259
|
+
sessionId: z.ZodString;
|
|
260
|
+
requestId: z.ZodString;
|
|
261
|
+
payload: z.ZodObject<{
|
|
262
|
+
deviceId: z.ZodString;
|
|
263
|
+
resetMode: z.ZodOptional<z.ZodEnum<{
|
|
264
|
+
"app-only": "app-only";
|
|
265
|
+
"full-erase": "full-erase";
|
|
266
|
+
}>>;
|
|
267
|
+
acceptH264: z.ZodOptional<z.ZodBoolean>;
|
|
268
|
+
secureContext: z.ZodOptional<z.ZodBoolean>;
|
|
269
|
+
}, z.core.$strip>;
|
|
270
|
+
}, z.core.$strip>;
|
|
271
|
+
readonly 'device:shutdown': z.ZodObject<{
|
|
272
|
+
type: z.ZodLiteral<"device:shutdown">;
|
|
273
|
+
sessionId: z.ZodString;
|
|
274
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
275
|
+
payload: z.ZodObject<{
|
|
276
|
+
deviceId: z.ZodString;
|
|
277
|
+
}, z.core.$strip>;
|
|
278
|
+
}, z.core.$strip>;
|
|
279
|
+
readonly 'app:install': z.ZodObject<{
|
|
280
|
+
type: z.ZodLiteral<"app:install">;
|
|
281
|
+
sessionId: z.ZodString;
|
|
282
|
+
requestId: z.ZodString;
|
|
283
|
+
buildId: z.ZodNumber;
|
|
284
|
+
}, z.core.$strip>;
|
|
285
|
+
readonly 'app:launch': z.ZodObject<{
|
|
286
|
+
type: z.ZodLiteral<"app:launch">;
|
|
287
|
+
sessionId: z.ZodString;
|
|
288
|
+
requestId: z.ZodString;
|
|
289
|
+
buildId: z.ZodNumber;
|
|
290
|
+
}, z.core.$strip>;
|
|
291
|
+
readonly 'app:clear-state': z.ZodObject<{
|
|
292
|
+
type: z.ZodLiteral<"app:clear-state">;
|
|
293
|
+
sessionId: z.ZodString;
|
|
294
|
+
requestId: z.ZodString;
|
|
295
|
+
payload: z.ZodObject<{
|
|
296
|
+
bundleId: z.ZodString;
|
|
297
|
+
}, z.core.$strip>;
|
|
298
|
+
}, z.core.$strip>;
|
|
299
|
+
readonly 'open-url': z.ZodObject<{
|
|
300
|
+
type: z.ZodLiteral<"open-url">;
|
|
301
|
+
sessionId: z.ZodString;
|
|
302
|
+
requestId: z.ZodString;
|
|
303
|
+
payload: z.ZodObject<{
|
|
304
|
+
url: z.ZodString;
|
|
305
|
+
}, z.core.$strip>;
|
|
306
|
+
}, z.core.$strip>;
|
|
307
|
+
readonly 'input:touch:start': z.ZodObject<{
|
|
308
|
+
type: z.ZodLiteral<"input:touch:start">;
|
|
309
|
+
sessionId: z.ZodString;
|
|
310
|
+
payload: z.ZodObject<{
|
|
311
|
+
x: z.ZodNumber;
|
|
312
|
+
y: z.ZodNumber;
|
|
313
|
+
}, z.core.$strip>;
|
|
314
|
+
}, z.core.$strip>;
|
|
315
|
+
readonly 'input:touch:move': z.ZodObject<{
|
|
316
|
+
type: z.ZodLiteral<"input:touch:move">;
|
|
317
|
+
sessionId: z.ZodString;
|
|
318
|
+
payload: z.ZodObject<{
|
|
319
|
+
x: z.ZodNumber;
|
|
320
|
+
y: z.ZodNumber;
|
|
321
|
+
}, z.core.$strip>;
|
|
322
|
+
}, z.core.$strip>;
|
|
323
|
+
readonly 'input:touch:end': z.ZodObject<{
|
|
324
|
+
type: z.ZodLiteral<"input:touch:end">;
|
|
325
|
+
sessionId: z.ZodString;
|
|
326
|
+
requestId: z.ZodString;
|
|
327
|
+
payload: z.ZodOptional<z.ZodObject<{
|
|
328
|
+
x: z.ZodNumber;
|
|
329
|
+
y: z.ZodNumber;
|
|
330
|
+
}, z.core.$strip>>;
|
|
331
|
+
}, z.core.$strip>;
|
|
332
|
+
readonly 'input:pinch:start': z.ZodObject<{
|
|
333
|
+
type: z.ZodLiteral<"input:pinch:start">;
|
|
334
|
+
sessionId: z.ZodString;
|
|
335
|
+
payload: z.ZodObject<{
|
|
336
|
+
f0: z.ZodObject<{
|
|
337
|
+
x: z.ZodNumber;
|
|
338
|
+
y: z.ZodNumber;
|
|
339
|
+
}, z.core.$strip>;
|
|
340
|
+
f1: z.ZodObject<{
|
|
341
|
+
x: z.ZodNumber;
|
|
342
|
+
y: z.ZodNumber;
|
|
343
|
+
}, z.core.$strip>;
|
|
344
|
+
}, z.core.$strip>;
|
|
345
|
+
}, z.core.$strip>;
|
|
346
|
+
readonly 'input:pinch:move': z.ZodObject<{
|
|
347
|
+
type: z.ZodLiteral<"input:pinch:move">;
|
|
348
|
+
sessionId: z.ZodString;
|
|
349
|
+
payload: z.ZodObject<{
|
|
350
|
+
f0: z.ZodObject<{
|
|
351
|
+
x: z.ZodNumber;
|
|
352
|
+
y: z.ZodNumber;
|
|
353
|
+
}, z.core.$strip>;
|
|
354
|
+
f1: z.ZodObject<{
|
|
355
|
+
x: z.ZodNumber;
|
|
356
|
+
y: z.ZodNumber;
|
|
357
|
+
}, z.core.$strip>;
|
|
358
|
+
}, z.core.$strip>;
|
|
359
|
+
}, z.core.$strip>;
|
|
360
|
+
readonly 'input:pinch:end': z.ZodObject<{
|
|
361
|
+
type: z.ZodLiteral<"input:pinch:end">;
|
|
362
|
+
sessionId: z.ZodString;
|
|
363
|
+
requestId: z.ZodString;
|
|
364
|
+
}, z.core.$strip>;
|
|
365
|
+
readonly 'input:key': z.ZodObject<{
|
|
366
|
+
type: z.ZodLiteral<"input:key">;
|
|
367
|
+
sessionId: z.ZodString;
|
|
368
|
+
requestId: z.ZodString;
|
|
369
|
+
payload: z.ZodObject<{
|
|
370
|
+
code: z.ZodString;
|
|
371
|
+
modifiers: z.ZodOptional<z.ZodNumber>;
|
|
372
|
+
}, z.core.$strip>;
|
|
373
|
+
}, z.core.$strip>;
|
|
374
|
+
readonly 'input:type': z.ZodObject<{
|
|
375
|
+
type: z.ZodLiteral<"input:type">;
|
|
376
|
+
sessionId: z.ZodString;
|
|
377
|
+
requestId: z.ZodString;
|
|
378
|
+
payload: z.ZodObject<{
|
|
379
|
+
text: z.ZodString;
|
|
380
|
+
}, z.core.$strip>;
|
|
381
|
+
}, z.core.$strip>;
|
|
382
|
+
readonly 'input:button': z.ZodObject<{
|
|
383
|
+
type: z.ZodLiteral<"input:button">;
|
|
384
|
+
sessionId: z.ZodString;
|
|
385
|
+
requestId: z.ZodString;
|
|
386
|
+
payload: z.ZodObject<{
|
|
387
|
+
name: z.ZodString;
|
|
388
|
+
phase: z.ZodOptional<z.ZodEnum<{
|
|
389
|
+
down: "down";
|
|
390
|
+
up: "up";
|
|
391
|
+
}>>;
|
|
392
|
+
}, z.core.$strip>;
|
|
393
|
+
}, z.core.$strip>;
|
|
394
|
+
readonly 'input:rotate': z.ZodObject<{
|
|
395
|
+
type: z.ZodLiteral<"input:rotate">;
|
|
396
|
+
sessionId: z.ZodString;
|
|
397
|
+
}, z.core.$strip>;
|
|
398
|
+
readonly 'input:keyboard:toggle': z.ZodObject<{
|
|
399
|
+
type: z.ZodLiteral<"input:keyboard:toggle">;
|
|
400
|
+
sessionId: z.ZodString;
|
|
401
|
+
}, z.core.$strip>;
|
|
402
|
+
readonly 'clipboard:read': z.ZodObject<{
|
|
403
|
+
type: z.ZodLiteral<"clipboard:read">;
|
|
404
|
+
sessionId: z.ZodString;
|
|
405
|
+
requestId: z.ZodString;
|
|
406
|
+
payload: z.ZodOptional<z.ZodObject<{
|
|
407
|
+
press: z.ZodOptional<z.ZodEnum<{
|
|
408
|
+
copy: "copy";
|
|
409
|
+
cut: "cut";
|
|
410
|
+
}>>;
|
|
411
|
+
}, z.core.$strip>>;
|
|
412
|
+
}, z.core.$strip>;
|
|
413
|
+
readonly 'clipboard:write': z.ZodObject<{
|
|
414
|
+
type: z.ZodLiteral<"clipboard:write">;
|
|
415
|
+
sessionId: z.ZodString;
|
|
416
|
+
requestId: z.ZodString;
|
|
417
|
+
payload: z.ZodObject<{
|
|
418
|
+
text: z.ZodString;
|
|
419
|
+
pasteAfter: z.ZodOptional<z.ZodBoolean>;
|
|
420
|
+
}, z.core.$strip>;
|
|
421
|
+
}, z.core.$strip>;
|
|
422
|
+
};
|
|
423
|
+
declare const ANSWERABLE: {
|
|
424
|
+
readonly 'device:boot': z.ZodObject<{
|
|
425
|
+
type: z.ZodLiteral<"device:boot">;
|
|
426
|
+
sessionId: z.ZodString;
|
|
427
|
+
requestId: z.ZodString;
|
|
428
|
+
}, z.core.$strip>;
|
|
429
|
+
readonly 'app:install': z.ZodObject<{
|
|
430
|
+
type: z.ZodLiteral<"app:install">;
|
|
431
|
+
sessionId: z.ZodString;
|
|
432
|
+
requestId: z.ZodString;
|
|
433
|
+
}, z.core.$strip>;
|
|
434
|
+
readonly 'app:launch': z.ZodObject<{
|
|
435
|
+
type: z.ZodLiteral<"app:launch">;
|
|
436
|
+
sessionId: z.ZodString;
|
|
437
|
+
requestId: z.ZodString;
|
|
438
|
+
}, z.core.$strip>;
|
|
439
|
+
readonly 'app:clear-state': z.ZodObject<{
|
|
440
|
+
type: z.ZodLiteral<"app:clear-state">;
|
|
441
|
+
sessionId: z.ZodString;
|
|
442
|
+
requestId: z.ZodString;
|
|
443
|
+
}, z.core.$strip>;
|
|
444
|
+
readonly 'open-url': z.ZodObject<{
|
|
445
|
+
type: z.ZodLiteral<"open-url">;
|
|
446
|
+
sessionId: z.ZodString;
|
|
447
|
+
requestId: z.ZodString;
|
|
448
|
+
}, z.core.$strip>;
|
|
449
|
+
readonly 'input:touch:end': z.ZodObject<{
|
|
450
|
+
type: z.ZodLiteral<"input:touch:end">;
|
|
451
|
+
sessionId: z.ZodString;
|
|
452
|
+
requestId: z.ZodString;
|
|
453
|
+
}, z.core.$strip>;
|
|
454
|
+
readonly 'input:pinch:end': z.ZodObject<{
|
|
455
|
+
type: z.ZodLiteral<"input:pinch:end">;
|
|
456
|
+
sessionId: z.ZodString;
|
|
457
|
+
requestId: z.ZodString;
|
|
458
|
+
}, z.core.$strip>;
|
|
459
|
+
readonly 'input:key': z.ZodObject<{
|
|
460
|
+
type: z.ZodLiteral<"input:key">;
|
|
461
|
+
sessionId: z.ZodString;
|
|
462
|
+
requestId: z.ZodString;
|
|
463
|
+
}, z.core.$strip>;
|
|
464
|
+
readonly 'input:button': z.ZodObject<{
|
|
465
|
+
type: z.ZodLiteral<"input:button">;
|
|
466
|
+
sessionId: z.ZodString;
|
|
467
|
+
requestId: z.ZodString;
|
|
468
|
+
}, z.core.$strip>;
|
|
469
|
+
readonly 'input:type': z.ZodObject<{
|
|
470
|
+
type: z.ZodLiteral<"input:type">;
|
|
471
|
+
sessionId: z.ZodString;
|
|
472
|
+
requestId: z.ZodString;
|
|
473
|
+
}, z.core.$strip>;
|
|
474
|
+
readonly 'clipboard:read': z.ZodObject<{
|
|
475
|
+
type: z.ZodLiteral<"clipboard:read">;
|
|
476
|
+
sessionId: z.ZodString;
|
|
477
|
+
requestId: z.ZodString;
|
|
478
|
+
}, z.core.$strip>;
|
|
479
|
+
readonly 'clipboard:write': z.ZodObject<{
|
|
480
|
+
type: z.ZodLiteral<"clipboard:write">;
|
|
481
|
+
sessionId: z.ZodString;
|
|
482
|
+
requestId: z.ZodString;
|
|
483
|
+
}, z.core.$strip>;
|
|
484
|
+
};
|
|
485
|
+
export type AnswerableType = keyof typeof ANSWERABLE;
|
|
486
|
+
/**
|
|
487
|
+
* The parse product, derived from the map — **not** a union of the protocol's interfaces.
|
|
488
|
+
*
|
|
489
|
+
* An earlier draft returned `BrowserToRelay | AgentToRelay | AgentToBrowser | StreamToRelay`, which
|
|
490
|
+
* violates this file's own opening rule with its return type: narrowing that by
|
|
491
|
+
* `msg.type === 'session:chrome'` hands back `payload: ChromePayload`, fully typed, with nothing
|
|
492
|
+
* having checked it — worse than the `as` it replaced, because a cast can at least be grepped.
|
|
493
|
+
* Deriving from `INBOUND` means an Envelope member arrives as `{ type, sessionId }` and reading
|
|
494
|
+
* `msg.payload` off it is a compile error, which is the claim the tiers make.
|
|
495
|
+
*/
|
|
496
|
+
export type ParsedInbound = {
|
|
497
|
+
[K in keyof typeof INBOUND]: z.output<(typeof INBOUND)[K]>;
|
|
498
|
+
}[keyof typeof INBOUND];
|
|
499
|
+
export type InboundType = keyof typeof INBOUND;
|
|
500
|
+
export type InboundDirection = 'browser' | 'agent' | 'stream';
|
|
501
|
+
export type ParseFailure = {
|
|
502
|
+
ok: false;
|
|
503
|
+
reason: 'not-an-object';
|
|
504
|
+
} | {
|
|
505
|
+
ok: false;
|
|
506
|
+
reason: 'unknown-type';
|
|
507
|
+
type: string;
|
|
508
|
+
} | {
|
|
509
|
+
ok: false;
|
|
510
|
+
reason: 'bad-shape';
|
|
511
|
+
type: InboundType;
|
|
512
|
+
detail: string;
|
|
513
|
+
}
|
|
514
|
+
/** The payload is wrong but the envelope is not, so the caller can be told. */
|
|
515
|
+
| {
|
|
516
|
+
ok: false;
|
|
517
|
+
reason: 'bad-payload';
|
|
518
|
+
type: AnswerableType;
|
|
519
|
+
sessionId: string;
|
|
520
|
+
requestId: string;
|
|
521
|
+
detail: string;
|
|
522
|
+
};
|
|
523
|
+
export type ParseResult = {
|
|
524
|
+
ok: true;
|
|
525
|
+
msg: ParsedInbound;
|
|
526
|
+
/** The frame as it arrived.
|
|
527
|
+
*
|
|
528
|
+
* Forwarding differs by direction and this is why both are available. An **agent**-origin
|
|
529
|
+
* message is forwarded as this, so a field a newer agent added survives a relay that does not
|
|
530
|
+
* know it — `z.object` strips, and stripping here would break upward compatibility in the one
|
|
531
|
+
* direction where the sender is the more recently updated side. A **browser**-origin message is
|
|
532
|
+
* forwarded as `msg` instead, so a key an attacker appended does not survive.
|
|
533
|
+
*
|
|
534
|
+
* It is also where the two Envelope payloads the relay stores come from, and it should stay
|
|
535
|
+
* visibly separate for that reason: a value read off `raw` is a value the parser did not
|
|
536
|
+
* vouch for. */
|
|
537
|
+
raw: Readonly<Record<string, unknown>>;
|
|
538
|
+
} | ParseFailure;
|
|
539
|
+
/**
|
|
540
|
+
* Which socket role is allowed to send this type.
|
|
541
|
+
*
|
|
542
|
+
* This replaces `AGENT_MSG_TYPE_LIST` — 29 literals hand-copied into `RelayServer` and held by two
|
|
543
|
+
* type assertions. It is derived from the map above, which the assertions at the bottom of this file
|
|
544
|
+
* tie back to the protocol's own direction unions, so the copy is gone rather than moved.
|
|
545
|
+
*
|
|
546
|
+
* A runtime set cannot come out of a union directly (types erase), which is why it comes out of the
|
|
547
|
+
* schema map's keys. That makes the relay's role gate depend on this map existing — a real coupling,
|
|
548
|
+
* and the reason the coverage assertions below are not optional.
|
|
549
|
+
*/
|
|
550
|
+
export declare function directionOf(type: InboundType): InboundDirection;
|
|
551
|
+
/**
|
|
552
|
+
* Parse a frame the relay received.
|
|
553
|
+
*
|
|
554
|
+
* **Takes no role.** A first design did, and it could not be called: `classifyConnection` returns
|
|
555
|
+
* `role: 'first-message'` for every local connection and every remote agent-scoped PAT, so the role is
|
|
556
|
+
* assigned from the first message's own `type`. `agent:register` is the message that *creates* the
|
|
557
|
+
* role, so selecting a schema by role to validate it is circular — and defaulting the unknown role to
|
|
558
|
+
* `'browser'`, which is what the relay does for a socket that skips the handshake, would have closed
|
|
559
|
+
* every agent's socket on its opening frame. The order is parse, then role, then gate.
|
|
560
|
+
*/
|
|
561
|
+
export declare function parseInbound(raw: unknown): ParseResult;
|
|
562
|
+
export {};
|
|
563
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/validate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAiPxB,QAAA,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAuE,CAAA;AAkBpF,QAAA,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAaN,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,UAAU,CAAA;AAIpD;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,GAAG;KAAG,CAAC,IAAI,MAAM,OAAO,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC,MAAM,OAAO,OAAO,CAAC,CAAA;AAEhH,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,OAAO,CAAA;AAC9C,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAA;AAE7D,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACvE,+EAA+E;GAC7E;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpH,MAAM,MAAM,WAAW,GACnB;IACE,EAAE,EAAE,IAAI,CAAA;IACR,GAAG,EAAE,aAAa,CAAA;IAClB;;;;;;;;;;qBAUiB;IACjB,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CACvC,GACD,YAAY,CAAA;AAQhB;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,gBAAgB,CAI/D;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,WAAW,CAgCtD"}
|