Explicit, Bun-native typed HTTP APIs — without runtime proxies, code generation, or production dependencies.
Lugas uses the beta dist-tag for prerelease builds. Check npm or GitHub Releases for the currently available version.
For published beta builds:
bun add lugas@betaRequires Bun 1.4.x; TypeScript 7.0.2 is the verified toolchain for the full compile-time contract experience.
// app.ts
import { defineApp, json, route } from "lugas";
const app = defineApp({
routes: {
"/hello": {
GET: route({
handler: () => json(200, { message: "Hello from Lugas" }),
}),
},
},
});
export default app;// server.ts
import app from "./app";
const server = app.serve({ port: 3000 });
console.log(`Lugas is listening on ${server.url}`);bun run server.ts
curl http://localhost:3000/helloRoutes stay ordinary HTTP: native Request, explicit statuses, real fetch underneath.
Validation and guards compose per route; schema outputs and guard enrichments arrive typed on the handler context:
import { defineApp, defineModule, guard, json, route } from "lugas";
import { z } from "zod"; // any Standard Schema v1 validator works
const auth = guard({
name: "auth",
handler: (ctx) => {
if (!ctx.request.headers.get("authorization")) return json(401, { error: "unauthorized" });
return { user: { id: "u_1" } };
},
});
export default defineApp({
modules: [
defineModule({
name: "invoices",
routes: {
"/invoices": {
POST: route({
before: [auth],
body: z.object({ amount: z.number().positive(), currency: z.string().length(3) }),
handler: (ctx) => json(201, { id: "inv_1", amount: ctx.body.amount, user: ctx.user.id }),
}),
},
},
}),
],
});Most TypeScript frameworks sit at one of two extremes: a thin router that leaves all structure to you, or a large platform with decorators, proxies, and generated clients. Lugas takes a narrower path — keep HTTP explicit, add only the structure that makes Bun applications predictable, typed, testable, and inspectable:
- typed routes with status-discriminated, wire-honest response types;
- Standard Schema v1 validation (Zod, Valibot, …) with schema-derived handler types;
- ordered guards with typed context enrichment;
- RFC 9457 Problem Details errors with stable diagnostic codes;
- an end-to-end typed client — no code generation, no runtime
Proxy; - zero production runtime dependencies.
Full positioning and framework comparisons: docs/choosing-lugas.md.
import type { AppContract } from "lugas";
import { createClient } from "lugas/client";
import type app from "./app";
const api = createClient<AppContract<typeof app>>({ baseUrl: "https://api.example.com" });
const result = await api.post("/invoices", {
body: { amount: 125, currency: "USD" },
});
if (result.ok) {
console.log(result.status, result.data.id);
} else {
console.error(result.status, result.error); // Problem Details on 4xx/5xx
}Types describe the wire. A handler returning json(200, { createdAt: new Date() }) is observed by the client as { createdAt: string } — non-finite numbers, toJSON() drops, and throws are all modeled, not hidden. Details: docs/wire-honest-types.md.
| Capability | Status |
|---|---|
| Bun-native server, typed routes, modules | Available |
| Standard Schema validation on params/query/headers/body | Available |
| Ordered guards with typed context enrichment | Available |
Status-discriminated, wire-honest responses (json/text/problem/empty) |
Available |
| RFC 9457 Problem Details + redacted 500s | Available |
End-to-end typed client (lugas/client, browser-safe) |
Available |
Service lifecycle: init, drain-ordered shutdown, reverse disposal (service()) |
Available |
Test-server helpers (lugas/testing) |
Available |
Static route manifest + inspection CLI (lugas-manifest-v1) |
Available |
First-party CORS (defineApp({ cors }), opt-in, fail-closed) |
Available in 0.1.0-beta.2 (M8-001) |
Server-Sent Events (sse() helper, deterministic cleanup) |
Available in 0.1.0-beta.2 (M8-002) |
Structured logging (defineApp({ logging }), sink contract) |
Available in 0.1.0-beta.2 (M8-003) |
OpenAPI 3.1 + Scalar reference UI (defineApp({ openapi }), zero-dependency) |
Available in 0.1.0-beta.2 (M8-004) |
Drizzle ORM adapter (lugas/drizzle, application-owned instance) |
Available in 0.1.0-beta.3 (M9-001) |
Cookie primitives (parseCookies/cookie, RFC 6265, auth-interop recipe) |
Shipped on main (M9-002) |
WebSockets (websocket() routes, pre-upgrade guards, shutdown close-1001) |
Shipped on main (M9-003) |
Secure headers + health/readiness (secureHeaders, health) |
Shipped on main (M9-004) |
Runnable, single-concept applications under examples/ — indexed in examples/README.md:
| Example | Demonstrates |
|---|---|
basic |
Minimal app: routes, JSON/text, redirect, Problem Details |
validation |
Zod + Valibot across params, query, headers, body |
auth |
Ordered guards: 401/403 short-circuits, context enrichment |
client |
Typed client round-trip against a live test server |
proof-api |
Realistic CRUD API combining all of the above |
Verified matrix (see docs/compatibility.md): Bun 1.4.x on Linux x86-64, macOS arm64, and Windows x64; TypeScript 7.0.2; Zod 4.4.3 and Valibot 1.4.2 (any Standard Schema v1 validator works). Browser-safe client bundle plus a prebuilt browser artifact (lugas/client/browser) verified in a same-origin real-browser lane; real browsers are not part of the per-OS CI matrix.
Known beta limitations: the server core and CLI are Bun-only (the client bundle is runtime-neutral), declarations ship as direct .ts sources, and in-flight handler work is not cancelled on client disconnect.
Shipped and planned work lives in docs/roadmap.md. The Drizzle adapter (docs/drizzle.md) ships in lugas@0.1.0-beta.3 (published under npm beta, source commit f3c72e6, M9-001). First-party CORS (docs/cors.md), Server-Sent Events (docs/sse.md), Structured Logging (docs/logging.md), and OpenAPI 3.1 + Scalar (docs/openapi.md) ship in 0.1.0-beta.2+; latest points at 0.1.0-beta.2.
| Document | Contents |
|---|---|
docs/getting-started.md |
Install, first app, validation, guards, client, testing, CLI |
docs/routing.md |
Route maps, path syntax, modules, native values, the derived handler context |
docs/validation.md |
Standard Schema slots, coercion, body parsing, the 422 failure contract |
docs/guards.md |
Ordered guards, typed context enrichment, short-circuits, composition patterns |
docs/responses.md |
Typed response helpers, Problem Details, notFound/onError, redaction |
docs/services.md |
Named dependencies, service() lifecycle, the init traffic gate, drain shutdown |
docs/client.md |
The end-to-end typed client: calls, per-status results, error classes |
docs/testing.md |
createTestServer, the bound typed client, lifecycle and error-contract tests |
docs/wire-honest-types.md |
How response types model JSON serialization truth |
docs/design-principles.md |
Explicit HTTP, no codegen, no proxies, zero forced ecosystem |
docs/choosing-lugas.md |
Fit and comparison with raw Bun, Elysia, Hono, Fastify, tRPC |
docs/api-reference.md |
Public API reference |
docs/diagnostics.md |
Diagnostic code catalog (LUGAS_*) |
docs/manifest-v1.md |
Frozen lugas-manifest-v1 schema |
docs/client-error-semantics.md |
Client error and redaction policy |
docs/drizzle.md |
Drizzle integration: application-owned instance as a service |
docs/cookies.md |
Cookie primitives and the Better Auth interop recipe |
docs/websockets.md |
WebSocket routes: pre-upgrade guards, native sockets, shutdown semantics |
docs/production.md |
Production hardening: secure headers and health/readiness |
docs/performance-gates.md |
Release performance budgets and evidence policy |
CHANGELOG.md |
Release history |
| Release evidence | Candidate evidence packet, provenance, and checksums (GitHub) |
Agent-facing context: llms.txt and llms-full.txt. Governance, delivery history, and architecture decisions live under docs/okf/; implementation evidence under docs/reports/.
Contributions follow the worktree + verify-gate workflow in CONTRIBUTING.md — real-application feedback, type-inference reproductions, and cross-platform reports are the highest-value contributions during beta. Community rules: CODE_OF_CONDUCT.md. Questions and support: SUPPORT.md.
Do not open public issues for security vulnerabilities — report privately per SECURITY.md.