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:

EndpointBehavior
POST /triggerAccepts an ExecutionEvent JSON body, invokes the workflow, returns { executionId } with status 202
POST /eventsAccepts { 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/events

Middleware

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.