@currentjs/router
v0.1.3
Published
Lightweight decorator-based HTTP/HTTPS server with routing,JWT authentication, and static files serving for @currentjs generated apps.
Downloads
140
Maintainers
Readme
@currentjs/router 🚀
A surprisingly capable HTTP router designed to be the backbone of the
currentjsframework ecosystem. Mostly vibe-coded with Claude 4 Sonnet, because... why not?
What Is This Thing? 🤔
This is a decorator-based HTTP/HTTPS server that can handle APIs, serve static files, render templates, and even pretend to be a SPA framework. It's designed to be the routing backbone for apps generated by the currentjs framework and works best within that ecosystem.
Key Philosophy: Zero external dependencies, maximum vibes. We only use Node.js built-ins because we're rebels like that.
Installation 📦
Using @currentjs/gen (Code Generator) - Recommended
# No manual installation needed
# The router is automatically included when you generate a project
currentjs create app my-app(for more details see the documentation)
Manual Installation - For standalone use
npm i @currentjs/router💡 Pro Tip: If you're using the
currentjscode generator, you probably don't need to install this manually. The code generator (@currentjs/gen) will handle all the setup for you automatically!
Features That Actually Work ✨
- 🎭 Decorators:
@Get,@Post,@Put,@Patch,@Delete,@Render,@Controller - 🔀 Dynamic routing: Path parameters like
/users/:id(because who has time to hardcode everything?) - 🔐 JWT Authentication: Built-in JWT parsing and user context (HS256, because we're not animals)
- 📁 Static file serving: With path traversal protection (security matters, kids)
- 🎨 Template rendering: SSR support with layouts and partial content for SPAs
- 🔒 HTTPS support: Because it's 2025 and HTTP is so last decade
- ⚡ Zero dependencies: Just Node.js and good vibes
Quick Start (The "I Just Want It To Work" Guide) 🏃♂️
import { Get, Post, Controller, createWebServer } from '@currentjs/router';
import type { IContext } from '@currentjs/router';
@Controller('/api/posts')
class PostController {
@Get('/:id')
async getPost(ctx: IContext) {
const id = ctx.request.parameters.id;
return { id, title: 'Hello World', author: 'Claude' };
}
@Post('/')
async createPost(ctx: IContext) {
// Access the authenticated user (if JWT token provided)
const user = ctx.request.user;
return {
ok: true,
received: ctx.request.body,
createdBy: user?.email || 'anonymous'
};
}
}
const server = createWebServer({
controllers: [new PostController()],
webDir: './public' // Optional: serve static files too
});
server.listen(3000);
console.log('🚀 Server running on http://localhost:3000');Decorators (The Magic Spells) 🪄
HTTP Method Decorators
@Get('/path') // GET requests
@Post('/path') // POST requests
@Put('/path') // PUT requests
@Patch('/path') // PATCH requests
@Delete('/path') // DELETE requestsController Decorator
@Controller('/api/v1') // Base path for all routes in this controller
class MyController {
@Get('/hello') // Becomes GET /api/v1/hello
sayHello() { return { message: 'Hi!' }; }
}Render Decorator (For the Template Lovers)
@Controller('/')
class PageController {
@Get('/dashboard')
@Render('dashboard.html', 'layout.html') // template, optional layout
async dashboard(ctx: IContext) {
return {
title: 'Dashboard',
user: ctx.request.user,
data: await getSomeData()
};
}
}Path Parameters (Because Dynamic Is Better) 🛣️
@Get('/users/:userId/posts/:postId')
async getUserPost(ctx: IContext) {
const { userId, postId } = ctx.request.parameters;
// Query params are also in parameters!
const { limit, offset } = ctx.request.parameters;
return { userId, postId, limit, offset };
}Authentication (JWT Magic) 🔐
Just include a JWT token in the Authorization header and we'll parse it for you:
// Request header: Authorization: Bearer your.jwt.token
@Get('/profile')
async getProfile(ctx: IContext) {
const user = ctx.request.user; // Parsed from JWT
if (!user) {
throw new Error('Authentication required');
}
return {
id: user.id,
email: user.email,
role: user.role
};
}JWT Requirements:
- Algorithm: HS256
- Secret: Set
JWT_SECRETenvironment variable - Standard claims:
id(orsub),role,email
Template Rendering (SSR in 2025? Bold!) 🎨
When you provide a renderer function, routes with @Render will return HTML:
import { createWebServer } from '@currentjs/router';
import { TemplateEngine } from '@currentjs/templating'; // Recommended!
const templateEngine = new TemplateEngine('./templates');
const server = createWebServer({
controllers: [new PageController()],
webDir: './public'
}, {
renderer: async (template, data, layout) => {
const content = await templateEngine.render(template, data);
if (layout) {
return await templateEngine.render(layout, { ...data, content });
}
return content;
},
errorTemplate: 'error.html' // Optional error page template
});Pro Tip: While you can use any template engine, this router is optimized for @currentjs/templating which provides powerful features like component composition, conditional rendering, and seamless SPA support.
SPA Support: The router detects X-Partial-Content: true headers and skips the layout for seamless SPA navigation.
Static File Serving (Because Someone Has to Serve Those Cat GIFs) 📁
const server = createWebServer({
controllers: [new ApiController()],
webDir: './public' // Serves static files from this directory
}, {
indexFiles: ['index.html', 'index.htm'] // Default files for directories
});Security Features:
- Path traversal protection (no
../../../etc/passwdnonsense) - Proper MIME type detection
- Directory index file serving
HTTPS (Because Security) 🔒
import fs from 'fs';
const server = createWebServer({
controllers: [new SecureController()]
}, {
https: {
key: fs.readFileSync('./server.key'),
cert: fs.readFileSync('./server.crt')
}
});
server.listen(3443); // Traditional HTTPS portContext Object (Your Window to the Request) 📦
Every route handler receives a context object with everything you need:
interface IContext {
request: {
url: string; // Original URL
path: string; // Normalized path
method: string; // HTTP method
parameters: Record<string, string | number>; // Path params + query params
body: any; // Parsed JSON or raw string
headers: Record<string, string | string[]>; // Request headers
user?: AuthenticatedUser; // Parsed JWT user (if authenticated)
};
response: Record<string, any>; // For future response customization
}Return Values (What You Give Is What You Get) 📤
- Objects/Arrays: Automatically serialized to JSON with
application/jsoncontent type - Strings: Sent as
text/plain; charset=utf-8 - Template routes: Rendered as HTML when using
@Renderdecorator
Advanced Configuration 🔧
const server = createWebServer({
controllers: [controller1, controller2],
webDir: './public'
}, {
port: 3000,
host: '0.0.0.0',
https: false, // or { key: Buffer, cert: Buffer }
renderer: myTemplateRenderer,
staticDir: './assets', // Override webDir for static files
indexFiles: ['index.html', 'home.html'],
errorTemplate: 'error.html'
});Part of a Bigger Picture 🌍
This router is designed as the HTTP layer for the currentjs code generation framework. It's built to work seamlessly with generated controllers, services, domain models, and especially with @currentjs/templating for rendering. Think of it as the networking hub that connects all the generated pieces together.
Vibe Engineering 🎵
This package was primarily developed through conversations with Claude 4 Sonnet, which explains why the code feels like it was written by someone who actually enjoys programming. The result is a router that's both functional and surprisingly pleasant to use.
Authorship & contribution
Vibecoded with claude-4-sonnet (mostly) by Konstantin Zavalny. Yes, it is a vibecoded solution, really.
Any contributions such as bugfixes, improvements, etc are very welcome.
License
GNU Lesser General Public License (LGPL)
It simply means, that you:
- can create a proprietary application that uses this library without having to open source their entire application code (this is the "lesser" aspect of LGPL compared to GPL).
- can make any modifications, but must distribute those modifications under the LGPL (or a compatible license) and include the original copyright and license notice.
