A client and a server, on one port A client, and its server in a Web Worker
Bead is a binary call protocol, one surface in TypeScript, C# and Rust, over a WebSocket, over HTTP or in a Web Worker. Try a scene: its result shows in its card, and the wire shows what crossed. Its source is on GitHub.
- Log in as a writer
- Subscribe, then burst
- Send a glyph, or start a slow call and cancel it
Who you are
An access token, a JWT each call presents in its header: a read needs one that
holds, a write one whose scope holds write.
Identity
logged out
—
A counter, paced
Subscribe, then burst: five changes come as two notifications, paced — the first, then the latest — and five signals merge into two reads.
Counter
—2 subscriptions: the value, paced; the signal, merged by the page
Last burst —
—
8 MiB, in chunks
A glyph drawn at random crosses in chunks, each sent as the other end grants credit.
Glyph
—
Calls that end otherwise
Slow, cancelled, timed out, failed — and the server asking back.
Result
—
- Sign up the valid one it holds
- Break several fields, and sign up
- Validate before sending: the client refuses it first
Payload rules
A sign-up whose .proto holds protovalidate's rules, compiled by beadc:
the server judges each request before its resolver, and answers one they refuse
PAYLOAD_INVALID, each violation shown under its field.
The same sign-up over HTTP and JSON
A gateway answers it as one more client of the server, its route
POST /api/SignUp/signUp, a refusal in RFC 9457's problem; yarn demo runs one, which this page, its server a Web Worker,
cannot.
Its request, as it is filled
What the gateway answers
What it answers shows once the sign-up is sent.
The sign-up's OpenAPI document
What beadc wrote of the sign-up's routes, OpenAPI 3.1.1: what its HTTP form takes, and each answer it gives; the gateway serves it at /openapi.json.
The server, every second
—
Read every second, its health and what each layer holds by a stats call,
the calls it answered by the metrics call beside, over Bead itself, both
left out of the wire and of these counts.
Open this page in a second tab: each tab is a client of this one server, which counts them, and they share its counter.
- Calls answered
- —
- by the server, the reads aside
- Median
- —
- estimated within its bucket
- Connections
- —
- a client a tab
- Subscriptions
- —
- the server notifies
Per procedure, what the server answered
What each end's metrics registry counts, every second: the server's by a
metrics call, over Bead itself, so a server in a Web Worker answers it
as a Node one does, and /metrics serves it to a scraper. The reads are left out, the durations estimated within their buckets.
Per procedure, what this tab's client made
What each layer holds: router, server, sessions, transport
The server's exposition, as a scrape reads it
The client's exposition
The same service, in TypeScript and in C#
examples/hello's HelloService, both sides as the repository builds and
runs them: one surface, name for name, each in its language's own idiom.
Go deeper
What the wire shows goes to the console too, with no reload:
localStorage.setItem('bead:debug', '*'), or a filter such as
d(rx), -token, and e(notification) for the envelopes. The
Bead DevTools panel filters every view; -metrics, -stats leaves polling
out of its Broker view where DATA joins its call. Uncertain captures stay visible.
One contract, several packages
Cut a blueprint into the outputs of beadc.yaml: each writes a
server, a client and a gateway over its own
selection of procedures, and each transport of its server takes the procedures it is
given. Every choice comes from the blueprint; nothing is typed. What each class holds
and what beadc generate would refuse are beadc's own code, run in this
page.
Or drop here a bead-blueprint/1 file, which
beadc blueprint writes; it stays in this browser. The page reads its
services and their procedures alone: a blueprint's own checks are
beadc check's.
Packages
What each class holds
A filled dot: the class holds the procedure. The server class holds its resolvers,
its notifiers and the requesters of its commands; the client class its requesters,
its notifications and the resolvers of the commands it answers; the gateway its
routes. A transport's column is what it takes: a request to any other procedure is
answered SERVICE_UNKNOWN or PROCEDURE_UNKNOWN.
The procedures each transport takes
The gateway's routes
beadc.yaml's outputs
Each folder and each transport's key is derived from what its package holds, never
from its place in the list: removing a package renames no other. To name them
otherwise, rename them in beadc.yaml; a key of
server.transports is the member of
SERVED_PROCEDURES (TypeScript) or ServedProcedures (C#) the
application hands its transport. The file around these outputs keeps its
version and its source: what depends on the disk, the
.proto roots among it, stays beadc generate's.