Skip to content

Add capnweb-typecheck RPC validators#169

Draft
teamchong wants to merge 5 commits into
cloudflare:mainfrom
teamchong:typescript-rpc-validators
Draft

Add capnweb-typecheck RPC validators#169
teamchong wants to merge 5 commits into
cloudflare:mainfrom
teamchong:typescript-rpc-validators

Conversation

@teamchong
Copy link
Copy Markdown
Collaborator

@teamchong teamchong commented May 11, 2026

Closes #174

Summary

Adds capnweb-validate, an opt-in TypeScript-to-runtime-validator transform for Cap'n Web and Workers RPC services.

Server validation is enabled with @validateRpc() on the service class. Users keep importing Cap'n Web APIs from capnweb, so the service remains usable with native Workers RPC and with Cap'n Web.

Client validation is enabled by the transform recognizing Cap'n Web session constructors by TypeScript symbol resolution. No client import change is required.

Validated paths:

  • server incoming arguments
  • server resolved return values
  • client outgoing arguments
  • client resolved return values

If @validateRpc() is left untransformed, it throws a configuration error instead of silently running without validation.

How it works

  • The transform finds @validateRpc() decorators imported from capnweb-validate.
  • It resolves the concrete RPC surface from:
    1. explicit decorator type argument
    2. a single implemented interface
    3. the class public methods
  • If a class implements multiple interfaces and no @validateRpc<T>() type argument is given, the transform emits a warning and falls back to class public methods.
  • It lowers method signatures into runtime validators.
  • It emits plain JavaScript validator objects using capnweb-validate/internal/core.
  • It rewrites the decorator to wrap constructed service instances.
  • It recognizes Cap'n Web client session calls from capnweb and injects client-side validation wrappers.
  • The CLI writes a transformed source tree for Wrangler and other flows without bundler plugin hooks.
  • The universal plugin supports Vite, Rollup, Webpack, Rspack, esbuild, and Farm.

Supported pass-by-value types include primitives, arrays, tuples, plain objects, unions, Record<string, T>, selected platform built-ins, and Promise<T> return unwrapping.

Pass-by-reference values include plain functions, RpcStub<T>, RpcPromise<T>, RpcTarget subclasses, and Workers RPC stubs.

Unsupported wire types such as Map, Set, WeakMap, WeakSet, RegExp, ArrayBuffer, and non-Uint8Array typed arrays fail at build time.

Included

  • New packages/capnweb-validate workspace package:
    • @validateRpc() class decorator
    • @skipRpcValidation() method opt-out
    • structured RpcValidationError
    • capnweb-free core runtime validators and wrappers
    • Cap'n Web-specific compatibility helpers under capnweb-validate/capnweb
    • transform implementation
    • CLI
    • universal bundler plugin adapters
  • capnweb is an optional peer dependency. The root entry and capnweb-validate/internal/core have no capnweb imports; Cap'n Web-specific helpers live under capnweb-validate/capnweb and capnweb-validate/internal/capnweb. Workers RPC-only users can install capnweb-validate alone.
  • Workers RPC WorkerEntrypoint support. Runtime-invoked methods on WorkerEntrypoint subclasses (fetch, tail, trace, scheduled, queue, test, email, connect, tailStream) bypass the validator so the Workers runtime can still invoke them; user-defined RPC methods are validated.
  • RpcValidationError extends TypeError with err.rpcValidation = { path, expected, actual, value }. path is JSON-pointer-style, for example ["Api", "authenticate", 0, "profile", "email"].
  • Root build/test wiring.
  • Transform/runtime test coverage.
  • Client session validation without changing imports from capnweb.
  • examples/worker-react validation wiring.
  • VS Code launch/tasks for the example.

Example

Server:

import { newWorkersRpcResponse, RpcTarget } from "capnweb";
import { validateRpc } from "capnweb-validate";

type User = { id: string; name: string };

@validateRpc()
class Api extends RpcTarget {
  async authenticate(sessionToken: string): Promise<User> {
    return { id: "u_1", name: "Ada Lovelace" };
  }
}

export default {
  fetch(request: Request, env: Env) {
    return newWorkersRpcResponse(request, new Api());
  },
};

Client:

import { newHttpBatchRpcSession } from "capnweb";
import type { Api } from "./worker";

const api = newHttpBatchRpcSession<Api>("/api");

await api.authenticate("cookie-123");

Wrangler flow

Wrangler does not expose a bundler plugin hook, so use the CLI for Worker source:

npx capnweb-validate build --cwd src --out .wrangler/validate

Point Wrangler's main at the generated entry under .wrangler/validate.

The React client uses the Vite plugin, not the CLI.

Testing

Package:

npm run -w capnweb-validate build
npm run -w capnweb-validate test

Repo:

npm run build
npm run test:types

Example:

cd examples/worker-react/client && npm run build
node ../../packages/capnweb-validate/dist/cli.cjs build --cwd server --out ../.wrangler/validate
npx tsc -p examples/worker-react/server/tsconfig.json --noEmit

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 11, 2026

⚠️ No Changeset found

Latest commit: 6f46d78

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 11, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 11, 2026

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/capnweb@169

commit: 6f46d78

@teamchong teamchong force-pushed the typescript-rpc-validators branch from c0dc243 to a762c16 Compare May 11, 2026 18:56
@teamchong teamchong changed the title Add TypeScript RPC validation codegen Add capnweb-typecheck for TypeScript RPC validation codegen May 11, 2026
@teamchong teamchong force-pushed the typescript-rpc-validators branch 5 times, most recently from 400182b to 7d866ac Compare May 12, 2026 02:27
@teamchong teamchong changed the title Add capnweb-typecheck for TypeScript RPC validation codegen Add capnweb-typecheck RPC validators May 27, 2026
@teamchong teamchong force-pushed the typescript-rpc-validators branch 2 times, most recently from bda749b to 4ceeec5 Compare May 27, 2026 04:30
Add the capnweb-typecheck package, marker transform, plugin adapters, CLI, runtime validators, tests, and Worker React debug example.
@teamchong teamchong force-pushed the typescript-rpc-validators branch from 4ceeec5 to 7f94aff Compare May 27, 2026 13:41
@teamchong teamchong force-pushed the typescript-rpc-validators branch from 0a6e258 to 2e725b9 Compare May 27, 2026 22:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

runtime type validation

1 participant