-
The simplest, fastest, and most organized way to build production-ready servers with Bun.
We prefer to use
spacewith@solution-dist/serverfor a better experience.-
install
spacefirst.-
> space init <name> -t server # This will clone a ready-to-use repo and make some changes to suit your server. > cd <name> # Go to the project directory > space install # Install the dependencies
-
> space lint > space build > space test > space start
-
import { server } from '@je-es/server'; const app = server({ port : 3000, routes : [ { method : 'GET', path : '/', handler : (c) => c.json({ message: 'Hello World!' }) } ] }); await app.start();
> space start 16:16:31 Server started at http://localhost:3000 16:17:25 GET / 200 1ms ...
-
-
-
-
import { server } from '@je-es/server'; const app = server({ port : 3000, logging : { level: 'info', pretty: true }, routes : [ { method : 'GET', path : '/users/:id', handler : (c) => c.json({ userId : c.params.id, ip : c.ip, requestId : c.requestId }) }, { method : 'POST', path : '/users', handler : (c) => c.status(201).json({ created : true, data : c.body }) } ] }); await app.start();
-
import { server, table, integer, text, primaryKey, notNull } from '@je-es/server'; const users = table('users', [ primaryKey(integer('id'), true), notNull(text('name')), notNull(text('email')) ]); const app = server({ port : 3000, database : { connection : './app.db', schema : { users } }, routes: [ { method : 'GET', path : '/users', handler : (c) => c.json(c.db!.all('users')) }, { method : 'POST', path : '/users', handler : (c) => c.json(c.db!.insert('users', c.body)) }, { method : 'GET', path : '/users/:id', handler : (c) => { const user = c.db!.findById('users', parseInt(c.params.id)); return user ? c.json(user) : c.status(404).json({ error: 'Not found' }); } } ] }); await app.start();
-
const app = server({ port : 3000, security : { rateLimit : { max: 100, windowMs: 60000 }, cors : { origin : ['http://localhost:3000'], credentials : true } }, routes: [/* your routes */] });
-
const app = server({ port : 3000, static : { path : '/public', directory : './public', maxAge : 3600 } });
-
const app = server({ port : 3000, i18n : { defaultLanguage : 'en', supportedLanguages : ['en', 'ar', 'fr'], staticPath : 'static/i18n' }, routes: [ { method : 'GET', path : '/message', handler : (c) => { // Language auto-detected from ?lang=ar, Accept-Language header, or defaults to 'en' const greeting = c.i18n?.t('message.greeting', { name: 'John' }); return c.json({ greeting }); } } ] });
Translation files (
static/i18n/*.json):// en.json { "message.greeting": "Hello {name}" } // ar.json { "message.greeting": "مرحبا {name}" }
Key Features:
- Auto language detection from query params, headers, or defaults
- Smart parameter replacement with nested translation key support
- All supported languages loaded at server startup
- Works with any number of languages dynamically
-
-
-
import { server, type ServerConfig } from '@je-es/server'; const config: ServerConfig = { port : 3000, hostname : 'localhost', // Timeouts & Limits requestTimeout : 30000, maxRequestSize : 10485760, gracefulShutdownTimeout : 10000, // Logging (via @je-es/slog) logging: { level : 'info', // 'debug' | 'info' | 'warn' | 'error' pretty : false }, // Database (via @je-es/sdb) database: { connection : './app.db', // or ':memory:' schema : {} }, // Multiple databases database: [ { name: 'default', connection: './main.db' }, { name: 'cache', connection: ':memory:' } ], // Security security: { rateLimit : { max: 100, windowMs: 60000 }, cors : { origin: '*', credentials: true } }, // Static files static: { path : '/public', directory : './public', maxAge : 3600 }, // Lifecycle onStartup : async (app) => { console.log('Starting...'); }, onReady : async (app, db) => { console.log('Server ready with DB'); }, onShutdown : async () => { console.log('Shutting down...'); } };
-
handler : (c: AppContext) => { // Request c.params // URL parameters c.query // Query string c.body // Parsed body (JSON/form/multipart) c.headers // Request headers c.ip // Client IP c.requestId // Unique request ID // Resources c.db // Database instance c.logger // Logger instance // Response c.json({ data }) c.text('text') c.html('HTML') c.redirect('/path') c.file('./file.pdf', 'application/pdf') c.status(201).json({ created: true }) // Headers c.setHeader('X-Custom', 'value') c.getHeader('Authorization') // Cookies c.setCookie('session', 'token', { httpOnly: true }) c.getCookie('session') c.deleteCookie('session') }
-
// Single method { method : 'GET', path : '/users', handler } // Multiple methods { method : ['GET', 'POST'], path : '/api', handler } // Dynamic parameters { method : 'GET', path : '/users/:id', handler } { method : 'GET', path : '/posts/:postId/comments/:commentId', handler } // Wildcards { method : 'GET', path : '/files/*', handler }
-
// CRUD c.db!.all ('users') c.db!.findById ('users', 1) c.db!.find ('users', { role: 'admin' }) c.db!.insert ('users', { name: 'John' }) c.db!.update ('users', 1, { name: 'Jane' }) c.db!.delete ('users', 1) // Multiple databases const mainDb = app.db.get('default'); const cacheDb = app.db.get('cache');
-
await app.start(); // Add single route app.addRoute({ method : 'POST', path : '/dynamic', handler : (c) => c.json({ dynamic: true }) }); // Add multiple routes app.addRoutes([ { method : 'GET', path : '/route1', handler }, { method : 'GET', path : '/route2', handler } ]); // Get all routes const routes = app.getRoutes();
-
-
-
security: { rateLimit: { max : 100, windowMs : 60000, keyGenerator : (c) => c.ip, message : 'Too many requests' } }
-
security: { cors: { origin : ['http://localhost:3000'], // or: origin : '*', // or: origin : (origin) => origin.endsWith('.example.com'), methods : ['GET', 'POST', 'PUT', 'DELETE'], credentials : true } }
-
import { SecurityManager } from '@je-es/server'; const security = new SecurityManager(); security.sanitizeHtml('xss'); security.sanitizeSql("'; DROP TABLE users--");
-
const security = new SecurityManager(); const token = security.generateCsrfToken('session-id'); const valid = security.validateCsrfToken(token, 'session-id');
-
-
import { AppError, // Custom errors ValidationError, // 400 DatabaseError, // 500 TimeoutError, // 408 RateLimitError // 429 } from '@je-es/server'; handler : (c) => { if (!c.body?.email) { throw new ValidationError('Email required'); } if (invalid) { throw new AppError('Invalid data', 400, 'INVALID_DATA'); } return c.json({ success: true }); }
-
// Health check GET /health // Response: { status, timestamp, uptime, activeRequests } // Readiness check GET /readiness // Response: { ready, checks: { database, activeRequests }, timestamp }
-
-
c.setCookie('session', 'token', { maxAge : 3600, httpOnly : true, secure : true, sameSite : 'Strict', path : '/', domain : 'example.com' });
-
static: { path : '/public', directory : './public', maxAge : 3600, index : ['index.html'], dotfiles : 'deny', // 'allow' | 'deny' | 'ignore' etag : true, lastModified : true, immutable : false, extensions : ['html', 'htm'], setHeaders : (ctx, path) => { ctx.setHeader('X-Custom', 'value'); } }
-
const app = server({ gracefulShutdownTimeout: 10000, onStartup: async (app) => { // Initialize database, admin user, etc. console.log('✓ Server initialized'); }, onShutdown: async () => { // Cleanup console.log('Server shutting down gracefully...'); } }); process.on('SIGTERM', async () => { await app.stop(); process.exit(0); });
-
Use
onReadyto perform operations with the fully initialized server and databases. UnlikeonStartup,onReadyprovides access to database instances.const app = server({ database: { connection: './app.db', schema: { users } }, onReady: async (app, db) => { // Databases are now fully initialized const defaultDb = db.get('default'); // Seed initial data defaultDb?.insert('users', { name: 'Admin', email: 'admin@example.com' }); // Add routes dynamically app.addRoute({ method: 'GET', path: '/api/health', handler: (c) => c.json({ status: 'ok' }) }); console.log('✓ Database initialization complete'); } });
-
handler : (c) => { c.logger?.info( { userId: 123 }, 'User action'); c.logger?.warn( { attempt: 3 }, 'Warning'); c.logger?.error({ error: 'msg' }, 'Error'); }
-
-
import { server, table, integer, text, primaryKey, notNull } from '@je-es/server'; const users = table('users', [ primaryKey(integer('id'), true), notNull(text('name')), notNull(text('email')) ]); const app = server({ port : 3000, logging : { level: 'info', pretty: true }, database : { connection: './app.db', schema: { users } }, security : { rateLimit : { max: 100, windowMs: 60000 }, cors : { origin: ['http://localhost:3000'] } }, static : { path: '/public', directory: './public' }, routes : [ { method : 'GET', path : '/api/users', handler : (c) => c.json(c.db!.all('users')) }, { method : 'POST', path : '/api/users', handler : (c) => { if (!c.body?.name || !c.body?.email) { throw new ValidationError('Name and email required'); } const user = c.db!.insert('users', c.body); return c.status(201).json(user); } }, { method : 'GET', path : '/api/users/:id', handler : (c) => { const user = c.db!.findById('users', parseInt(c.params.id)); return user ? c.json(user) : c.status(404).json({ error: 'Not found' }); } } ] }); await app.start();
-
Notifications
You must be signed in to change notification settings - Fork 0
The simplest, fastest, and most organized way to build production-ready servers with Bun.
License
je-es/server
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
About
The simplest, fastest, and most organized way to build production-ready servers with Bun.

