Skip to content

litejs/server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LiteJS Server – Coverage Size Buy Me A Tea

A small, zero-dependency HTTP application core that runs the same code across Bun, Cloudflare Workers, Deno, Node.js, and on browser Service Worker.

Usage

npm install @litejs/server

// app.mjs
import { App } from "@litejs/server"

const app = App()

// Middlewares runs only if any route matches
app.use((req, env) => {
	// return a response to stop further execution
})

// Only single, first matching route get executed!
app.get('hello/world', (res, env) => 'Hello MOON!')
app.get('hello/{name}', (res, env) => 'Hello ' + req.param.name)
app.get('bye/{name}', (res, env) => 'Bye ' + req.param.name)
app.get('bye/moon', (res, env) => { /* Never executed as previous handler matches */ })
app.get('teapot', () => ({ body: "no coffee", status: 418 }))
app.get('notFound', () => 404) // Return a number to send status code

// Group routes and mount under a prefix
const subApp = App()
.post("", (req, env) => {
    // GET /api -> req.path == '/' and req.fullPath == '/api'
    return { data: [] }
})
.post("echo", async (req, env) => {
    // POST /api/echo -> req.path == '/echo' and req.fullPath == '/api/echo'
    return await req.json()
})

app.mount("api", subApp)

export default app

Handlers receive (req, env) and may return a string (sent as text/plain), a number (status only), an object (serialized to JSON), a { body, status, headers } object, or a native Response. Thrown errors map to err.code || 500.

Requests include param, path, fullPath, query, searchParams, and header(name).

Routes

  • user/{username} matches one path segment (no /)
  • post/{id+} matches one or more digits
  • files/{rest*}.ext matches all chars, greedy
  • a/{dir/}{name} matches zero or more slash-terminated directories
  • pub/\{x} matches the literal path pub/{x}

Adapters

The same app runs on every runtime. @litejs/server exports the matching adapter through conditional export, so the one file below runs unchanged on Node.js, Bun, and Deno.

// run.mjs
import {
    DB, KV, listen, loadEnv, serveStatic, setupShutdown
} from "@litejs/server"
import app from "./app.mjs"

const db = new DB("db.sqlite")
const env = loadEnv(".env.json", {
    ASSETS: serveStatic("public"),
    // Inject Cloudflare style KV on top of sqlite
    DEVICE: KV(db, "device"),
})
const server = listen(app, env)
app.get("/{path*}", env.ASSETS.fetch)

// Attach SIGINT/SIGTERM/SIGHUP/uncaughtException
setupShutdown([ server ])

Run it with node run.mjs, bun run.mjs, or deno run -A run.mjs.

Runtimes

  • Node.js, Bun, Deno: import from @litejs/server; the runtime is detected automatically.
  • Cloudflare Workers: import { worker } from "@litejs/server", then export default { fetch: worker(app) }.
  • Service Workers: import { listen } from "@litejs/server".

On Node, Bun, and Deno @litejs/server also exports serveStatic, loadEnv, setupShutdown, and SQLite-backed DB (D1) and KV shims.

Runnable examples are in test/server/.

Copyright (c) 2026 Lauri Rooden <lauri@rooden.ee>
MIT License | GitHub repo | npm package | Buy Me A Tea

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

 

Packages

 
 
 

Contributors

Languages