TomoeJS — The Art of Perfect Balance.
Ultra-Fast · Contract-Driven · Compile-Time Type Safety · Universal Web Standards Core
Tomoe (巴) is a next-generation, high-performance web framework designed with a single goal: bridging the gap between strict backend correctness and supreme developer experience.
Embracing native Web Standard APIs (Request, Response, Headers, Cookies), TomoeJS is universally portable across Bun, Cloudflare Workers, Node.js, Deno, and Vercel. It eliminates the single largest flaw in modern web frameworks: unsafe, untyped middleware side-effects.
Important
TomoeJS is currently a release candidate. Review the production readiness checklist, deployment guide, release checklist, and security policy before production use.
- 🛡️ Contract-Driven Design: The first framework introducing Relics & Guards to enforce typed preconditions at boot time instead of throwing unexpected runtime errors in production.
- ⚡ Supreme Performance: Features a pre-compiled radix tree router and cached middleware onion runners to achieve maximum throughput.
- 🌐 Web Standards First: Zero-dependency wrapper that interacts directly with native Web standard objects like
RequestandResponse. - 🔌 Native WebSockets: Out-of-the-box WebSocket support with custom handshake header hooks and path parameter support.
- 🧰 End-to-End Type Safety: Generate a fully typed client SDK directly from your server type signature without codegen or build scripts.
- 🔮 Graph Compilation & Validation: Pre-compile routing tables, run validations, and audit middleware onion chains at startup.
Install TomoeJS using your preferred package manager:
# npm
npm install tomoejs@rc
# pnpm
pnpm add tomoejs@rc
# bun
bun add tomoejs@rc
# yarn
yarn add tomoejs@rcCreate an index.ts file to see TomoeJS in action:
import { Tomoe } from "tomoejs"
const app = new Tomoe()
// 1. Static response
app.get("/", (c) => c.text("Welcome to TomoeJS!"))
// 2. Dynamic path parameters (automatically URL-decoded)
app.get("/hello/:name", (c) => {
const name = c.param("name") // Automatically handles URL decoding (e.g. "%20" to " ")
return c.json({ message: `Hello, ${name}!` })
})
export default appbun index.tsTo use standard Node.js environments, use the built-in HTTP server adapter:
import { Tomoe, createServer } from "tomoejs"
const app = new Tomoe()
app.get("/", (c) => c.text("Hello from Node.js!"))
const server = createServer(app)
server.listen(3000, () => {
console.log("Server listening at http://localhost:3000")
})In traditional frameworks (Express, Fastify, Hono, Elysia), middleware injects values into the request context implicitly, leaving route handlers to blindly assume the values exist:
// ❌ Traditional (Unsafe): Will compile, but throws runtime errors if the auth middleware is missed or ordered incorrectly!
app.use(authMiddleware)
app.get("/me", (c) => {
const user = c.get("user") // Typeless! Could be undefined if middleware failed or was skipped.
return c.json(user)
})TomoeJS replaces implicit context manipulation with explicit dependency contracts called Relics & Guards. If a route handler depends on state (like a database connection or verified user), that dependency must be declared.
// 👑 TomoeJS (Contract-Driven): Fully typed at compile time.
// If authRelic isn't mounted, TS compiler blocks it, and app.compile() throws at startup.
app.get("/me", authRelic, (ctx) => {
// ctx.user is fully typed and guaranteed to exist!
return ctx.json(ctx.user)
})By resolving dependencies before invoking the route handler, TomoeJS guarantees compile-time safety and prevents runtime crashes caused by misordered middleware.
Benchmarks are run using Autocannon with 100 concurrent connections in an isolated environment. The socket ports and server processes are cleared programmatically between runs to ensure accuracy.
- Operating System: Windows 11
- Node.js version:
v24.13.0| Bun version:v1.3.3 - Frameworks Tested: TomoeJS
v1.0.0-rc.3, Honov4.12.23, Elysiav1.4.28
| Framework | Requests / Sec (Throughput) | Avg Latency | P99 Latency |
|---|---|---|---|
| TomoeJS (Bun) | 45,131 req/s | 1.58 ms | 5 ms |
| Hono (Bun) | 42,691 req/s | 1.91 ms | 4 ms |
| Elysia (Bun) | 41,987 req/s | 1.96 ms | 4 ms |
| Hono (Node) | 29,480 req/s | 2.92 ms | 7 ms |
| TomoeJS (Node) | 20,369 req/s | 4.41 ms | 11 ms |
| Framework | Requests / Sec (Throughput) | Avg Latency | P99 Latency |
|---|---|---|---|
| TomoeJS (Bun) | 45,853 req/s | 1.54 ms | 4 ms |
| Elysia (Bun) | 39,043 req/s | 2.21 ms | 4 ms |
| Hono (Bun) | 36,856 req/s | 2.30 ms | 4 ms |
| Hono (Node) | 29,067 req/s | 3.00 ms | 6 ms |
| TomoeJS (Node) | 22,600 req/s | 3.95 ms | 8 ms |
| Framework | Requests / Sec (Throughput) | Avg Latency | P99 Latency |
|---|---|---|---|
| Elysia (Bun) | 37,878 req/s | 2.29 ms | 4 ms |
| TomoeJS (Bun) | 33,573 req/s | 2.41 ms | 6 ms |
| Hono (Bun) | 31,886 req/s | 2.54 ms | 6 ms |
| Hono (Node) | 23,374 req/s | 3.76 ms | 8 ms |
| TomoeJS (Node) | 20,616 req/s | 4.37 ms | 9 ms |
| Framework | Messages / Sec (Throughput) | Avg Latency | P99 Latency |
|---|---|---|---|
| Elysia (Bun) | 45,535 msg/s | 0.43 ms | N/A |
| 👑 TomoeJS (Node) | 45,448 msg/s | 0.42 ms | N/A |
| Hono (Bun) | 44,159 msg/s | 0.44 ms | N/A |
| Hono (Node) | 43,964 msg/s | 0.45 ms | N/A |
| TomoeJS (Bun) | 27,759 msg/s | 0.69 ms | N/A |
- Native WebSocket API
- End-to-End Type-Safe Client SDK
- OpenAPI Specs & Swagger UI
- Graph Compilation & Inspection
- Runtimes & Deployment Matrix
- Error Handling (Functional & Thrown)
TomoeJS implements a high-performance radix tree router featuring dynamic path parameters, wildcard support, and fast paths for static routes.
const app = new Tomoe()
// Static route
app.get("/api/v1/status", (ctx) => ctx.json({ ok: true }))
// Path parameters (inferred in types, URL-decoded automatically)
app.get("/api/users/:userId/posts/:postId", (ctx) => {
const { userId, postId } = ctx.params
return ctx.json({ userId, postId })
})
// Wildcard routes
app.get("/assets/*", (ctx) => {
const filepath = ctx.param("*")
return ctx.text(`Requested asset: ${filepath}`)
})Organize large projects cleanly using either standalone sub-routers or inline protected scope routes.
Perfect for separating business domains into modular files:
import { Tomoe } from "tomoejs"
const animeRouter = new Tomoe()
animeRouter.get("/list", (c) => c.json(["FMA", "Hunter x Hunter"]))
animeRouter.get("/:id", (c) => c.json({ id: c.param("id") }))
const app = new Tomoe()
app.route("/api/anime", animeRouter) // Mounted at `/api/anime/list` and `/api/anime/:id`Enforce contract middleware on a group of nested routes:
app.scope("/admin", adminAccessRelics, (scoped) => {
scoped.get("/dashboard", (ctx) => {
// Access typed properties inherited from scope relics
return ctx.json({ user: ctx.user, org: ctx.org })
})
})Middlewares intercept incoming requests to manipulate context, handle telemetry, or manage CORS headers.
import type { Middleware } from "tomoejs"
const responseTime = (): Middleware => {
return async (ctx, next) => {
const start = performance.now()
const response = await next()
const duration = (performance.now() - start).toFixed(2)
response.headers.set("X-Response-Time", `${duration}ms`)
return response
}
}
app.use(responseTime())import { cors, logger, csrf, rateLimit } from "tomoejs"
// Cross-Origin Resource Sharing
app.use(cors({ origin: ["https://example.com"] }))
// Console Request Logger
app.use(logger())
// Cross-Site Request Forgery Protection
app.use(csrf({ origin: ["https://trusted.com"] }))
// In-Memory Rate Limiting
app.use(rateLimit({ windowMs: 60000, max: 100 }))Handlers receive a unified Context object, providing helpers to parse inputs and construct Web Standard responses.
ctx.req: The native WebRequestinstance.ctx.query(key): Read a query string parameter.ctx.queries: Get all query parameters as a key-value object.ctx.header(name): Read a request header (case-insensitive).ctx.header(name, value): Queue a header to be written to the response.ctx.json(data, init?): Return a JSON response with matching content-type.ctx.text(body, init?): Return a plain text response.ctx.html(markup, init?): Return an HTML response.ctx.redirect(url, status?): Perform a redirection response.
TomoeJS provides an RFC 6265 secure, lazy-parsed cookie API:
app.get("/auth", (ctx) => {
// Read request cookie
const token = ctx.cookie("session_token")
// Queue response cookie
ctx.setCookie("user_id", "12345", {
httpOnly: true,
secure: true,
sameSite: "Strict",
maxAge: 3600
})
return ctx.json({ loggedIn: !!token })
})You can read payloads standardly or use Zod validations to safely parse incoming data.
Ideal for stream-friendly handlers with zero allocations:
app.post("/upload", async (ctx) => {
const jsonBody = await ctx.req.json()
const textBody = await ctx.req.text()
const formData = await ctx.req.formData() // parses multipart uploads
const arrayBuffer = await ctx.req.arrayBuffer()
return ctx.json({ received: true })
})Injects pre-validated bodies directly into ctx.body:
import { relic } from "tomoejs"
import { z } from "zod"
const userSchema = z.object({
username: z.string().min(3),
email: z.string().email()
})
app.post("/register", relic.body(userSchema), (ctx) => {
// Autocomplete-ready and validated at runtime
const { username, email } = ctx.body
return ctx.json({ status: "created", username })
})Create modular, chainable components to manage authentication, session state, or database connections.
- Relics (
relic): Compute values asynchronously and inject them intoctx. - Guards (
guard): Enforce security rules. Cannot inject variables but can depend on other relics. - Unite (
unite): Merge multiple Relics and Guards into a single cohesive route contract.
import { relic, guard, err, Unauthorized, Forbidden, unite } from "tomoejs"
// 1. Create a relic that injects a verified 'user'
const authenticateUser = relic("user", async (ctx) => {
const token = ctx.header("Authorization")
if (!token) return err(Unauthorized) // Returns a structured functional error
const user = await db.verifyToken(token)
if (!user) return err(Unauthorized)
return user
})
// 2. Create a guard that checks role requirements
const checkAdminRole = guard(async (ctx, use) => {
const user = use(authenticateUser) // Resolve user dependency safely
if (!user.isAdmin) return err(Forbidden)
})
// 3. Chain them using unite()
const adminAccess = unite(authenticateUser, checkAdminRole)
// 4. Protect a scoped routing path
app.scope("/admin", adminAccess, (router) => {
router.get("/metrics", (ctx) => {
// Both user validation and role authorization are guaranteed here
return ctx.json({ activeUser: ctx.user.username, systemHealth: "ok" })
})
})TomoeJS supports schema validation out of the box using Zod, Valibot, ArkType, or TypeBox.
import { z } from "zod"
import { unite, relic } from "tomoejs"
const itemBody = z.object({ name: z.string() })
const queryPage = z.object({ page: z.coerce.number().default(1) })
app.post(
"/items",
unite(relic.body(itemBody), relic.query(queryPage)),
(ctx) => {
const { name } = ctx.body
const { page } = ctx.query
return ctx.json({ name, page })
}
)Supported natively on Node.js (via the createServer adapter) and other runtimes. WebSocket handlers are integrated directly into the core router gateway, supporting relics and parameters.
import { Tomoe, createServer } from "tomoejs"
const app = new Tomoe()
app.ws("/chat/:roomId", {
// Protocol Handshake Hook
handshake(ctx) {
const requestedProtocol = ctx.header("Sec-WebSocket-Protocol")
if (requestedProtocol) {
ctx.header("Sec-WebSocket-Protocol", requestedProtocol)
}
},
// Connection opened
open(ws, socketCtx) {
console.log(`Connected to room: ${socketCtx.params.roomId}`)
ws.send(JSON.stringify({ status: "connected" }))
},
// Message received
message(ws, data, socketCtx) {
ws.send(JSON.stringify({ echo: data }))
},
// Connection closed
close(ws, socketCtx) {
console.log(`Disconnected from room: ${socketCtx.params.roomId}`)
}
})
// Secure WebSocket routes using Relics
app.ws("/secure-feed", authRelic, {
open(ws, socketCtx) {
const user = socketCtx.relics.user
ws.send(`Hello secure user, ${user.name}!`)
}
})
const server = createServer(app)
server.listen(3000)Share type definitions directly from your backend instance to your frontend to generate a type-safe client SDK without external code generation.
const app = new Tomoe().post("/posts", relic.body(postSchema), (ctx) => {
return ctx.json({ id: "100" })
})
export type AppRouter = typeof appimport { createClient } from "tomoejs"
import type { AppRouter } from "./server"
const client = createClient<AppRouter>("http://localhost:3000")
// Inputs (body, params, headers, query) are validated at compile-time!
const { data, error, status } = await client("/posts").post({
body: { title: "Next-Gen Web Frameworks", content: "..." }
})TomoeJS automatically parses Zod/Valibot/TypeBox schema dependencies registered in route relics to generate full OpenAPI v3 specs and serve Swagger UI.
import { swagger } from "tomoejs"
const app = new Tomoe()
// Setup docs endpoint
swagger(app, {
title: "TomoeJS Core Services",
version: "1.0.0",
path: "/docs", // Swagger UI endpoint
specPath: "/openapi.json" // OpenAPI Spec endpoint
})Compile the route radix tree, validate relic dependency chains, and cache middleware onion pipelines at startup to eliminate runtime cold starts.
const app = new Tomoe()
// Compiles the routing tree. Called automatically on first request.
app.compile()
// Audit the registered routing structure
const { routes, stats } = app.graph()
console.log(`Audit complete: registered ${routes.length} active endpoints.`)TomoeJS interacts with standard request/response models directly, making it universally compatible across JS runtimes.
export default appLaunch with bun index.ts.
export default {
fetch: app.fetch
}Deno.serve((req) => app.fetch(req))import { createServer } from "tomoejs"
const server = createServer(app)
server.listen(3000)TomoeJS utilizes functional result mapping to minimize V8 call-stack serialization overhead, but fully supports standard throw-catch exceptions.
Includes BadRequest, Unauthorized, Forbidden, NotFound, MethodNotAllowed, Conflict, TooManyRequests, ServerError, and more.
import { HttpError, httpError } from "tomoejs"
// Simple helper
const TeapotError = httpError(418, "I'm a teapot")
// Rich Custom Error Details
const paymentErr = new HttpError(402, "Payment Failed", { reason: "INSUFFICIENT_FUNDS" })// Local scope override
app.scope("/api", authRelic, (scoped) => {
scoped.onError(401, (ctx) => {
return ctx.json({ error: "Access Denied: Please authenticate" }, { status: 401 })
})
})
// Global application fallback
app.onError((error, ctx) => {
console.error("Critical Exception:", error)
return ctx?.json({ error: "Internal Server Error" }, { status: 500 })
?? new Response("Internal Server Error", { status: 500 })
})Distributed under the MIT License. Built with 🌸 and perfect balance.
