Skip to content

Repository files navigation

Tomoe Logo

TomoeJS — The Art of Perfect Balance.

GitHub StarsNPM VersionLicenseBun SupportWeb Standards

Ultra-Fast · Contract-Driven · Compile-Time Type Safety · Universal Web Standards Core


🌸 What is Tomoe?

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.


✨ Features at a Glance

  • 🛡️ 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 Request and Response.
  • 🔌 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.

📦 Installation

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@rc

🚀 Quick Start in 60 Seconds

Create an index.ts file to see TomoeJS in action:

import{Tomoe}from"tomoejs"constapp=newTomoe()// 1. Static responseapp.get("/",(c)=>c.text("Welcome to TomoeJS!"))// 2. Dynamic path parameters (automatically URL-decoded)app.get("/hello/:name",(c)=>{constname=c.param("name")// Automatically handles URL decoding (e.g. "%20" to " ")returnc.json({message: `Hello, ${name}!`})})exportdefaultapp

Run with Bun:

bun index.ts

Run with Node.js:

To use standard Node.js environments, use the built-in HTTP server adapter:

import{Tomoe,createServer}from"tomoejs"constapp=newTomoe()app.get("/",(c)=>c.text("Hello from Node.js!"))constserver=createServer(app)server.listen(3000,()=>{console.log("Server listening at http://localhost:3000")})

⚔️ The Problem: Traditional Middleware vs. The Tomoe Way

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)=>{constuser=c.get("user")// Typeless! Could be undefined if middleware failed or was skipped.returnc.json(user)})

The Tomoe Solution: Relics & Guards

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!returnctx.json(ctx.user)})

By resolving dependencies before invoking the route handler, TomoeJS guarantees compile-time safety and prevents runtime crashes caused by misordered middleware.


⚡ Performance Benchmarks

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.

Environment Details

  • Operating System: Windows 11
  • Node.js version: v24.13.0 | Bun version: v1.3.3
  • Frameworks Tested: TomoeJS v1.0.0-rc.3, Hono v4.12.23, Elysia v1.4.28

1. Static JSON Payload (/json)

FrameworkRequests / Sec (Throughput)Avg LatencyP99 Latency
TomoeJS (Bun)45,131 req/s1.58 ms5 ms
Hono (Bun)42,691 req/s1.91 ms4 ms
Elysia (Bun)41,987 req/s1.96 ms4 ms
Hono (Node)29,480 req/s2.92 ms7 ms
TomoeJS (Node)20,369 req/s4.41 ms11 ms

2. Radix Dynamic Routing (/user/:id/posts/:postId)

FrameworkRequests / Sec (Throughput)Avg LatencyP99 Latency
TomoeJS (Bun)45,853 req/s1.54 ms4 ms
Elysia (Bun)39,043 req/s2.21 ms4 ms
Hono (Bun)36,856 req/s2.30 ms4 ms
Hono (Node)29,067 req/s3.00 ms6 ms
TomoeJS (Node)22,600 req/s3.95 ms8 ms

3. Pre-Compiled Middleware Onion Pipeline (/protected)

FrameworkRequests / Sec (Throughput)Avg LatencyP99 Latency
Elysia (Bun)37,878 req/s2.29 ms4 ms
TomoeJS (Bun)33,573 req/s2.41 ms6 ms
Hono (Bun)31,886 req/s2.54 ms6 ms
Hono (Node)23,374 req/s3.76 ms8 ms
TomoeJS (Node)20,616 req/s4.37 ms9 ms

4. WebSocket Echo Message Roundtrip (/ws)

FrameworkMessages / Sec (Throughput)Avg LatencyP99 Latency
Elysia (Bun)45,535 msg/s0.43 msN/A
👑 TomoeJS (Node)45,448 msg/s0.42 msN/A
Hono (Bun)44,159 msg/s0.44 msN/A
Hono (Node)43,964 msg/s0.45 msN/A
TomoeJS (Bun)27,759 msg/s0.69 msN/A

🛠️ API Reference & Documentation

🛣️ Routing & Scopes

  1. Radix Tree Routing & Parameters
  2. Sub-routers & Prefix Scopes
  3. Custom & Built-in Middleware

📥 Request & Response Management

  1. Context API & Cookies
  2. Request Body & Payload Parsing

🛡️ Contracts & Validation

  1. Relics & Guards Contract System
  2. Schema Validation Relics

⚡ Real-Time, Tooling & Deployments

  1. Native WebSocket API
  2. End-to-End Type-Safe Client SDK
  3. OpenAPI Specs & Swagger UI
  4. Graph Compilation & Inspection
  5. Runtimes & Deployment Matrix
  6. Error Handling (Functional & Thrown)

1. Radix Tree Routing & Parameters

TomoeJS implements a high-performance radix tree router featuring dynamic path parameters, wildcard support, and fast paths for static routes.

constapp=newTomoe()// Static routeapp.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.paramsreturnctx.json({ userId, postId })})// Wildcard routesapp.get("/assets/*",(ctx)=>{constfilepath=ctx.param("*")returnctx.text(`Requested asset: ${filepath}`)})

2. Sub-routers & Prefix Scopes

Organize large projects cleanly using either standalone sub-routers or inline protected scope routes.

Option A: Mounted Sub-Routers (app.route)

Perfect for separating business domains into modular files:

import{Tomoe}from"tomoejs"constanimeRouter=newTomoe()animeRouter.get("/list",(c)=>c.json(["FMA","Hunter x Hunter"]))animeRouter.get("/:id",(c)=>c.json({id: c.param("id")}))constapp=newTomoe()app.route("/api/anime",animeRouter)// Mounted at `/api/anime/list` and `/api/anime/:id`

Option B: Inline Scope Groups (app.scope)

Enforce contract middleware on a group of nested routes:

app.scope("/admin",adminAccessRelics,(scoped)=>{scoped.get("/dashboard",(ctx)=>{// Access typed properties inherited from scope relicsreturnctx.json({user: ctx.user,org: ctx.org})})})

3. Custom & Built-in Middleware

Middlewares intercept incoming requests to manipulate context, handle telemetry, or manage CORS headers.

Custom Middleware Example

importtype{Middleware}from"tomoejs"constresponseTime=(): Middleware=>{returnasync(ctx,next)=>{conststart=performance.now()constresponse=awaitnext()constduration=(performance.now()-start).toFixed(2)response.headers.set("X-Response-Time",`${duration}ms`)returnresponse}}app.use(responseTime())

Built-in Production Middleware

import{cors,logger,csrf,rateLimit}from"tomoejs"// Cross-Origin Resource Sharingapp.use(cors({origin: ["https://example.com"]}))// Console Request Loggerapp.use(logger())// Cross-Site Request Forgery Protectionapp.use(csrf({origin: ["https://trusted.com"]}))// In-Memory Rate Limitingapp.use(rateLimit({windowMs: 60000,max: 100}))

4. Context API & Cookies

Handlers receive a unified Context object, providing helpers to parse inputs and construct Web Standard responses.

  • ctx.req: The native Web Request instance.
  • 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.

Cookie Management

TomoeJS provides an RFC 6265 secure, lazy-parsed cookie API:

app.get("/auth",(ctx)=>{// Read request cookieconsttoken=ctx.cookie("session_token")// Queue response cookiectx.setCookie("user_id","12345",{httpOnly: true,secure: true,sameSite: "Strict",maxAge: 3600})returnctx.json({loggedIn: !!token})})

5. Request Body & Payload Parsing

You can read payloads standardly or use Zod validations to safely parse incoming data.

Standard Parsing (Native Web APIs)

Ideal for stream-friendly handlers with zero allocations:

app.post("/upload",async(ctx)=>{constjsonBody=awaitctx.req.json()consttextBody=awaitctx.req.text()constformData=awaitctx.req.formData()// parses multipart uploadsconstarrayBuffer=awaitctx.req.arrayBuffer()returnctx.json({received: true})})

Contract-Driven Parsing (Relic-enforced)

Injects pre-validated bodies directly into ctx.body:

import{relic}from"tomoejs"import{z}from"zod"constuserSchema=z.object({username: z.string().min(3),email: z.string().email()})app.post("/register",relic.body(userSchema),(ctx)=>{// Autocomplete-ready and validated at runtimeconst{ username, email }=ctx.bodyreturnctx.json({status: "created", username })})

6. Relics & Guards Contract System

Create modular, chainable components to manage authentication, session state, or database connections.

  • Relics (relic): Compute values asynchronously and inject them into ctx.
  • 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'constauthenticateUser=relic("user",async(ctx)=>{consttoken=ctx.header("Authorization")if(!token)returnerr(Unauthorized)// Returns a structured functional errorconstuser=awaitdb.verifyToken(token)if(!user)returnerr(Unauthorized)returnuser})// 2. Create a guard that checks role requirementsconstcheckAdminRole=guard(async(ctx,use)=>{constuser=use(authenticateUser)// Resolve user dependency safelyif(!user.isAdmin)returnerr(Forbidden)})// 3. Chain them using unite()constadminAccess=unite(authenticateUser,checkAdminRole)// 4. Protect a scoped routing pathapp.scope("/admin",adminAccess,(router)=>{router.get("/metrics",(ctx)=>{// Both user validation and role authorization are guaranteed herereturnctx.json({activeUser: ctx.user.username,systemHealth: "ok"})})})

7. Schema Validation Relics

TomoeJS supports schema validation out of the box using Zod, Valibot, ArkType, or TypeBox.

import{z}from"zod"import{unite,relic}from"tomoejs"constitemBody=z.object({name: z.string()})constqueryPage=z.object({page: z.coerce.number().default(1)})app.post("/items",unite(relic.body(itemBody),relic.query(queryPage)),(ctx)=>{const{ name }=ctx.bodyconst{ page }=ctx.queryreturnctx.json({ name, page })})

8. Native WebSocket API

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"constapp=newTomoe()app.ws("/chat/:roomId",{// Protocol Handshake Hookhandshake(ctx){constrequestedProtocol=ctx.header("Sec-WebSocket-Protocol")if(requestedProtocol){ctx.header("Sec-WebSocket-Protocol",requestedProtocol)}},// Connection openedopen(ws,socketCtx){console.log(`Connected to room: ${socketCtx.params.roomId}`)ws.send(JSON.stringify({status: "connected"}))},// Message receivedmessage(ws,data,socketCtx){ws.send(JSON.stringify({echo: data}))},// Connection closedclose(ws,socketCtx){console.log(`Disconnected from room: ${socketCtx.params.roomId}`)}})// Secure WebSocket routes using Relicsapp.ws("/secure-feed",authRelic,{open(ws,socketCtx){constuser=socketCtx.relics.userws.send(`Hello secure user, ${user.name}!`)}})constserver=createServer(app)server.listen(3000)

9. End-to-End Type-Safe Client SDK

Share type definitions directly from your backend instance to your frontend to generate a type-safe client SDK without external code generation.

Server Setup (server.ts):

constapp=newTomoe().post("/posts",relic.body(postSchema),(ctx)=>{returnctx.json({id: "100"})})exporttypeAppRouter=typeofapp

Frontend Consumer (client.ts):

import{createClient}from"tomoejs"importtype{AppRouter}from"./server"constclient=createClient<AppRouter>("http://localhost:3000")// Inputs (body, params, headers, query) are validated at compile-time!const{ data, error, status }=awaitclient("/posts").post({body: {title: "Next-Gen Web Frameworks",content: "..."}})

10. OpenAPI Specs & Swagger UI

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"constapp=newTomoe()// Setup docs endpointswagger(app,{title: "TomoeJS Core Services",version: "1.0.0",path: "/docs",// Swagger UI endpointspecPath: "/openapi.json"// OpenAPI Spec endpoint})

11. Graph Compilation & Inspection

Compile the route radix tree, validate relic dependency chains, and cache middleware onion pipelines at startup to eliminate runtime cold starts.

constapp=newTomoe()// Compiles the routing tree. Called automatically on first request.app.compile()// Audit the registered routing structureconst{ routes, stats }=app.graph()console.log(`Audit complete: registered ${routes.length} active endpoints.`)

12. Runtimes & Deployment Matrix

TomoeJS interacts with standard request/response models directly, making it universally compatible across JS runtimes.

Bun (Recommended for maximum speed)

exportdefaultapp

Launch with bun index.ts.

Cloudflare Workers

exportdefault{fetch: app.fetch}

Deno

Deno.serve((req)=>app.fetch(req))

Node.js

import{createServer}from"tomoejs"constserver=createServer(app)server.listen(3000)

13. Error Handling (Functional & Thrown)

TomoeJS utilizes functional result mapping to minimize V8 call-stack serialization overhead, but fully supports standard throw-catch exceptions.

Standard Pre-built Errors

Includes BadRequest, Unauthorized, Forbidden, NotFound, MethodNotAllowed, Conflict, TooManyRequests, ServerError, and more.

Custom Errors

import{HttpError,httpError}from"tomoejs"// Simple helperconstTeapotError=httpError(418,"I'm a teapot")// Rich Custom Error DetailsconstpaymentErr=newHttpError(402,"Payment Failed",{reason: "INSUFFICIENT_FUNDS"})

Scoped & Global Error Interceptors

// Local scope overrideapp.scope("/api",authRelic,(scoped)=>{scoped.onError(401,(ctx)=>{returnctx.json({error: "Access Denied: Please authenticate"},{status: 401})})})// Global application fallbackapp.onError((error,ctx)=>{console.error("Critical Exception:",error)returnctx?.json({error: "Internal Server Error"},{status: 500})??newResponse("Internal Server Error",{status: 500})})

📄 License

Distributed under the MIT License. Built with 🌸 and perfect balance.

About

Tomoe — The art of perfect balance

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages