@rudderjs/router 0.2.0 → 0.2.1

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.
Files changed (2) hide show
  1. package/boost/guidelines.md +121 -0
  2. package/package.json +3 -2
@@ -0,0 +1,121 @@
1
+ # @rudderjs/router
2
+
3
+ ## Overview
4
+
5
+ Decorator-based and fluent HTTP router for RudderJS. Provides a global `router` singleton (alias: `Route`), named routes, URL generation via `route()`, HMAC-signed URLs via `Url`, route-level middleware, and decorator-based controllers (`@Controller`, `@Get`, `@Post`, etc.). The router is a peer of `@rudderjs/core` — core loads it at runtime via `resolveOptionalPeer` to avoid a dependency cycle.
6
+
7
+ ## Key Patterns
8
+
9
+ ### Fluent routes
10
+
11
+ ```ts
12
+ import { router, Route } from '@rudderjs/router'
13
+
14
+ Route.get('/api/health', (_req, res) => res.json({ status: 'ok' }))
15
+ Route.post('/api/users', async (req, res) => res.status(201).json(req.body))
16
+ Route.delete('/api/users/:id', handler)
17
+ Route.all('/api/*', (_req, res) => res.status(404).json({ message: 'Not found' })) // any method
18
+ ```
19
+
20
+ `router` and `Route` are the same global singleton.
21
+
22
+ ### Named routes + URL generation
23
+
24
+ ```ts
25
+ import { Route, route } from '@rudderjs/router'
26
+
27
+ Route.get('/users/:id', handler).name('users.show')
28
+ Route.post('/users', handler).name('users.store')
29
+
30
+ route('users.show', { id: 42 }) // '/users/42'
31
+ route('search', { q: 'hi', page: 2 }) // '/search?q=hi&page=2' (unused params → query string)
32
+ route('posts.show', { slug: 'hello' }) // optional ':id?' segment omitted
33
+ ```
34
+
35
+ Throws if a required parameter is missing or the name is not registered.
36
+
37
+ ### Route-level middleware
38
+
39
+ ```ts
40
+ Route.get('/protected', handler, [authMiddleware])
41
+ Route.post('/admin', handler, [authMiddleware, adminMiddleware])
42
+ ```
43
+
44
+ ### Decorator controllers
45
+
46
+ ```ts
47
+ import { Controller, Get, Post, Delete, Middleware, router } from '@rudderjs/router'
48
+
49
+ @Controller('/api/users')
50
+ @Middleware([authMiddleware]) // applies to all methods
51
+ class UserController {
52
+ @Get('/')
53
+ index(_req, res) { return res.json({ data: [] }) }
54
+
55
+ @Post('/')
56
+ async create(req, res) { return res.status(201).json({ data: req.body }) }
57
+
58
+ @Delete('/:id')
59
+ @Middleware([adminMiddleware]) // additional middleware on this method only
60
+ async destroy(req, res) { return res.status(204).send('') }
61
+ }
62
+
63
+ router.registerController(UserController)
64
+ ```
65
+
66
+ ### Signed URLs
67
+
68
+ ```ts
69
+ import { Url } from '@rudderjs/router'
70
+
71
+ Url.signedRoute('invoice.download', { id: 42 })
72
+ // '/invoice/42?signature=abc123...'
73
+
74
+ Url.temporarySignedRoute('invoice.download', 3600, { id: 42 })
75
+ // '/invoice/42?expires=...&signature=...'
76
+
77
+ Url.sign('/some/path?foo=bar') // sign arbitrary path
78
+ Url.isValidSignature(req) // validate on the receiving end
79
+ Url.current(req) // full URL of this request
80
+ Url.previous(req, '/') // Referer header or fallback
81
+ Url.setKey('override-key') // override APP_KEY (e.g. in tests)
82
+ ```
83
+
84
+ The signing key defaults to `APP_KEY`. HMAC-SHA256 with timing-safe comparison.
85
+
86
+ ### `ValidateSignature()` middleware
87
+
88
+ ```ts
89
+ import { ValidateSignature } from '@rudderjs/router'
90
+
91
+ Route.get('/invoice/:id/download', handler, [ValidateSignature()])
92
+ .name('invoice.download')
93
+ ```
94
+
95
+ Rejects requests with a missing / invalid / expired signature with a `403`.
96
+
97
+ ## Common Pitfalls
98
+
99
+ - **Circular dep if you add core to router**: `@rudderjs/core` is a **peer** dependency of router. Never add `@rudderjs/core` to router's `dependencies` or `devDependencies` — core resolves router at runtime via `resolveOptionalPeer('@rudderjs/router')`.
100
+ - **Missing `reflect-metadata`**: decorator controllers require `import 'reflect-metadata'` at the app entry point plus `experimentalDecorators: true` + `emitDecoratorMetadata: true` in tsconfig.
101
+ - **Controller URL must match the view**: if a controller returns `view('dashboard')` but the URL is `/admin/dashboard`, SPA nav falls back to full reloads. Add `export const route = '/admin/dashboard'` in the view file — see `@rudderjs/view`.
102
+ - **`APP_KEY` unset**: `Url.sign*()` throws unless `APP_KEY` is set or `Url.setKey()` is called first.
103
+ - **Named route not found**: `route('foo.bar')` throws if the name wasn't registered. Use `Route.get(...).name('foo.bar')` before the first call.
104
+ - **Double slashes**: composed paths (prefix + route) are normalised automatically — you don't need to strip leading slashes yourself.
105
+
106
+ ## Key Imports
107
+
108
+ ```ts
109
+ import {
110
+ router, // global singleton
111
+ Route, // alias for router
112
+ route, // URL generator for named routes
113
+ Url, // signed URLs (signedRoute, temporarySignedRoute, isValidSignature, current, previous)
114
+ ValidateSignature,// middleware
115
+ Controller, // decorator: class-level prefix
116
+ Middleware, // decorator: class or method-level middleware
117
+ Get, Post, Put, Patch, Delete, Options, // method decorators
118
+ } from '@rudderjs/router'
119
+
120
+ import type { RouteDefinition, RouteBuilder } from '@rudderjs/router'
121
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rudderjs/router",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -9,7 +9,8 @@
9
9
  },
10
10
  "type": "module",
11
11
  "files": [
12
- "dist"
12
+ "dist",
13
+ "boost"
13
14
  ],
14
15
  "main": "./dist/index.js",
15
16
  "types": "./dist/index.d.ts",