@skein-js/express
v0.5.0
Published
Express adapter for skein-js — mount the Agent Protocol on an Express Router.
Maintainers
Readme
@skein-js/express
Express adapter for skein-js — mount the Agent Protocol on an Express
Router.
Part of skein-js — a TypeScript Agent Protocol server for LangGraph.js, and a drop-in replacement for the LangGraph CLI.
Status: 🚧 Pre-alpha — implemented; the v1 framework adapter.
What it does
Converts Express req/res into @skein-js/agent-protocol's normalized
request, dispatches to its handler table, and pipes JSON / 204 / text/event-stream responses back
out. It adds no protocol logic of its own — it's a thin transport shim. It ships:
createExpressServer— a zero-setup server (reads alanggraph.json, wires in-memory drivers).skeinRouter— a mountableRouterfor an existing Express app.createHandlerRouter— the pure shim for callers wiring their ownProtocolDeps.
Install
pnpm add @skein-js/express @langchain/langgraphexpress (>=4.18) and @langchain/langgraph are peer dependencies. express is almost
always already in your app; add it too if not (pnpm add express).
Usage
The zero-setup server — reads a langgraph.json, wires in-memory drivers, and serves the protocol:
import { createExpressServer } from "@skein-js/express";
const server = await createExpressServer({ config: "./langgraph.json" });
await server.listen(2024); // defaults: port 2024, host "localhost"
// …later:
await server.close();Mount the router on an existing Express app:
import express from "express";
import { skeinRouter } from "@skein-js/express";
const app = express();
const { router, runtime } = await skeinRouter({ config: "./langgraph.json" });
app.use(router);
app.listen(2024);
// runtime.worker.stop() to drain background runs on shutdown.Bring your own persistent drivers (e.g. Postgres + Redis, assembled by
@skein-js/runtime) through the same deps seam:
import { skeinRouter } from "@skein-js/express";
import { buildRuntime } from "@skein-js/runtime";
const runtime = await buildRuntime({
configPath: "./langgraph.json",
store: "postgres",
queue: "redis",
});
const { router } = await skeinRouter({ deps: runtime.deps, cors: runtime.cors });
app.use(router);API
createExpressServer(options): Promise<SkeinExpressServer>—SkeinExpressServer={ app, runtime, listen(port?, host?), close() }.listendefaults to port2024, host"localhost", resolves the NodeServeronce bound;close()stops the run worker then the HTTP server (idempotent).skeinRouter(options): Promise<SkeinRouter>—SkeinRouter={ router, runtime }.SkeinRouterOptions— common{ logger?, cors?, warm? }plus either{ config, importModule? }(in-memory runtime from alanggraph.json) or{ deps }(bring-your-ownProtocolDeps).warm: trueeagerly loads graphs at startup;loggermounts per-request logging.createHandlerRouter(handlers, options?)/skeinRoutes— the pure route table, for composing your own routing over an existingProtocolHandlers.corsFromHttpConfig(http)/toCorsOptions(config)— map alanggraph.jsonhttp.corsblock ontocorsoptions (LanggraphCorsConfig).loadInMemoryRuntime/loadReloadableInMemoryRuntime— the in-memoryProtocolDepsloaders (the reloadable one addsreloadGraphs/snapshotState/hydrateState, poweringskein dev).- Low-level mappers:
toProtocolRequest,sendProtocolResponse,sendErrorResponse.
CORS
Browser clients (Agent Chat UI, React useStream) run on a different origin. CORS is off by
default (non-permissive) and driven by the http.cors block of langgraph.json, matching the
LangGraph CLI:
{
"graphs": { "agent": "./agent.ts:graph" },
"http": { "cors": { "allow_origins": ["http://localhost:3000"] } },
}Override in code with the cors option: pass CorsOptions
to restrict origins, true for permissive dev, or false to force it off.
Reuse
Thin transport shim over @skein-js/agent-protocol; adds no protocol logic of
its own.
Learn more
- Agent Protocol surface · Streaming (SSE) · React SDK /
useStream - skein-js overview · Reuse-first architecture · Root README
