{"id":49762051,"url":"https://github.com/celsianjs/celsian","last_synced_at":"2026-06-08T05:01:15.628Z","repository":{"id":340235510,"uuid":"1158974948","full_name":"CelsianJs/celsian","owner":"CelsianJs","description":"CelsianJS — Backend framework built on Web Standard APIs. Hook-based server, type-safe RPC, real-time streaming, caching, task queues. 590 tests.","archived":false,"fork":false,"pushed_at":"2026-06-08T03:48:32.000Z","size":1272,"stargazers_count":0,"open_issues_count":10,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-08T04:23:04.166Z","etag":null,"topics":["backend","framework","rpc","server","typescript","web-standards"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/celsian","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CelsianJs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":"AUDIT-2026-06-07.md","citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-16T06:38:32.000Z","updated_at":"2026-06-08T03:33:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/CelsianJs/celsian","commit_stats":null,"previous_names":["celsianjs/celsian"],"tags_count":191,"template":false,"template_full_name":null,"purl":"pkg:github/CelsianJs/celsian","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CelsianJs%2Fcelsian","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CelsianJs%2Fcelsian/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CelsianJs%2Fcelsian/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CelsianJs%2Fcelsian/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CelsianJs","download_url":"https://codeload.github.com/CelsianJs/celsian/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CelsianJs%2Fcelsian/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34048682,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backend","framework","rpc","server","typescript","web-standards"],"created_at":"2026-05-11T09:55:00.942Z","updated_at":"2026-06-08T05:01:15.620Z","avatar_url":"https://github.com/CelsianJs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CelsianJS\n\n[![npm version](https://img.shields.io/npm/v/celsian)](https://www.npmjs.com/package/celsian)\n[![license](https://img.shields.io/npm/l/celsian)](https://github.com/CelsianJs/celsian/blob/main/LICENSE)\n[![CI](https://img.shields.io/github/actions/workflow/status/CelsianJs/celsian/test.yml?branch=main\u0026label=tests)](https://github.com/CelsianJs/celsian/actions)\n\nTypeScript backend framework built on Web Standard APIs. Runs everywhere -- Node.js, Bun, Deno, Cloudflare Workers, AWS Lambda, Vercel.\n\n- **Multi-runtime** -- Write once, deploy to any JavaScript runtime. Built on `Request`/`Response`, not `req`/`res`.\n- **Significantly faster than Express** -- Radix-tree router, zero-copy request building, pre-stringified error paths. 1.3x-1.7x faster across all scenarios.\n- **Built-in everything** -- Background tasks, cron, WebSocket, CORS, CSRF protection, security headers, DB analytics, rate limiting, JWT, caching, compression, OpenAPI docs.\n- **Fastify-style plugin encapsulation** -- Scoped hooks and decorations by default. No accidental middleware leaks.\n- **Schema-agnostic validation** -- Auto-detects Zod, TypeBox, or Valibot. No config, no adapters.\n\n## Quick Start\n\n```bash\nnpx create-celsian my-api\ncd my-api\nnpm run dev\n```\n\nOr manually:\n\n```bash\nnpm install @celsian/core\n```\n\n```typescript\nimport { createApp, serve } from '@celsian/core';\n\nconst app = createApp({ logger: true });\n\n// ─── Background tasks with retries ───\napp.task({\n  name: 'sendWelcomeEmail',\n  retries: 3,\n  async handler(input: { to: string }) {\n    await sendEmail(input.to, 'Welcome!');\n  },\n});\n\n// ─── Cron job: clean up expired sessions every night ───\napp.cron('cleanup', '0 3 * * *', async () =\u003e {\n  await db.query('DELETE FROM sessions WHERE expires_at \u003c NOW()');\n});\n\n// ─── API routes ───\napp.post('/users', async (req, reply) =\u003e {\n  const body = req.parsedBody as { name: string; email: string };\n  const user = await db.createUser(body);\n  await app.enqueue('sendWelcomeEmail', { to: body.email });\n  return reply.status(201).json(user);\n});\n\napp.get('/users/:id', (req, reply) =\u003e {\n  return reply.json({ id: req.params.id, name: 'Alice' });\n});\n\nserve(app, { port: 3000 });\n```\n\nTasks, cron, and API routes in one file -- no separate worker process needed. On Bun or Deno, `serve()` auto-detects the runtime. No code changes needed.\n\n```bash\nbun run server.ts   # Uses Bun.serve() automatically\ndeno run server.ts  # Uses Deno.serve() automatically\n```\n\n## Why CelsianJS\n\n### Multi-Runtime\n\nBuilt on Web Standard `Request`/`Response` -- not Node.js `IncomingMessage`/`ServerResponse`. One adapter line deploys anywhere:\n\n```typescript\nexport default createCloudflareHandler(app);          // Cloudflare Workers\nexport const handler = createLambdaHandler(app);      // AWS Lambda\nexport default createVercelEdgeHandler(app);           // Vercel Edge\n```\n\n### Honest Benchmarks\n\nBenchmarked on Node.js v22, Apple Silicon, 10 connections for 10 seconds per scenario:\n\n| Scenario              | Fastify (req/s) | CelsianJS (req/s) | Express (req/s) |\n| --------------------- | ---------------: | -----------------: | --------------: |\n| JSON response         |           45,866 |             27,996 |          16,321 |\n| Route params          |           45,440 |             27,026 |          16,288 |\n| Middleware (5 layers)  |           41,380 |             24,445 |          15,751 |\n| JSON body parsing     |           29,998 |             19,074 |          14,648 |\n| Error handling        |           32,398 |             18,542 |          14,765 |\n\n**Fastify is faster.** It operates directly on Node.js internals with `fast-json-stringify` — hard to beat. CelsianJS pays a performance tax for Web Standard API compatibility (`Request`/`Response` object creation per request).\n\n**CelsianJS is 1.3-1.7x faster than Express** while shipping batteries that neither Fastify nor Express include: background task queues, cron scheduling, multi-runtime deployment, and DB analytics. If raw throughput is your only concern, use Fastify. If you need application infrastructure in a single framework, that's where CelsianJS fits.\n\n### Built-In Everything\n\nNo hunting for middleware packages:\n\n```typescript\nawait app.register(security(), { encapsulate: false });  // Helmet-style headers\nawait app.register(cors({ origin: 'https://myapp.com' }));\nawait app.register(csrf(), { encapsulate: false });      // CSRF token protection\nawait app.register(rateLimit({ max: 100, window: 60_000 }));\nawait app.register(compress());\nawait app.register(jwt({ secret: process.env.JWT_SECRET! }));\nawait app.register(openapi({ title: 'My API' }));\n\napp.health();                                             // /health + /ready\napp.task({ name: 'email', handler, retries: 3 });        // Background tasks\napp.cron('cleanup', '0 3 * * *', cleanupHandler);        // Cron jobs\napp.ws('/chat', { open, message, close });                // WebSocket\n```\n\n### Plugin Encapsulation\n\nPlugins get isolated scopes by default. Hooks and decorations registered inside a plugin do not leak to sibling plugins or the parent scope.\n\n```typescript\n// Auth plugin -- hooks only apply to routes registered inside\nasync function authPlugin(app) {\n  app.addHook('onRequest', async (req, reply) =\u003e {\n    const token = req.headers.get('authorization');\n    if (!token) return reply.unauthorized();\n  });\n\n  app.get('/me', (req, reply) =\u003e {\n    return reply.json({ user: req.user });\n  });\n}\n\n// Public routes -- no auth required\napp.get('/health', (req, reply) =\u003e reply.json({ status: 'ok' }));\n\n// Register auth plugin under /api prefix\nawait app.register(authPlugin, { prefix: '/api' });\n```\n\nUse `{ encapsulate: false }` when a plugin should affect all routes (e.g., CORS, database):\n\n```typescript\nawait app.register(cors(), { encapsulate: false });\n```\n\n### Type-Safe Schema Validation\n\nPass any Zod, TypeBox, or Valibot schema. CelsianJS auto-detects the library.\n\n```typescript\napp.route({\n  method: 'POST',\n  url: '/users',\n  schema: {\n    body: z.object({ name: z.string().min(1), email: z.string().email() }),\n  },\n  handler(req, reply) {\n    const { name, email } = req.parsedBody as { name: string; email: string };\n    return reply.status(201).json({ id: '1', name, email });\n  },\n});\n// Invalid input returns 400 with structured issues automatically\n```\n\n## Features at a Glance\n\n| Category | Features |\n| -------- | -------- |\n| **Routing** | Radix-tree router, params, wildcards, HEAD fallback, 405, route tagging |\n| **Hooks** | 8-hook lifecycle (onRequest through onResponse), route-level hooks |\n| **Plugins** | Scoped encapsulation, app/request/reply decorators |\n| **Validation** | Zod, TypeBox, Valibot auto-detect; body, querystring, params schemas |\n| **Reply** | json, html, stream, redirect, sendFile, download, cookies, 9 error helpers |\n| **Security** | Helmet-style headers, CORS, CSRF protection, JWT, fixed-window rate limiting |\n| **Background** | Task queue with retries, cron scheduling, Redis queue backend |\n| **Real-time** | WebSocket with broadcast and connection management |\n| **Database** | Connection pool plugin, transactions, query analytics, Server-Timing |\n| **Caching** | Response cache, session management (KV store) |\n| **Infra** | Compression, OpenAPI 3.1 + Swagger UI, structured logging, inject() testing |\n| **Deploy** | Node, Bun, Deno, Workers, Lambda, Vercel, Fly.io, Railway, graceful shutdown |\n\n## Core Concepts\n\n### Routes and Handlers\n\n```typescript\napp.get('/users/:id', (req, reply) =\u003e {\n  return reply.json({ id: req.params.id, include: req.query.include });\n});\n\n// Full route options with schema, hooks, and deployment tagging\napp.route({\n  method: 'POST',\n  url: '/items',\n  kind: 'serverless',\n  schema: { body: mySchema },\n  preHandler: [authHook],\n  handler(req, reply) { return reply.status(201).json(req.parsedBody); },\n});\n```\n\n### Hooks Lifecycle\n\n8 hooks run in order: `onRequest` \u003e `preParsing` \u003e `preValidation` \u003e `preHandler` \u003e `handler` \u003e `preSerialization` \u003e `onSend` \u003e `onResponse`. Plus `onError` for error handling. Any hook can short-circuit by returning a `Response`.\n\n```typescript\n// Global hook\napp.addHook('onRequest', async (req, reply) =\u003e {\n  reply.header('x-request-id', crypto.randomUUID());\n});\n\n// Route-level hook\napp.route({\n  method: 'POST',\n  url: '/admin/users',\n  onRequest: [requireAdmin],\n  handler(req, reply) { return reply.json({ created: true }); },\n});\n```\n\nSee [Hooks Lifecycle](docs/hooks.md) for the complete guide.\n\n### Reply Helpers\n\n```typescript\nreply.json({ data: [] });                            // JSON response\nreply.html('\u003ch1\u003eHello\u003c/h1\u003e');                         // HTML response\nreply.stream(readableStream);                         // Streaming\nreply.redirect('/new-path', 301);                     // Redirect\nawait reply.sendFile('/path/to/report.pdf');          // Serve file\nawait reply.download('/path/to/data.csv', 'export');  // Download\n\n// Structured error responses\nreply.notFound('User not found');     // 404\nreply.badRequest('Missing email');    // 400\nreply.unauthorized('Token expired');  // 401\nreply.forbidden();                    // 403\nreply.conflict();                     // 409\nreply.tooManyRequests();              // 429\n\n// Cookies + chaining\nreply.cookie('session', token, { httpOnly: true, secure: true });\nreturn reply.status(201).header('x-custom', 'value').json({ id: '1' });\n```\n\n### Error Handling\n\nThrown errors are caught and returned as structured JSON. Stack traces are stripped in production.\n\n```typescript\nimport { HttpError } from '@celsian/core';\n\n// Throw HTTP errors anywhere\nthrow new HttpError(403, 'Forbidden');\n// { \"error\": \"Forbidden\", \"statusCode\": 403, \"code\": \"FORBIDDEN\" }\n\n// Custom error handler\napp.setErrorHandler((error, req, reply) =\u003e {\n  if (error.message.includes('UNIQUE constraint')) return reply.conflict();\n  return reply.internalServerError();\n});\n```\n\n### Type-Safe RPC\n\n`@celsian/rpc` provides tRPC-style procedures with type inference, middleware, and OpenAPI generation.\n\n```typescript\n// server.ts\nimport { procedure, router, RPCHandler } from '@celsian/rpc';\n\nconst appRouter = router({\n  users: {\n    list: procedure\n      .input(z.object({ limit: z.number().optional() }))\n      .query(async ({ input }) =\u003e [{ id: '1', name: 'Alice' }]),\n    create: procedure\n      .input(z.object({ name: z.string(), email: z.string().email() }))\n      .mutation(async ({ input }) =\u003e ({ id: '2', ...input })),\n  },\n});\n\nconst rpc = new RPCHandler(appRouter);\napp.route({ method: ['GET', 'POST'], url: '/_rpc/*path', handler: (req) =\u003e rpc.handle(req) });\nexport type AppRouter = typeof appRouter;\n\n// client.ts\nconst client = createRPCClient\u003cAppRouter\u003e({ baseUrl: 'http://localhost:3000/_rpc' });\nconst users = await client.users.list.query({ limit: 10 });\nconst newUser = await client.users.create.mutate({ name: 'Bob', email: 'bob@example.com' });\n```\n\n## Try the Demo\n\nThe [SaaS Demo](examples/saas-demo/) builds a complete backend in one file (~250 lines): JWT auth, users CRUD, background tasks, cron, SSE, and OpenAPI docs.\n\n```bash\ncd examples/saas-demo\nnpm install\nnpx tsx src/index.ts\n```\n\nThen hit `http://localhost:3000/docs` for the Swagger UI, or:\n\n```bash\n# Register\ncurl -X POST http://localhost:3000/register \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"email\":\"alice@example.com\",\"password\":\"secret123\",\"name\":\"Alice\"}'\n\n# Login and grab the token\ncurl -X POST http://localhost:3000/login \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"email\":\"alice@example.com\",\"password\":\"secret123\"}'\n```\n\n## Ecosystem\n\n### Core Packages\n\n| Package | Description |\n| ------- | ----------- |\n| `@celsian/core` | Server runtime, routing, hooks, plugins, task queue, cron, WebSocket, CORS, security, database, OpenAPI |\n| `@celsian/schema` | Standard Schema adapters -- auto-detects Zod, TypeBox, Valibot |\n| `@celsian/rpc` | Type-safe RPC procedures, middleware, OpenAPI generation, typed client |\n| `@celsian/jwt` | JWT sign/verify plugin with route guard helper |\n| `@celsian/cache` | KV store, response caching, session management |\n| `@celsian/rate-limit` | Fixed-window rate limiter with pluggable store |\n| `@celsian/compress` | Response compression (gzip/deflate via CompressionStream) |\n| `@celsian/queue-redis` | Redis-backed task queue for production |\n\n### Deployment Adapters\n\n| Package | Target |\n| ------- | ------ |\n| `@celsian/adapter-cloudflare` | Cloudflare Workers (env bindings, execution context) |\n| `@celsian/adapter-lambda` | AWS Lambda + API Gateway v2 |\n| `@celsian/adapter-vercel` | Vercel Serverless + Edge Functions |\n| `@celsian/adapter-node` | Standalone Node.js server |\n| `@celsian/adapter-fly` | Fly.io (generates fly.toml, Dockerfile, multi-region) |\n| `@celsian/adapter-railway` | Railway (generates railway.json, Procfile) |\n\n### Tooling\n\n| Package | Description |\n| ------- | ----------- |\n| `create-celsian` | Project scaffolder (`npx create-celsian my-api`) |\n| `@celsian/cli` | Dev server, route listing, code generation |\n| `celsian` | Meta-package for single-import convenience |\n\n## Production Features\n\n### Graceful Shutdown\n\nOn SIGTERM/SIGINT: stops accepting connections, drains in-flight requests, stops workers and cron, runs cleanup.\n\n```typescript\nserve(app, {\n  shutdownTimeout: 15_000,\n  onShutdown: () =\u003e db.close(),\n});\n```\n\n### Health Checks and Route Manifest\n\n```typescript\napp.health({ check: () =\u003e pool.isHealthy() });  // /health + /ready\n\n// Tag routes for deployment tooling\napp.route({ method: 'GET', url: '/api/users', kind: 'serverless', handler });\napp.route({ method: 'GET', url: '/ws', kind: 'hot', handler });\nconst manifest = app.getRouteManifest(); // { serverless: [...], hot: [...], task: [...] }\n```\n\n### Database Analytics\n\nWrap your pool with `trackedPool()` for per-request query metrics, `Server-Timing` headers, and slow query logging -- zero handler changes. See [Database Plugin](docs/database.md).\n\n```typescript\nconst pool = trackedPool(pgPool);\nawait app.register(database({ createPool: () =\u003e pool }), { encapsulate: false });\nawait app.register(dbAnalytics({ slowThreshold: 100 }), { encapsulate: false });\n// Response: Server-Timing: db;dur=12.5;desc=\"3 queries\"\n```\n\n### Testing Without a Server\n\n```typescript\nconst response = await app.inject({ method: 'GET', url: '/hello' });\nconst body = await response.json();  // { hello: 'world' }\n```\n\n## Deployment\n\nSwap the entry point to deploy anywhere. See [Deployment Guide](docs/deployment.md) for full instructions.\n\n```typescript\nserve(app, { port: 3000 });                              // Node / Bun / Deno\n\nexport default createCloudflareHandler(app);              // Cloudflare Workers\nexport const handler = createLambdaHandler(app);          // AWS Lambda\nexport default createVercelHandler(app);                  // Vercel Serverless\nexport default createVercelEdgeHandler(app);              // Vercel Edge\n```\n\nFly.io and Railway adapters auto-generate deployment configs (fly.toml, Dockerfile, railway.json).\n\n## Benchmark Results\n\nNode.js v22.13.1, macOS Darwin (Apple Silicon), 10 connections, 10s per scenario.\n\n| Scenario              | Fastify (req/s) | CelsianJS (req/s) | Express (req/s) |\n| --------------------- | ---------------: | -----------------: | --------------: |\n| JSON response         |           45,866 |             27,996 |          16,321 |\n| Route params          |           45,440 |             27,026 |          16,288 |\n| Middleware (5)        |           41,380 |             24,445 |          15,751 |\n| JSON body parsing     |           29,998 |             19,074 |          14,648 |\n| Error handling        |           32,398 |             18,542 |          14,765 |\n\nFastify is the fastest Node.js framework. CelsianJS is 1.3-1.7x faster than Express. The gap with Fastify comes from Web Standard API overhead (`Request`/`Response` per request). CelsianJS trades some throughput for multi-runtime portability and built-in application infrastructure.\n\n## Configuration\n\nCelsianJS loads `celsian.config.ts` (or `.js`/`.mjs`) automatically:\n\n```typescript\nimport { defineConfig } from '@celsian/core';\n\nexport default defineConfig({\n  server: { port: 3000, host: 'localhost', trustProxy: true },\n  schema: { provider: 'auto' },  // or 'zod' | 'typebox' | 'valibot'\n});\n```\n\n## Documentation\n\n- [Quick Start Guide](docs/quickstart.md)\n- [Hooks Lifecycle](docs/hooks.md)\n- [Plugins and Encapsulation](docs/plugins.md)\n- [Deployment Guide](docs/deployment.md)\n- [Database Plugin](docs/database.md)\n\n## WhatStack\n\nCelsianJS is the backend half of [WhatStack](https://whatfw.com) — the agent-first full-stack framework:\n\n| Layer | Framework | What It Does |\n|-------|-----------|-------------|\n| Frontend | [WhatFW](https://whatfw.com) | Signals, fine-grained rendering, MCP DevTools |\n| Backend | **CelsianJS** | Hooks, plugins, tasks, cron, RPC, multi-runtime |\n| Deploy | Vura | Platform deployment (coming soon) |\n\n## Contributing\n\n```bash\ngit clone https://github.com/CelsianJs/celsian.git\ncd celsian\npnpm install\npnpm test\n```\n\nThe project uses pnpm workspaces. All packages are in `packages/`. Tests use Vitest.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcelsianjs%2Fcelsian","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcelsianjs%2Fcelsian","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcelsianjs%2Fcelsian/lists"}