Generated Clients
The same route declarations that produce the server also generate a typed client for your website's frontend — no hand-written fetch calls, no drift between server and client.
sh
./weld app.weld --emit ts -o api.ts # TypeScript
./weld app.weld --emit js -o api.js # JS with JSDoc types
./weld app.weld --emit client -o api # both api.ts and api.jsRoute clients
Path parameters become arguments and {?q} query references become a typed query object:
ts
import { WeldClient } from "./api.ts";
const api = new WeldClient({ baseUrl: "https://example.com" });
await api.getUsersById("42"); // GET /users/42
await api.getUsersByIdPostsByPost("7", "99", { q: "new" }); // GET /users/7/posts/99?q=new- Record types become TypeScript interfaces; a route's
-> Treturn type flows through to the client method's return type. - A
body x: Tparam becomes a typed argument:postUsers(input: NewUser). - Non-2xx responses throw a
WeldErrorcarrying the status and body. - The
.jsoutput is identical but plain JavaScript with JSDoc@param/@returns, so types show up in editors with zero build step.
Hub clients
Every hub also generates a typed WebSocket client — a <Name>Hub class whose constructor takes the connect-time query params, whose methods are typed request/response calls correlated by id, and with on(event, cb) for server-pushed events:
ts
import { ChatHub } from "./api.ts";
const chat = new ChatHub("ws://localhost:8080", { token, room: "general" });
await chat.ready();
chat.on<ChatMsg>("ChatMsg", (m) => console.log(m.from, m.text));
await chat.say("general", "hi"); // typed method callVerified end-to-end against a live hub with the generated JS client.