HTTP Server
The HTTP runtime exposes /trigger and /events endpoints for triggering workflows and awaiting results over the network. It uses the same worker and SQLite infrastructure as the local runtime, with a Bun HTTP server on top.
Server
server.ts
import pino from "pino";
import { createRoutes, createMiddleware } from "@yieldstar/bun-http-server";
import { createWorkflowInvoker } from "@yieldstar/bun-worker-invoker";
import { SqliteEventLoop, createSqliteDb } from "@yieldstar/bun-sqlite-runtime";
import { router } from "./shared";
const logger = pino();
const workerPath = new URL("./worker.ts", import.meta.url).href;
const invoker = createWorkflowInvoker({ workerPath, logger });
const db = createSqliteDb({ path: "./.db/http.sqlite" });
new SqliteEventLoop(db).start({ onNewEvent: invoker.execute, logger });
Bun.serve({
port: 8080,
routes: {
"/status": new Response("OK"),
...createRoutes({ invoker, logger }),
},
});Client
import { createHttpSdkFactory } from "yieldstar";
import type { Router } from "./shared";
const createSdk = createHttpSdkFactory<Router>();
const sdk = createSdk({ url: "http://localhost:8080" });
const exec = await sdk.trigger({
workflowId: "my-workflow",
});
await exec.ack();
const result = await exec.waitForResult();Routes
createRoutes registers two POST endpoints:
| Endpoint | Behavior |
|---|---|
POST /trigger | Accepts an ExecutionEvent JSON body, invokes the workflow, returns { executionId } with status 202 |
POST /events | Accepts { executionId }, blocks until the workflow completes, returns the result as JSON |
An optional basePath prefixes both routes:
createRoutes({ invoker, logger, basePath: "/api/workflows" });
// → POST /api/workflows/trigger
// → POST /api/workflows/eventsMiddleware
Middleware functions run before the workflow is invoked. They can inspect the request, modify the event context, or return early:
import { createMiddleware } from "@yieldstar/bun-http-server";
const auth = createMiddleware(async (req, event, next, logger) => {
const token = req.headers.get("Authorization");
if (!token) return new Response("Unauthorized", { status: 401 });
event.context.set("userId", parseToken(token).sub);
return next();
});
createRoutes({ invoker, logger, middleware: [auth] });Middleware receives four arguments: req (the Request), event (a MiddlewareEvent with a mutable context map), next (calls the next middleware or handler), and logger. The context map is frozen after all middleware runs and becomes a read-only Map inside the workflow via event.context.