Repository navigation
Add Biome no-type-assertion plugin and remove all as casts - #3
Conversation
Lint-only config (formatter off, no preset rules) so the only check is the no-type-assertion Grit plugin. Adds a root `pnpm lint` script. Co-authored-by: Anirudh Kamath <kamath@users.noreply.github.com>
- Parse untrusted JSON (HTTP bodies, CDP responses, provider APIs, sandbox bridge payloads, sessionStorage) with zod instead of casting. - Validate enum-like browse params (screenshot type, mouse button, load state, clip) with zod-backed helpers; export the allowed values from page.ts. - Unwrap the QuickJS variant with a runtime guard: its CJS typings disagree with the ESM runtime shape. - Let browser_run's input schema be the honest union of the two modes and narrow it where a single shape is needed (examples/02-mcp-server). - Drop casts TypeScript can already narrow (in-operator, AI SDK dynamic flag). Co-authored-by: Anirudh Kamath <kamath@users.noreply.github.com>
Test results are parsed with zod so a wrong shape fails loudly; Mastra tools
get a real execute context (RequestContext + noopObserve) instead of {} as never.
Co-authored-by: Anirudh Kamath <kamath@users.noreply.github.com>
Main (#2) added Biome with the recommended preset and formatter and reformatted the codebase. Conflicts resolved by normalizing formatting on both sides and three-way merging the content: - biome.json/package.json: main's config and scripts, plus the no-type-assertion plugin. - page.ts: keep main's Quad tuple and area(); derive Quad from a zod tuple schema so the quads cast stays removed. - examples/02-mcp-server: keep main's sessions guard and this branch's sessionId shape narrowing. - tools.test.ts: keep main's non-null-assertion removals, with zod parsing in place of the casts. - api.chat.ts: type `let messages` for noImplicitAnyLet.
biome.json loads the no-type-assertion plugin from node_modules, which the standalone setup-biome binary does not have.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ac13c2e. Configure here.
| errorText?: string; | ||
| }; | ||
| const parsed = toolPartSchema.safeParse(part); | ||
| if (!parsed.success) return null; |
There was a problem hiding this comment.
In-progress tool calls hidden
Medium Severity
toolPartSchema treats input and output as required, but AI SDK dynamic-tool parts omit those keys while a call is streaming or waiting (input-streaming / input-available). asToolCall then fails safeParse and returns null, so in-progress browser_run rows never render and the existing running state is unused until the call finishes.
Reviewed by Cursor Bugbot for commit ac13c2e. Configure here.


Summary
Adds
biome-plugin-no-type-assertionto the Biome setup from #2 and removes all 77astype assertions it flagged. Where a value comes from outside the type system, it is now validated with zod (already a dependency of every package). Elsewhere, the cast is replaced by a type guard or TypeScript's own narrowing.pnpm lint(main'sbiome check) now runs the formatter, the recommended rules and the plugin.as constis still allowed.What changed
Untrusted data is parsed with zod instead of cast
/screeninapp.ts,/api/chat(the body is parsed with zod, then messages are checked with the AI SDK'svalidateUIMessages), and web UI error and browser-handle responses./json/version,Page.captureScreenshot, andDOM.getContentQuads(itsQuadtype is now derived from a zod tuple).JSON.parseof host-call arguments and log entries), and the browser handle saved insessionStorage.CallToolResultSchemafrom the MCP SDK.Browse command params
screenshot.type, mousebutton,waitUntil,wait load <state>, andclipare validated by small zod-backed helpers (optEnum,oneOf,optClip). Invalid values now raise aBrowseCommandErrorinstead of passing through. The allowed values are exported frompage.ts(LOAD_STATES,MOUSE_BUTTONS), and the types derive from them.QuickJS variant
@jitl/quickjs-wasmfile-release-syncships CommonJS typings. Under NodeNext its default import is typed as{ default: variant }, but ESM runtimes (Node, workerd) hand over the variant itself. The newsandbox/variant.tsunwraps it with a runtime type guard. It is used byrunner.ts,worker.tsandruntime-bundled.ts.browser_runinput schema (tools)cdpUrlandsessionIdexist is gone.inputSchemais now the honest union of the two modes.examples/02-mcp-servernarrows it with anincheck before handing the shape toregisterTool.toModelOutputcallbacks receiveunknownbecause Mastra types output only throughoutputSchema, so they parse their input with zod.LiveView.urlnow also acceptsundefined.Casts that were simply unnecessary
in-operator narrowing in the web UI'scodeOf/textOf.dynamicflag inexamples/01-hello-world.ErrorOptionsinCdpEndpointError.connectOverCdpincore.ts.App.fetchis narrowed to the single argument every caller passes.Tests
RequestContext+noopObserve) instead of{} as never.Behavior changes
LoadState,MouseButtonand"png" | "jpeg"types; previously they were forwarded to CDP./api/chatreturns 400 for a malformed body or malformed messages; previously a malformed body could throw and return 500.Validation
pnpm lintandpnpm check(all 5 packages)pnpm test(62 tests) andpnpm buildtest:runtimeandtest:workeragainst real Chrometest:e2e: 14/14 against real Chrome