@rudderjs/router 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Suleiman Shahbari
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,220 @@
1
+ # @rudderjs/router
2
+
3
+ Decorator-based and fluent HTTP router for RudderJS. Supports named routes, URL generation, signed URLs, route-level middleware, and controller registration.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @rudderjs/router
9
+ ```
10
+
11
+ ---
12
+
13
+ ## Fluent routing
14
+
15
+ ```ts
16
+ import { router } from '@rudderjs/router'
17
+
18
+ router.get('/api/health', (_req, res) => res.json({ status: 'ok' }))
19
+ router.post('/api/users', async (req, res) => { /* ... */ })
20
+ router.delete('/api/users/:id', async (req, res) => { /* ... */ })
21
+
22
+ // Catch-all (matches any HTTP method)
23
+ router.all('/api/*', (_req, res) => res.status(404).json({ message: 'Not found' }))
24
+ ```
25
+
26
+ `router` is the global singleton. `Route` is an alias for it.
27
+
28
+ ---
29
+
30
+ ## Named routes
31
+
32
+ Chain `.name()` on any fluent route registration to assign a name:
33
+
34
+ ```ts
35
+ router.get('/users/:id', handler).name('users.show')
36
+ router.post('/users', handler).name('users.store')
37
+ router.get('/invoices/:id/download', handler, [ValidateSignature()]).name('invoice.download')
38
+ ```
39
+
40
+ ---
41
+
42
+ ## `route()` — URL generation
43
+
44
+ Generate a URL from a named route. Route parameters are substituted; unused params are appended as a query string.
45
+
46
+ ```ts
47
+ import { route } from '@rudderjs/router'
48
+
49
+ route('users.show', { id: 42 }) // '/users/42'
50
+ route('search', { q: 'hello', page: 2 }) // '/search?q=hello&page=2'
51
+ route('users.list') // '/users'
52
+ ```
53
+
54
+ Optional parameters (`:id?`) are omitted when not provided:
55
+
56
+ ```ts
57
+ // route defined as '/posts/:category?/:slug'
58
+ route('posts.show', { slug: 'hello' }) // '/posts/hello'
59
+ ```
60
+
61
+ Throws if a required parameter is missing or the named route is not defined.
62
+
63
+ ---
64
+
65
+ ## `Url` — signed URLs
66
+
67
+ Signed URLs include an HMAC-SHA256 `signature` parameter. The signing key is read from `APP_KEY` in your environment, or set explicitly with `Url.setKey()`.
68
+
69
+ ```ts
70
+ import { Url } from '@rudderjs/router'
71
+
72
+ // Sign a named route
73
+ Url.signedRoute('invoice.download', { id: 42 })
74
+ // → '/invoice/42?signature=abc123...'
75
+
76
+ // Sign with an expiry (seconds from now)
77
+ Url.temporarySignedRoute('invoice.download', 3600, { id: 42 })
78
+ // → '/invoice/42?expires=1234567890&signature=abc123...'
79
+
80
+ // Sign an arbitrary path
81
+ Url.sign('/some/path?foo=bar')
82
+
83
+ // Validate a request's signature
84
+ Url.isValidSignature(req) // → boolean
85
+
86
+ // Current URL and referer helpers
87
+ Url.current(req) // → req.url
88
+ Url.previous(req, '/') // → Referer header or fallback
89
+
90
+ // Override the signing key (e.g. in tests)
91
+ Url.setKey('my-secret-key')
92
+ ```
93
+
94
+ ---
95
+
96
+ ## `ValidateSignature()` middleware
97
+
98
+ Rejects requests with a missing, invalid, or expired URL signature with `403`.
99
+
100
+ ```ts
101
+ import { ValidateSignature } from '@rudderjs/router'
102
+
103
+ router.get('/invoice/:id/download', handler, [ValidateSignature()])
104
+ .name('invoice.download')
105
+ ```
106
+
107
+ ---
108
+
109
+ ## Decorator-based routing
110
+
111
+ ```ts
112
+ import { Controller, Get, Post, Delete, Middleware, router } from '@rudderjs/router'
113
+ import type { AppRequest, AppResponse } from '@rudderjs/contracts'
114
+
115
+ @Controller('/api/users')
116
+ @Middleware([authMiddleware]) // applies to all routes in this controller
117
+ class UserController {
118
+ @Get('/')
119
+ index(_req: AppRequest, res: AppResponse) {
120
+ return res.json({ data: [] })
121
+ }
122
+
123
+ @Post('/')
124
+ async create(req: AppRequest, res: AppResponse) {
125
+ return res.status(201).json({ data: req.body })
126
+ }
127
+
128
+ @Delete('/:id')
129
+ @Middleware([adminMiddleware]) // additional middleware for this route only
130
+ async destroy(req: AppRequest, res: AppResponse) {
131
+ return res.status(204).send('')
132
+ }
133
+ }
134
+
135
+ router.registerController(UserController)
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Route-level middleware (fluent)
141
+
142
+ ```ts
143
+ router.get('/protected', handler, [authMiddleware])
144
+ router.post('/admin', handler, [authMiddleware, adminMiddleware])
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Mounting onto a server adapter
150
+
151
+ ```ts
152
+ // bootstrap/app.ts — called automatically by Application.configure()
153
+ router.mount(serverAdapter)
154
+ ```
155
+
156
+ ---
157
+
158
+ ## API Reference
159
+
160
+ ### `Router`
161
+
162
+ | Method | Returns | Description |
163
+ |--------|---------|-------------|
164
+ | `get(path, handler, mw?)` | `RouteBuilder` | Register GET route |
165
+ | `post(path, handler, mw?)` | `RouteBuilder` | Register POST route |
166
+ | `put(path, handler, mw?)` | `RouteBuilder` | Register PUT route |
167
+ | `patch(path, handler, mw?)` | `RouteBuilder` | Register PATCH route |
168
+ | `delete(path, handler, mw?)` | `RouteBuilder` | Register DELETE route |
169
+ | `all(path, handler, mw?)` | `RouteBuilder` | Register route matching any method |
170
+ | `add(method, path, handler, mw?)` | `this` | Register route with explicit method |
171
+ | `use(middleware)` | `this` | Register global middleware |
172
+ | `registerController(Class)` | `this` | Register decorator-based controller |
173
+ | `mount(serverAdapter)` | `void` | Apply middleware + routes to adapter |
174
+ | `list()` | `RouteDefinition[]` | All registered routes |
175
+ | `listNamed()` | `Record<string, string>` | All named routes |
176
+ | `getNamedRoute(name)` | `string \| undefined` | Path for a named route |
177
+ | `reset()` | `this` | Clear routes, middleware, and named routes |
178
+
179
+ ### `RouteBuilder`
180
+
181
+ Returned by the shorthand route methods. Allows naming the registered route.
182
+
183
+ | Method | Description |
184
+ |--------|-------------|
185
+ | `.name(n)` | Assign a name to the route |
186
+
187
+ ### `Url`
188
+
189
+ | Method | Description |
190
+ |--------|-------------|
191
+ | `Url.setKey(key)` | Override the HMAC signing key |
192
+ | `Url.current(req)` | Full URL of the request |
193
+ | `Url.previous(req, fallback?)` | Referer header or fallback |
194
+ | `Url.signedRoute(name, params?, expiresAt?)` | Signed URL for a named route |
195
+ | `Url.temporarySignedRoute(name, seconds, params?)` | Expiring signed URL |
196
+ | `Url.sign(path, expiresAt?)` | Sign an arbitrary path |
197
+ | `Url.isValidSignature(req)` | Validate request signature |
198
+
199
+ ### Decorators
200
+
201
+ | Decorator | Target | Description |
202
+ |-----------|--------|-------------|
203
+ | `@Controller(prefix?)` | class | Marks class as a controller with a route prefix |
204
+ | `@Middleware([...handlers])` | class or method | Applies middleware handlers |
205
+ | `@Get(path)` | method | GET route |
206
+ | `@Post(path)` | method | POST route |
207
+ | `@Put(path)` | method | PUT route |
208
+ | `@Patch(path)` | method | PATCH route |
209
+ | `@Delete(path)` | method | DELETE route |
210
+ | `@Options(path)` | method | OPTIONS route |
211
+
212
+ ---
213
+
214
+ ## Notes
215
+
216
+ - `router` and `Route` are the same global singleton
217
+ - Decorator controllers require `reflect-metadata` at the app entry point
218
+ - Double slashes in composed paths are normalised automatically
219
+ - Signed URLs use HMAC-SHA256 with timing-safe comparison to prevent timing attacks
220
+ - `APP_KEY` must be set (or `Url.setKey()` called) before using signed URLs
@@ -0,0 +1,116 @@
1
+ import 'reflect-metadata';
2
+ import type { ServerAdapter, RouteDefinition, RouteHandler, MiddlewareHandler, HttpMethod, AppRequest } from '@rudderjs/contracts';
3
+ /** Mark a class as a controller with an optional route prefix */
4
+ export declare function Controller(prefix?: string): ClassDecorator;
5
+ /** Attach middleware to a controller class or route method */
6
+ export declare function Middleware(middleware: MiddlewareHandler[]): ClassDecorator & MethodDecorator;
7
+ export declare const Get: (path?: string) => MethodDecorator;
8
+ export declare const Post: (path?: string) => MethodDecorator;
9
+ export declare const Put: (path?: string) => MethodDecorator;
10
+ export declare const Patch: (path?: string) => MethodDecorator;
11
+ export declare const Delete: (path?: string) => MethodDecorator;
12
+ export declare const Options: (path?: string) => MethodDecorator;
13
+ /**
14
+ * Returned by `router.get/post/etc` — allows naming the registered route.
15
+ *
16
+ * @example
17
+ * router.get('/users/:id', handler).name('users.show')
18
+ * route('users.show', { id: 1 }) // → '/users/1'
19
+ */
20
+ export declare class RouteBuilder {
21
+ private readonly definition;
22
+ private readonly _router;
23
+ constructor(definition: RouteDefinition, _router: Router);
24
+ /** Assign a name to this route for use with `route()` and `Url.signedRoute()`. */
25
+ name(n: string): this;
26
+ }
27
+ export declare class Router {
28
+ private routes;
29
+ private globalMiddleware;
30
+ private namedRoutes;
31
+ /** @internal — called by RouteBuilder */
32
+ _registerName(name: string, path: string): void;
33
+ /** Look up a named route's path. */
34
+ getNamedRoute(name: string): string | undefined;
35
+ /** All registered named routes. */
36
+ listNamed(): Record<string, string>;
37
+ /** Clear registered routes, middleware, and named routes. */
38
+ reset(): this;
39
+ /** Register a global middleware (runs on every route). */
40
+ use(middleware: MiddlewareHandler): this;
41
+ /** Manually register a route. Returns `this` for bulk registration. */
42
+ add(method: HttpMethod, path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): this;
43
+ get(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): RouteBuilder;
44
+ post(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): RouteBuilder;
45
+ put(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): RouteBuilder;
46
+ patch(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): RouteBuilder;
47
+ delete(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): RouteBuilder;
48
+ all(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): RouteBuilder;
49
+ private _rb;
50
+ /** Register all routes from a decorator-based controller class. */
51
+ registerController(ControllerClass: new () => object): this;
52
+ /** Mount all routes onto a server adapter. */
53
+ mount(server: ServerAdapter): void;
54
+ /** All registered routes — useful for `routes:list`. */
55
+ list(): RouteDefinition[];
56
+ }
57
+ export declare const router: Router;
58
+ /** Alias for router — Laravel-style capitalised name */
59
+ export declare const Route: Router;
60
+ /**
61
+ * Generate a URL from a named route.
62
+ *
63
+ * - Route parameters (`:id`) are substituted from `params`.
64
+ * - Optional parameters (`:id?`) are omitted when not provided.
65
+ * - Unused params are appended as a query string.
66
+ *
67
+ * @example
68
+ * route('users.show', { id: 42 }) // '/users/42'
69
+ * route('search', { q: 'hello', page: 2 }) // '/search?q=hello&page=2'
70
+ */
71
+ export declare function route(name: string, params?: Record<string, string | number>): string;
72
+ export declare class Url {
73
+ /**
74
+ * Override the HMAC signing key used for signed URLs.
75
+ * Falls back to `process.env.APP_KEY`.
76
+ */
77
+ static setKey(key: string): void;
78
+ /** The full URL of the current request. */
79
+ static current(req: AppRequest): string;
80
+ /** The previous URL from the `Referer` header, or `fallback`. */
81
+ static previous(req: AppRequest, fallback?: string): string;
82
+ /**
83
+ * Generate a signed URL for a named route.
84
+ *
85
+ * @example
86
+ * Url.signedRoute('invoice.download', { id: 42 })
87
+ * // → '/invoice/42?signature=abc123'
88
+ */
89
+ static signedRoute(name: string, params?: Record<string, string | number>, expiresAt?: Date): string;
90
+ /**
91
+ * Generate a signed URL that expires after `seconds` seconds.
92
+ *
93
+ * @example
94
+ * Url.temporarySignedRoute('invoice.download', 3600, { id: 42 })
95
+ * // → '/invoice/42?expires=1234567890&signature=abc123'
96
+ */
97
+ static temporarySignedRoute(name: string, seconds: number, params?: Record<string, string | number>): string;
98
+ /**
99
+ * Sign an arbitrary path string.
100
+ * Appends `?signature=...` (and `?expires=...` if `expiresAt` given).
101
+ */
102
+ static sign(path: string, expiresAt?: Date): string;
103
+ /**
104
+ * Return `true` if the request has a valid (and non-expired) signature.
105
+ */
106
+ static isValidSignature(req: AppRequest): boolean;
107
+ }
108
+ /**
109
+ * Middleware that verifies a signed URL signature.
110
+ * Responds with 403 if the signature is missing, invalid, or expired.
111
+ *
112
+ * @example
113
+ * router.get('/invoice/:id/download', handler, [ValidateSignature()])
114
+ */
115
+ export declare function ValidateSignature(): MiddlewareHandler;
116
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,311 @@
1
+ import 'reflect-metadata';
2
+ // Lazy-load node:crypto to avoid bundling it into the client.
3
+ // Only used by Url (signed URLs) and ValidateSignature — server-only features.
4
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
+ let _crypto;
6
+ // Fire-and-forget: preload on server, no-op in browser
7
+ if (typeof globalThis.process !== 'undefined') {
8
+ import(/* @vite-ignore */ 'node:crypto').then(m => { _crypto = m; }).catch(() => { });
9
+ }
10
+ // ─── Metadata Keys ─────────────────────────────────────────
11
+ const CONTROLLER_PREFIX = 'rudderjs:controller:prefix';
12
+ const CONTROLLER_MIDDLEWARE = 'rudderjs:controller:middleware';
13
+ const ROUTE_DEFINITIONS = 'rudderjs:route:definitions';
14
+ const ROUTE_MIDDLEWARE = 'rudderjs:route:middleware';
15
+ // ─── Decorators ────────────────────────────────────────────
16
+ /** Mark a class as a controller with an optional route prefix */
17
+ export function Controller(prefix = '') {
18
+ return target => {
19
+ Reflect.defineMetadata(CONTROLLER_PREFIX, prefix, target);
20
+ };
21
+ }
22
+ /** Attach middleware to a controller class or route method */
23
+ export function Middleware(middleware) {
24
+ return (target, key) => {
25
+ if (key) {
26
+ // Method-level middleware (supports both decorator orders)
27
+ const perHandler = Reflect.getMetadata(ROUTE_MIDDLEWARE, target) ?? {};
28
+ const handlerKey = String(key);
29
+ perHandler[handlerKey] = [...(perHandler[handlerKey] ?? []), ...middleware];
30
+ Reflect.defineMetadata(ROUTE_MIDDLEWARE, perHandler, target);
31
+ // If route metadata already exists, merge immediately too.
32
+ const routes = Reflect.getMetadata(ROUTE_DEFINITIONS, target) ?? [];
33
+ const route = routes.find(r => r.handlerKey === key);
34
+ if (route)
35
+ route.middleware = [...middleware, ...route.middleware];
36
+ }
37
+ else {
38
+ // Class-level middleware
39
+ Reflect.defineMetadata(CONTROLLER_MIDDLEWARE, middleware, target);
40
+ }
41
+ };
42
+ }
43
+ /** Create an HTTP method decorator */
44
+ function createMethodDecorator(method) {
45
+ return (path = '/') => (target, key) => {
46
+ const perHandler = Reflect.getMetadata(ROUTE_MIDDLEWARE, target) ?? {};
47
+ const handlerMiddleware = perHandler[String(key)] ?? [];
48
+ const routes = Reflect.getMetadata(ROUTE_DEFINITIONS, target) ?? [];
49
+ routes.push({ method, path, handlerKey: key, middleware: [...handlerMiddleware] });
50
+ Reflect.defineMetadata(ROUTE_DEFINITIONS, routes, target);
51
+ };
52
+ }
53
+ export const Get = createMethodDecorator('GET');
54
+ export const Post = createMethodDecorator('POST');
55
+ export const Put = createMethodDecorator('PUT');
56
+ export const Patch = createMethodDecorator('PATCH');
57
+ export const Delete = createMethodDecorator('DELETE');
58
+ export const Options = createMethodDecorator('OPTIONS');
59
+ // ─── RouteBuilder ──────────────────────────────────────────
60
+ /**
61
+ * Returned by `router.get/post/etc` — allows naming the registered route.
62
+ *
63
+ * @example
64
+ * router.get('/users/:id', handler).name('users.show')
65
+ * route('users.show', { id: 1 }) // → '/users/1'
66
+ */
67
+ export class RouteBuilder {
68
+ definition;
69
+ _router;
70
+ constructor(definition, _router) {
71
+ this.definition = definition;
72
+ this._router = _router;
73
+ }
74
+ /** Assign a name to this route for use with `route()` and `Url.signedRoute()`. */
75
+ name(n) {
76
+ this._router._registerName(n, this.definition.path);
77
+ return this;
78
+ }
79
+ }
80
+ // ─── Router ────────────────────────────────────────────────
81
+ export class Router {
82
+ routes = [];
83
+ globalMiddleware = [];
84
+ namedRoutes = new Map();
85
+ /** @internal — called by RouteBuilder */
86
+ _registerName(name, path) {
87
+ this.namedRoutes.set(name, path);
88
+ }
89
+ /** Look up a named route's path. */
90
+ getNamedRoute(name) {
91
+ return this.namedRoutes.get(name);
92
+ }
93
+ /** All registered named routes. */
94
+ listNamed() {
95
+ return Object.fromEntries(this.namedRoutes);
96
+ }
97
+ /** Clear registered routes, middleware, and named routes. */
98
+ reset() {
99
+ this.routes = [];
100
+ this.globalMiddleware = [];
101
+ this.namedRoutes.clear();
102
+ return this;
103
+ }
104
+ /** Register a global middleware (runs on every route). */
105
+ use(middleware) {
106
+ this.globalMiddleware.push(middleware);
107
+ return this;
108
+ }
109
+ /** Manually register a route. Returns `this` for bulk registration. */
110
+ add(method, path, handler, middleware = []) {
111
+ this.routes.push({ method, path, handler, middleware });
112
+ return this;
113
+ }
114
+ // ── Shorthand methods — return RouteBuilder for .name() support ──
115
+ get(path, handler, middleware) { return this._rb('GET', path, handler, middleware); }
116
+ post(path, handler, middleware) { return this._rb('POST', path, handler, middleware); }
117
+ put(path, handler, middleware) { return this._rb('PUT', path, handler, middleware); }
118
+ patch(path, handler, middleware) { return this._rb('PATCH', path, handler, middleware); }
119
+ delete(path, handler, middleware) { return this._rb('DELETE', path, handler, middleware); }
120
+ all(path, handler, middleware) { return this._rb('ALL', path, handler, middleware); }
121
+ _rb(method, path, handler, middleware = []) {
122
+ const def = { method, path, handler, middleware };
123
+ this.routes.push(def);
124
+ return new RouteBuilder(def, this);
125
+ }
126
+ /** Register all routes from a decorator-based controller class. */
127
+ registerController(ControllerClass) {
128
+ const instance = new ControllerClass();
129
+ const prefix = Reflect.getMetadata(CONTROLLER_PREFIX, ControllerClass) ?? '';
130
+ const ctrlMw = Reflect.getMetadata(CONTROLLER_MIDDLEWARE, ControllerClass) ?? [];
131
+ const routes = Reflect.getMetadata(ROUTE_DEFINITIONS, ControllerClass.prototype) ?? [];
132
+ for (const route of routes) {
133
+ const fullPath = `${prefix}${route.path}`.replace(/\/+/g, '/');
134
+ const handler = instance[route.handlerKey].bind(instance);
135
+ this.routes.push({
136
+ method: route.method,
137
+ path: fullPath,
138
+ handler,
139
+ middleware: [...ctrlMw, ...route.middleware],
140
+ });
141
+ }
142
+ return this;
143
+ }
144
+ /** Mount all routes onto a server adapter. */
145
+ mount(server) {
146
+ for (const mw of this.globalMiddleware)
147
+ server.applyMiddleware(mw);
148
+ for (const route of this.routes)
149
+ server.registerRoute(route);
150
+ }
151
+ /** All registered routes — useful for `routes:list`. */
152
+ list() {
153
+ return [...this.routes];
154
+ }
155
+ }
156
+ // ─── Global router instance ────────────────────────────────
157
+ export const router = new Router();
158
+ /** Alias for router — Laravel-style capitalised name */
159
+ export const Route = router;
160
+ // ─── route() helper ────────────────────────────────────────
161
+ /**
162
+ * Generate a URL from a named route.
163
+ *
164
+ * - Route parameters (`:id`) are substituted from `params`.
165
+ * - Optional parameters (`:id?`) are omitted when not provided.
166
+ * - Unused params are appended as a query string.
167
+ *
168
+ * @example
169
+ * route('users.show', { id: 42 }) // '/users/42'
170
+ * route('search', { q: 'hello', page: 2 }) // '/search?q=hello&page=2'
171
+ */
172
+ export function route(name, params = {}) {
173
+ const path = router.getNamedRoute(name);
174
+ if (path === undefined)
175
+ throw new Error(`[RudderJS] Named route "${name}" is not defined.`);
176
+ const used = new Set();
177
+ let result = path.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\?)?/g, (_match, key, optional) => {
178
+ if (key in params) {
179
+ used.add(key);
180
+ return String(params[key]);
181
+ }
182
+ if (optional)
183
+ return '';
184
+ throw new Error(`[RudderJS] Missing required parameter "${key}" for route "${name}".`);
185
+ });
186
+ // Remove duplicate slashes that may appear when optional params are omitted
187
+ result = result.replace(/\/+/g, '/').replace(/\/$/, '') || '/';
188
+ // Remaining params → query string
189
+ const unused = Object.entries(params).filter(([k]) => !used.has(k));
190
+ if (unused.length > 0) {
191
+ const qs = new URLSearchParams(unused.map(([k, v]) => [k, String(v)])).toString();
192
+ result += (result.includes('?') ? '&' : '?') + qs;
193
+ }
194
+ return result;
195
+ }
196
+ // ─── Url ───────────────────────────────────────────────────
197
+ let _urlKey = '';
198
+ function _getSigningKey() {
199
+ const key = _urlKey || process.env['APP_KEY'] || '';
200
+ if (!key)
201
+ throw new Error('[RudderJS] No signing key configured. Set APP_KEY in your .env or call Url.setKey().');
202
+ return key;
203
+ }
204
+ function _splitPath(path) {
205
+ const idx = path.indexOf('?');
206
+ return idx === -1 ? [path, ''] : [path.slice(0, idx), path.slice(idx + 1)];
207
+ }
208
+ function _computeSignature(pathname, params) {
209
+ // Sort params for deterministic signing (exclude 'signature' itself)
210
+ const sorted = new URLSearchParams([...params.entries()]
211
+ .filter(([k]) => k !== 'signature')
212
+ .sort(([a], [b]) => a.localeCompare(b)));
213
+ const toSign = sorted.size > 0 ? `${pathname}?${sorted.toString()}` : pathname;
214
+ if (!_crypto)
215
+ throw new Error('[RudderJS Router] node:crypto not available — Url signing requires a server environment.');
216
+ return _crypto.createHmac('sha256', _getSigningKey()).update(toSign).digest('hex');
217
+ }
218
+ export class Url {
219
+ /**
220
+ * Override the HMAC signing key used for signed URLs.
221
+ * Falls back to `process.env.APP_KEY`.
222
+ */
223
+ static setKey(key) {
224
+ _urlKey = key;
225
+ }
226
+ /** The full URL of the current request. */
227
+ static current(req) {
228
+ return req.url;
229
+ }
230
+ /** The previous URL from the `Referer` header, or `fallback`. */
231
+ static previous(req, fallback = '/') {
232
+ return req.headers['referer'] ?? fallback;
233
+ }
234
+ /**
235
+ * Generate a signed URL for a named route.
236
+ *
237
+ * @example
238
+ * Url.signedRoute('invoice.download', { id: 42 })
239
+ * // → '/invoice/42?signature=abc123'
240
+ */
241
+ static signedRoute(name, params = {}, expiresAt) {
242
+ return Url.sign(route(name, params), expiresAt);
243
+ }
244
+ /**
245
+ * Generate a signed URL that expires after `seconds` seconds.
246
+ *
247
+ * @example
248
+ * Url.temporarySignedRoute('invoice.download', 3600, { id: 42 })
249
+ * // → '/invoice/42?expires=1234567890&signature=abc123'
250
+ */
251
+ static temporarySignedRoute(name, seconds, params = {}) {
252
+ return Url.signedRoute(name, params, new Date(Date.now() + seconds * 1000));
253
+ }
254
+ /**
255
+ * Sign an arbitrary path string.
256
+ * Appends `?signature=...` (and `?expires=...` if `expiresAt` given).
257
+ */
258
+ static sign(path, expiresAt) {
259
+ const [pathname, search] = _splitPath(path);
260
+ const params = new URLSearchParams(search);
261
+ if (expiresAt) {
262
+ params.set('expires', String(Math.floor(expiresAt.getTime() / 1000)));
263
+ }
264
+ const sig = _computeSignature(pathname, params);
265
+ params.set('signature', sig);
266
+ return `${pathname}?${params.toString()}`;
267
+ }
268
+ /**
269
+ * Return `true` if the request has a valid (and non-expired) signature.
270
+ */
271
+ static isValidSignature(req) {
272
+ const [pathname, search] = _splitPath(req.url);
273
+ const params = new URLSearchParams(search);
274
+ const signature = params.get('signature');
275
+ if (!signature)
276
+ return false;
277
+ // Check expiry before touching the signature
278
+ const expires = params.get('expires');
279
+ if (expires !== null) {
280
+ const expiry = parseInt(expires, 10);
281
+ if (isNaN(expiry) || Date.now() / 1000 > expiry)
282
+ return false;
283
+ }
284
+ const expected = _computeSignature(pathname, params);
285
+ try {
286
+ if (!_crypto)
287
+ return signature === expected;
288
+ return _crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
289
+ }
290
+ catch {
291
+ return false;
292
+ }
293
+ }
294
+ }
295
+ // ─── ValidateSignature middleware ───────────────────────────
296
+ /**
297
+ * Middleware that verifies a signed URL signature.
298
+ * Responds with 403 if the signature is missing, invalid, or expired.
299
+ *
300
+ * @example
301
+ * router.get('/invoice/:id/download', handler, [ValidateSignature()])
302
+ */
303
+ export function ValidateSignature() {
304
+ return async (req, res, next) => {
305
+ if (!Url.isValidSignature(req)) {
306
+ return res.status(403).json({ message: 'Invalid or expired URL signature.' });
307
+ }
308
+ await next();
309
+ };
310
+ }
311
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@rudderjs/router",
3
+ "version": "0.0.3",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/rudderjs/rudder",
8
+ "directory": "packages/router"
9
+ },
10
+ "type": "module",
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "import": "./dist/index.js",
19
+ "default": "./dist/index.js",
20
+ "types": "./dist/index.d.ts"
21
+ }
22
+ },
23
+ "dependencies": {
24
+ "reflect-metadata": "^0.2.2",
25
+ "@rudderjs/contracts": "0.0.3"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^20.0.0",
29
+ "@types/reflect-metadata": "^0.1.0",
30
+ "tsx": "^4.0.0",
31
+ "typescript": "^5.4.0"
32
+ },
33
+ "author": "Suleiman Shahbari",
34
+ "scripts": {
35
+ "build": "tsc -p tsconfig.build.json",
36
+ "dev": "tsc -p tsconfig.build.json --watch",
37
+ "typecheck": "tsc --noEmit",
38
+ "lint": "eslint src",
39
+ "clean": "rm -rf dist",
40
+ "test": "tsc -p tsconfig.test.json && node --test dist-test/index.test.js; EXIT=$?; rm -rf dist-test; exit $EXIT"
41
+ }
42
+ }