@tapflowio/protocol 0.17.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.
@@ -0,0 +1,364 @@
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
+ // ── field helpers ────────────────────────────────────────────────────────────
55
+ //
56
+ // `.min(1)`, never a bare `z.string()`, on both correlation fields. The predicates this replaces
57
+ // (`isAddressed` / `isCorrelated`) rejected the empty string as well as the absent one, and dropping
58
+ // that half would be a silent regression: a `device:boot` carrying `requestId: ''` would pass the door
59
+ // and the relay would answer `device:boot-error` with `requestId: ''` — a frame whose required
60
+ // correlator is present-but-empty, which every correlating consumer discards. `.min(1)` does not
61
+ // change what `z.output` infers (`min(minLength): this` — zod 4.4.3 `v4/classic/schemas.d.ts:95`), so
62
+ // it costs the tier assertions nothing.
63
+ const sessionId = z.string().min(1);
64
+ const requestId = z.string().min(1);
65
+ const point = z.object({ x: z.number(), y: z.number() });
66
+ // ── envelope-tier builders ───────────────────────────────────────────────────
67
+ //
68
+ // Four shapes cover all 22 forward-only messages. Getting one wrong is a compile error at its
69
+ // assertion below rather than something that shows up as a dropped frame in production.
70
+ /** `{ type, sessionId }` — no correlator on the interface. */
71
+ const env = (type) => z.object({ type: z.literal(type), sessionId });
72
+ /** `{ type, sessionId, requestId }`. */
73
+ const envC = (type) => z.object({ type: z.literal(type), sessionId, requestId });
74
+ /** `{ type, sessionId, requestId? }` — the relay originates some of these itself, so the agent's copy
75
+ * is not always a reply. */
76
+ const envCo = (type) => z.object({ type: z.literal(type), sessionId, requestId: requestId.optional() });
77
+ // ── browser → relay ──────────────────────────────────────────────────────────
78
+ //
79
+ // Fully validated, and the only direction whose parse product is what gets forwarded. This is the
80
+ // attacker-controllable side: a viewer can send arbitrary frames from devtools. `z.object` strips
81
+ // unknown keys rather than rejecting them, so forwarding the product — not the original — is what
82
+ // makes a key an attacker appended disappear before any agent sees it. Nothing in the repo loses a
83
+ // field to that: the dashboard, `mcp-server` and `flow-runner` all send through a
84
+ // `send(msg: BrowserToRelay)` signature, so their frames are already compile-checked against exactly
85
+ // these shapes.
86
+ const BROWSER_INBOUND = {
87
+ 'agents:list': z.object({ type: z.literal('agents:list') }),
88
+ 'session:start': z.object({ type: z.literal('session:start'), sessionId }),
89
+ 'session:end': z.object({ type: z.literal('session:end'), sessionId }),
90
+ 'session:leave': z.object({ type: z.literal('session:leave'), sessionId }),
91
+ 'device:boot': z.object({
92
+ type: z.literal('device:boot'),
93
+ sessionId,
94
+ requestId,
95
+ payload: z.object({
96
+ deviceId: z.string(),
97
+ resetMode: z.enum(['app-only', 'full-erase']).optional(),
98
+ acceptH264: z.boolean().optional(),
99
+ secureContext: z.boolean().optional(),
100
+ }),
101
+ }),
102
+ 'device:shutdown': z.object({
103
+ type: z.literal('device:shutdown'),
104
+ sessionId,
105
+ requestId: requestId.optional(),
106
+ payload: z.object({ deviceId: z.string() }),
107
+ }),
108
+ // Strict, because `ANSWERABLE` below answers a bad one rather than dropping it. A draft carried it
109
+ // through as `NaN` so the handler's `Number.isInteger` could keep replying `Build not found` — which
110
+ // worked, and left this message as the single special case in a class the door now handles uniformly.
111
+ // It was also the wrong diagnosis: nothing was looked up, so "not found" describes a query that never
112
+ // ran.
113
+ 'app:install': z.object({ type: z.literal('app:install'), sessionId, requestId, buildId: z.number().int() }),
114
+ 'app:launch': z.object({ type: z.literal('app:launch'), sessionId, requestId, buildId: z.number().int() }),
115
+ 'app:clear-state': z.object({
116
+ type: z.literal('app:clear-state'), sessionId, requestId,
117
+ payload: z.object({ bundleId: z.string() }),
118
+ }),
119
+ 'open-url': z.object({
120
+ type: z.literal('open-url'), sessionId, requestId, payload: z.object({ url: z.string() }),
121
+ }),
122
+ 'input:touch:start': z.object({ type: z.literal('input:touch:start'), sessionId, payload: point }),
123
+ 'input:touch:move': z.object({ type: z.literal('input:touch:move'), sessionId, payload: point }),
124
+ // `payload` optional because that is what the wire carries — the dashboard omits it and the agents
125
+ // never read it. See the note on `InputTouchEnd`.
126
+ 'input:touch:end': z.object({
127
+ type: z.literal('input:touch:end'), sessionId, requestId, payload: point.optional(),
128
+ }),
129
+ 'input:pinch:start': z.object({
130
+ type: z.literal('input:pinch:start'), sessionId, payload: z.object({ f0: point, f1: point }),
131
+ }),
132
+ 'input:pinch:move': z.object({
133
+ type: z.literal('input:pinch:move'), sessionId, payload: z.object({ f0: point, f1: point }),
134
+ }),
135
+ 'input:pinch:end': z.object({ type: z.literal('input:pinch:end'), sessionId, requestId }),
136
+ // `modifiers` is a bitmap, not a list — see the note on `InputKey`.
137
+ 'input:key': z.object({
138
+ type: z.literal('input:key'), sessionId, requestId,
139
+ payload: z.object({ code: z.string(), modifiers: z.number().optional() }),
140
+ }),
141
+ 'input:type': z.object({
142
+ type: z.literal('input:type'), sessionId, requestId, payload: z.object({ text: z.string() }),
143
+ }),
144
+ 'input:button': z.object({
145
+ type: z.literal('input:button'), sessionId, requestId,
146
+ payload: z.object({ name: z.string(), phase: z.enum(['down', 'up']).optional() }),
147
+ }),
148
+ 'input:rotate': z.object({ type: z.literal('input:rotate'), sessionId }),
149
+ 'input:keyboard:toggle': z.object({ type: z.literal('input:keyboard:toggle'), sessionId }),
150
+ 'clipboard:read': z.object({
151
+ type: z.literal('clipboard:read'), sessionId, requestId,
152
+ payload: z.object({ press: z.enum(['copy', 'cut']).optional() }).optional(),
153
+ }),
154
+ 'clipboard:write': z.object({
155
+ type: z.literal('clipboard:write'), sessionId, requestId,
156
+ payload: z.object({ text: z.string(), pasteAfter: z.boolean().optional() }),
157
+ }),
158
+ };
159
+ // ── agent → relay ────────────────────────────────────────────────────────────
160
+ /** The six the relay consumes. Every `.default()` below mirrors a `??` that is in `RelayServer` today,
161
+ * so an agent older than a field keeps working exactly as it does now — the default lands in the
162
+ * schema, where it is visible, instead of at the read site, where it read as defensive noise.
163
+ *
164
+ * This is what makes rejection affordable here: `z.input` stays as loose as the wire has ever been
165
+ * while `z.output` matches the interface, which is what the tier assertion compares. */
166
+ const AGENT_CONSUMED = {
167
+ 'agent:register': z.object({
168
+ type: z.literal('agent:register'),
169
+ // **All four defaults come from a `??` in `RelayServer`, and the list is exhaustive by
170
+ // construction** — `agentId ?? agentName` for identity, `devices ?? []`, `capabilities ?? []`, and
171
+ // `agentName ?? agentId ?? 'unknown'` / `platform ?? 'unknown'` in the connect log. A first draft
172
+ // defaulted only `capabilities` and `devices` and required these two, which would have made an
173
+ // agent omitting either **never register at all**: the frame is refused, no `agent:registered`
174
+ // goes back, and the agent's handshake promise never resolves — the whole Mac and every device on
175
+ // it simply absent from the dashboard, with one relay-side warn as the only trace. That is the
176
+ // most expensive rejection in the protocol, so this message is the one to be most tolerant on.
177
+ //
178
+ // `''` rather than `undefined` because `z.output` must match the interface, and it is behaviourally
179
+ // the same everywhere it reaches: `identity` stays falsy so no eviction runs, and the log line uses
180
+ // `||` for exactly this.
181
+ platform: z.string().default(''),
182
+ // How a viewer tells an agent that predates a capability from one that has it.
183
+ capabilities: z.array(z.string()).default([]),
184
+ agentId: z.string().optional(),
185
+ agentName: z.string().default(''),
186
+ // Deduplication by device id stays in the handler — it is a policy about the *set*, not a shape.
187
+ devices: z.array(z.object({
188
+ id: z.string(), name: z.string(), platform: z.string(), status: z.string(),
189
+ osVersion: z.string().optional(),
190
+ })).default([]),
191
+ }),
192
+ 'agent:resources': z.object({
193
+ type: z.literal('agent:resources'),
194
+ resources: z.object({
195
+ cpuPercent: z.number(), memUsedMB: z.number(), memTotalMB: z.number(),
196
+ slotsAvailable: z.number(), slotsTotal: z.number(), reportedAt: z.number(),
197
+ }),
198
+ }),
199
+ 'screenshot:done': z.object({
200
+ type: z.literal('screenshot:done'), sessionId, requestId,
201
+ // The claim, not the truth — the relay sniffs the bytes and logs a mismatch rather than
202
+ // overwriting this, because only the agent knows what it produced (#508).
203
+ format: z.enum(['png', 'jpeg']).default('png'),
204
+ data: z.string().default(''),
205
+ }),
206
+ 'screenshot:error': z.object({
207
+ type: z.literal('screenshot:error'), sessionId, requestId, message: z.string().default(''),
208
+ }),
209
+ 'ui:tree:response': z.object({
210
+ type: z.literal('ui:tree:response'), sessionId, requestId,
211
+ // Safe to validate where `ChromePayload` is not: a normalized shape every platform maps into,
212
+ // not a union with one member per platform.
213
+ elements: z.array(z.object({
214
+ role: z.enum([
215
+ 'button', 'text', 'input', 'image', 'checkbox', 'switch', 'slider', 'list', 'cell', 'tab', 'other',
216
+ ]),
217
+ label: z.string(),
218
+ identifier: z.string().optional(),
219
+ frame: z.object({ x: z.number(), y: z.number(), width: z.number(), height: z.number() }),
220
+ enabled: z.boolean(),
221
+ rawRole: z.string().optional(),
222
+ })).default([]),
223
+ }),
224
+ 'ui:tree:error': z.object({
225
+ type: z.literal('ui:tree:error'), sessionId, requestId, message: z.string().default(''),
226
+ }),
227
+ };
228
+ /** The 22 the relay only forwards. Envelope tier — see the header for why there is no exception. */
229
+ const AGENT_FORWARDED = {
230
+ 'session:chrome': env('session:chrome'),
231
+ 'session:deviceInfo': env('session:deviceInfo'),
232
+ // The only member whose `sessionId` is optional, and it is a documented deferral rather than an
233
+ // oversight — stamping it would make a replayed ready satisfy an in-flight boot. See `DeviceReady`.
234
+ 'device:ready': z.object({
235
+ type: z.literal('device:ready'),
236
+ sessionId: sessionId.optional(),
237
+ requestId: requestId.optional(),
238
+ }),
239
+ 'device:booting': env('device:booting'),
240
+ 'device:shutdown-done': envCo('device:shutdown-done'),
241
+ 'device:boot-error': envCo('device:boot-error'),
242
+ 'app:install-done': envC('app:install-done'),
243
+ 'app:install-error': envC('app:install-error'),
244
+ 'app:launch-done': envC('app:launch-done'),
245
+ 'app:launch-error': envC('app:launch-error'),
246
+ 'app:clear-state-done': envC('app:clear-state-done'),
247
+ 'app:clear-state-error': envC('app:clear-state-error'),
248
+ 'open-url:done': envC('open-url:done'),
249
+ 'open-url:error': envC('open-url:error'),
250
+ 'input:done': envC('input:done'),
251
+ 'input:error': envC('input:error'),
252
+ 'input:type-done': envC('input:type-done'),
253
+ 'input:type-error': envC('input:type-error'),
254
+ 'keyboard:toggled': env('keyboard:toggled'),
255
+ 'clipboard:data': envC('clipboard:data'),
256
+ 'clipboard:write-done': envC('clipboard:write-done'),
257
+ 'clipboard:error': envC('clipboard:error'),
258
+ };
259
+ const AGENT_INBOUND = { ...AGENT_CONSUMED, ...AGENT_FORWARDED };
260
+ // ── stream → relay ───────────────────────────────────────────────────────────
261
+ //
262
+ // One message, and its own direction on purpose: the relay assigns the role `'stream'` from it, so
263
+ // merging it into the agent direction would let a control socket claim to be a session's stream
264
+ // socket. Everything else on that socket is binary and never reaches this parser.
265
+ const STREAM_INBOUND = {
266
+ 'stream:register': z.object({ type: z.literal('stream:register'), sessionId }),
267
+ };
268
+ const INBOUND = { ...BROWSER_INBOUND, ...AGENT_INBOUND, ...STREAM_INBOUND };
269
+ // ── the requests whose payload failure can be answered ───────────────────────
270
+ //
271
+ // **The envelope is judged separately from the payload, and that is what makes an answer possible.**
272
+ // A frame whose `sessionId` and `requestId` are both good and whose payload is not carries everything
273
+ // a reply needs: an address and a correlator. Refusing it wholesale would be the regression this door
274
+ // otherwise ships — today a malformed `open-url` reaches the agent, which answers `open-url:error`
275
+ // from its own guard (`IOSAgent.ts` says so in writing: "validating third-party frames at the relay's
276
+ // door is #444, which will take this over"). Taking it over must not mean losing the answer.
277
+ //
278
+ // The cost of losing it is worst on the inputs, and not obviously: `awaitInputAck` reports silence
279
+ // from a session that has never acked as **success** (#457), so a dropped `input:key` would be
280
+ // reported to an MCP caller as an input that landed.
281
+ //
282
+ // Exactly the twelve browser requests that declare a required `requestId`. The relay maps each to the
283
+ // reply its own waiter reads; `scripts/__tests__/correlatedRequestsGated.test.mjs` derives that set
284
+ // from the protocol and holds all three lists to it.
285
+ const ANSWERABLE = {
286
+ 'device:boot': envC('device:boot'),
287
+ 'app:install': envC('app:install'),
288
+ 'app:launch': envC('app:launch'),
289
+ 'app:clear-state': envC('app:clear-state'),
290
+ 'open-url': envC('open-url'),
291
+ 'input:touch:end': envC('input:touch:end'),
292
+ 'input:pinch:end': envC('input:pinch:end'),
293
+ 'input:key': envC('input:key'),
294
+ 'input:button': envC('input:button'),
295
+ 'input:type': envC('input:type'),
296
+ 'clipboard:read': envC('clipboard:read'),
297
+ 'clipboard:write': envC('clipboard:write'),
298
+ };
299
+ const DIRECTIONS = new Map([
300
+ ...Object.keys(BROWSER_INBOUND).map((t) => [t, 'browser']),
301
+ ...Object.keys(AGENT_INBOUND).map((t) => [t, 'agent']),
302
+ ...Object.keys(STREAM_INBOUND).map((t) => [t, 'stream']),
303
+ ]);
304
+ /**
305
+ * Which socket role is allowed to send this type.
306
+ *
307
+ * This replaces `AGENT_MSG_TYPE_LIST` — 29 literals hand-copied into `RelayServer` and held by two
308
+ * type assertions. It is derived from the map above, which the assertions at the bottom of this file
309
+ * tie back to the protocol's own direction unions, so the copy is gone rather than moved.
310
+ *
311
+ * A runtime set cannot come out of a union directly (types erase), which is why it comes out of the
312
+ * schema map's keys. That makes the relay's role gate depend on this map existing — a real coupling,
313
+ * and the reason the coverage assertions below are not optional.
314
+ */
315
+ export function directionOf(type) {
316
+ // Non-null: `DIRECTIONS` is built from the same keys `InboundType` is derived from, and the
317
+ // coverage assertions below make a divergence a compile error rather than a runtime miss.
318
+ return DIRECTIONS.get(type);
319
+ }
320
+ /**
321
+ * Parse a frame the relay received.
322
+ *
323
+ * **Takes no role.** A first design did, and it could not be called: `classifyConnection` returns
324
+ * `role: 'first-message'` for every local connection and every remote agent-scoped PAT, so the role is
325
+ * assigned from the first message's own `type`. `agent:register` is the message that *creates* the
326
+ * role, so selecting a schema by role to validate it is circular — and defaulting the unknown role to
327
+ * `'browser'`, which is what the relay does for a socket that skips the handshake, would have closed
328
+ * every agent's socket on its opening frame. The order is parse, then role, then gate.
329
+ */
330
+ export function parseInbound(raw) {
331
+ // `JSON.parse` returns bare `null`, numbers and strings without throwing, and a caller that reads
332
+ // `.type` off one of those is the reason this is checked before anything else.
333
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
334
+ return { ok: false, reason: 'not-an-object' };
335
+ const frame = raw;
336
+ const type = frame['type'];
337
+ if (typeof type !== 'string' || !Object.hasOwn(INBOUND, type)) {
338
+ return { ok: false, reason: 'unknown-type', type: typeof type === 'string' ? type : String(type) };
339
+ }
340
+ const known = type;
341
+ // **The universe is the inbound map, not `AnyWireMessage`.** Eleven literals belong to no inbound
342
+ // direction — `session:joined`, `error`, `agents:listed` and the rest the relay produces. A browser
343
+ // that sends one today reaches the switch, matches no case and is ignored. Measuring `unknown-type`
344
+ // against every declared literal instead would classify those as a direction violation, and the
345
+ // relay closes a direction violation with 1008 — disconnecting a dashboard over a frame that is
346
+ // inert today.
347
+ const result = INBOUND[known].safeParse(frame);
348
+ if (!result.success) {
349
+ const detail = z.prettifyError(result.error);
350
+ // Second stage, and only for the twelve. If the envelope stands on its own, the failure is in the
351
+ // payload and the relay has an address and a correlator to answer with — see `ANSWERABLE`.
352
+ if (Object.hasOwn(ANSWERABLE, known)) {
353
+ const answerable = known;
354
+ const envelope = ANSWERABLE[answerable].safeParse(frame);
355
+ if (envelope.success) {
356
+ const { sessionId: s, requestId: r } = envelope.data;
357
+ return { ok: false, reason: 'bad-payload', type: answerable, sessionId: s, requestId: r, detail };
358
+ }
359
+ }
360
+ return { ok: false, reason: 'bad-shape', type: known, detail };
361
+ }
362
+ return { ok: true, msg: result.data, raw: frame };
363
+ }
364
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/validate/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapflowio/protocol",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "Wire protocol contract for tapflow — the WebSocket message types exchanged between browser, relay, and device agents",
5
5
  "keywords": [
6
6
  "tapflow",
@@ -28,6 +28,13 @@
28
28
  "tsx": "./src/index.ts",
29
29
  "import": "./dist/index.js",
30
30
  "default": "./dist/index.js"
31
+ },
32
+ "./validate": {
33
+ "types": "./dist/validate/index.d.ts",
34
+ "source": "./src/validate/index.ts",
35
+ "tsx": "./src/validate/index.ts",
36
+ "import": "./dist/validate/index.js",
37
+ "default": "./dist/validate/index.js"
31
38
  }
32
39
  },
33
40
  "files": [
@@ -36,17 +43,22 @@
36
43
  "LICENSE"
37
44
  ],
38
45
  "engines": {
39
- "node": ">=20.12.0"
46
+ "node": ">=22.0.0"
40
47
  },
41
48
  "publishConfig": {
42
49
  "access": "public"
43
50
  },
51
+ "dependencies": {
52
+ "zod": "^4.4.3"
53
+ },
54
+ "devDependencies": {
55
+ "typescript": "^5.0.0",
56
+ "vitest": "^4.1.10"
57
+ },
44
58
  "scripts": {
45
59
  "build": "tsc -b",
46
- "typecheck": "tsc -b && tsc -p tsconfig.assertions.json",
60
+ "typecheck": "tsc -b && tsc -p tsconfig.assertions.json && tsc -p src/__tests__/tsconfig.json",
61
+ "test": "vitest run",
47
62
  "lint": "eslint src"
48
- },
49
- "devDependencies": {
50
- "typescript": "^5.0.0"
51
63
  }
52
- }
64
+ }