@rudderjs/router 1.1.2 → 1.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.
- package/README.md +18 -0
- package/boost/guidelines.md +47 -0
- package/dist/binding-middleware.d.ts +54 -0
- package/dist/binding-middleware.d.ts.map +1 -0
- package/dist/binding-middleware.js +101 -0
- package/dist/binding-middleware.js.map +1 -0
- package/dist/index.d.ts +45 -139
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -314
- package/dist/index.js.map +1 -1
- package/dist/resource.d.ts +79 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/resource.js +104 -0
- package/dist/resource.js.map +1 -0
- package/dist/url-signing.d.ts +46 -0
- package/dist/url-signing.d.ts.map +1 -0
- package/dist/url-signing.js +133 -0
- package/dist/url-signing.js.map +1 -0
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -196,6 +196,23 @@ Returning `null` from `findForRoute` triggers `RouteModelNotFoundError` (HTTP 40
|
|
|
196
196
|
|
|
197
197
|
The `RouteResolver` contract is duck-typed — `name: string` + `findForRoute(value): unknown | Promise<unknown | null>` — so the router doesn't depend on `@rudderjs/orm`.
|
|
198
198
|
|
|
199
|
+
### Catch-all fallback with `router.fallback()`
|
|
200
|
+
|
|
201
|
+
Register a handler that runs when no other route matches — Laravel's `Route::fallback()`. Use it for custom 404 JSON shapes, vanity URL redirects, or a "soft" landing on api routes:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
router.fallback((_req, res) => res.status(404).json({
|
|
205
|
+
message: 'Endpoint not found',
|
|
206
|
+
}))
|
|
207
|
+
|
|
208
|
+
// Per-request middleware works too
|
|
209
|
+
router.fallback(handler, [LogUnknownRoute()])
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Only one fallback per router — registering a second one replaces the first. The fallback runs after every other matcher, including `router.all('/api/*', ...)`, so use it as the last-resort 404 path.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
199
216
|
### Custom 404 with `.missing()`
|
|
200
217
|
|
|
201
218
|
Override the default 404 response per route. Receives the request and the binding error; return a value the route handler may return — `Response`, plain object → JSON, string → body, or `undefined` (you wrote to `res` directly).
|
|
@@ -368,6 +385,7 @@ router.mount(serverAdapter)
|
|
|
368
385
|
| `use(middleware)` | `this` | Register global middleware |
|
|
369
386
|
| `bind(name, resolver, opts?)` | `this` | Bind a `:param` to a `RouteResolver` (e.g. an ORM Model) for auto-resolution |
|
|
370
387
|
| `listBindings()` | `Record<string, RouteResolver>` | All registered route bindings |
|
|
388
|
+
| `fallback(handler, mw?)` | `RouteBuilder` | Catch-all handler when no other route matches |
|
|
371
389
|
| `group(opts, fn)` | `this` | Apply prefix/domain/middleware to every route registered inside `fn` |
|
|
372
390
|
| `resource(name, Ctrl, opts?)` | `ResourceRegistration` | Register the seven canonical RESTful routes |
|
|
373
391
|
| `apiResource(name, Ctrl, opts?)` | `ResourceRegistration` | Resource minus `create`/`edit` |
|
package/boost/guidelines.md
CHANGED
|
@@ -75,6 +75,53 @@ router.get('/me', me).domain(':tenant.example.com')
|
|
|
75
75
|
|
|
76
76
|
Mismatched hosts return 404. Subdomain `:param` and path `:param` of the same name collide — path wins.
|
|
77
77
|
|
|
78
|
+
### Resource routes
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { router } from '@rudderjs/router'
|
|
82
|
+
|
|
83
|
+
// Full REST resource: index, create, store, show, edit, update, destroy
|
|
84
|
+
router.resource('posts', PostController)
|
|
85
|
+
|
|
86
|
+
// Subset
|
|
87
|
+
router.resource('posts', PostController, { only: ['index', 'show'] })
|
|
88
|
+
router.resource('posts', PostController, { except: ['destroy'] })
|
|
89
|
+
|
|
90
|
+
// API resource (no create/edit — those render HTML forms)
|
|
91
|
+
router.apiResource('posts', PostController)
|
|
92
|
+
|
|
93
|
+
// Singleton resource — only one of the thing (e.g. the current user's profile)
|
|
94
|
+
router.singleton('profile', ProfileController)
|
|
95
|
+
router.singleton('profile', ProfileController).creatable() // also registers create + store
|
|
96
|
+
router.singleton('profile', ProfileController).destroyable() // also registers destroy
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Generated route names follow `{resource}.{verb}` — e.g. `posts.index`, `posts.show`, `posts.store`. Use with `route('posts.show', { post: 42 })`.
|
|
100
|
+
|
|
101
|
+
### Route model binding
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { router } from '@rudderjs/router'
|
|
105
|
+
|
|
106
|
+
// Bind ':user' param to User model — auto-resolves req.bound.user from req.params.user
|
|
107
|
+
router.bind('user', User)
|
|
108
|
+
|
|
109
|
+
// Optional — resolves to null instead of 404 when not found
|
|
110
|
+
router.bind('viewer', User, { optional: true })
|
|
111
|
+
|
|
112
|
+
// Custom slug key — User.routeKey = 'slug' overrides the default 'id'
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The resolved model is available as `req.bound.user` in the handler. Missing records throw `RouteModelNotFoundError` (→ 404). Optional bindings skip the throw and set `req.bound.user = null`.
|
|
116
|
+
|
|
117
|
+
### Fallback route
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
router.fallback((_req, res) => res.status(404).json({ message: 'Not found' }))
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Catches all unmatched requests. Must be registered last.
|
|
124
|
+
|
|
78
125
|
### Route binding 404 customisation
|
|
79
126
|
|
|
80
127
|
```ts
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { MiddlewareHandler, RouteDefinition } from '@rudderjs/contracts';
|
|
2
|
+
/**
|
|
3
|
+
* Duck-typed contract for any object that resolves a string route parameter
|
|
4
|
+
* into a value (typically a Model instance, but the router doesn't depend on
|
|
5
|
+
* `@rudderjs/orm` — anything with a static `findForRoute` method works).
|
|
6
|
+
*
|
|
7
|
+
* Returning `null` signals "not found" — the router maps that to a thrown
|
|
8
|
+
* `RouteModelNotFoundError`, which the framework's HTTP layer renders as a 404.
|
|
9
|
+
*/
|
|
10
|
+
export interface RouteResolver {
|
|
11
|
+
/** Owning class name — used for error messages only. */
|
|
12
|
+
name: string;
|
|
13
|
+
/** Resolve the raw param value. Return `null` for not-found. */
|
|
14
|
+
findForRoute(value: string): Promise<unknown | null> | unknown | null;
|
|
15
|
+
}
|
|
16
|
+
export interface RouteBindingOptions {
|
|
17
|
+
/**
|
|
18
|
+
* When `true`, an absent or unresolvable param value silently sets
|
|
19
|
+
* `req.bound[name] = null` instead of throwing. Useful for shared routes
|
|
20
|
+
* that may or may not have a logged-in subject.
|
|
21
|
+
*/
|
|
22
|
+
optional?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** @internal — stored entry in `Router.bindings`. */
|
|
25
|
+
export interface RouteBinding {
|
|
26
|
+
resolver: RouteResolver;
|
|
27
|
+
optional: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Thrown by route binding middleware when a required `{param}` cannot be
|
|
31
|
+
* resolved into a model instance. `@rudderjs/core` picks up the duck-typed
|
|
32
|
+
* `httpStatus` and renders this as an HTTP 404; apps can catch it explicitly
|
|
33
|
+
* to render a custom not-found page.
|
|
34
|
+
*/
|
|
35
|
+
export declare class RouteModelNotFoundError extends Error {
|
|
36
|
+
readonly model: string;
|
|
37
|
+
readonly param: string;
|
|
38
|
+
readonly value: string;
|
|
39
|
+
/** Duck-typed signal to `@rudderjs/core`'s exception handler. */
|
|
40
|
+
readonly httpStatus = 404;
|
|
41
|
+
constructor(model: string, param: string, value: string);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build per-route binding middleware from the route's `{param}` segments and
|
|
45
|
+
* the router's binding map. Returns `null` when the route's path contains no
|
|
46
|
+
* bound params — callers skip installation in that case so unbound routes
|
|
47
|
+
* keep their original middleware chain.
|
|
48
|
+
*
|
|
49
|
+
* Takes the full `RouteDefinition` (not just `path`) so the closure can
|
|
50
|
+
* capture `def.missing` — the per-route 404 customisation set via
|
|
51
|
+
* `RouteBuilder.missing()`.
|
|
52
|
+
*/
|
|
53
|
+
export declare function buildBindingMiddleware(bindings: Map<string, RouteBinding>, def: RouteDefinition): MiddlewareHandler | null;
|
|
54
|
+
//# sourceMappingURL=binding-middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binding-middleware.d.ts","sourceRoot":"","sources":["../src/binding-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAK7E;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAA;IACZ,gEAAgE;IAChE,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,OAAO,GAAG,IAAI,CAAA;CACtE;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,aAAa,CAAA;IACvB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;;;;GAKG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IAEtB,iEAAiE;IACjE,QAAQ,CAAC,UAAU,OAAM;gBAEb,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAOxD;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EACnC,GAAG,EAAE,eAAe,GACnB,iBAAiB,GAAG,IAAI,CAuD1B"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { stripRegexSegments } from './index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by route binding middleware when a required `{param}` cannot be
|
|
4
|
+
* resolved into a model instance. `@rudderjs/core` picks up the duck-typed
|
|
5
|
+
* `httpStatus` and renders this as an HTTP 404; apps can catch it explicitly
|
|
6
|
+
* to render a custom not-found page.
|
|
7
|
+
*/
|
|
8
|
+
export class RouteModelNotFoundError extends Error {
|
|
9
|
+
model;
|
|
10
|
+
param;
|
|
11
|
+
value;
|
|
12
|
+
/** Duck-typed signal to `@rudderjs/core`'s exception handler. */
|
|
13
|
+
httpStatus = 404;
|
|
14
|
+
constructor(model, param, value) {
|
|
15
|
+
super(`[RudderJS] No ${model} matched route parameter "${param}" with value "${value}".`);
|
|
16
|
+
this.name = 'RouteModelNotFoundError';
|
|
17
|
+
this.model = model;
|
|
18
|
+
this.param = param;
|
|
19
|
+
this.value = value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build per-route binding middleware from the route's `{param}` segments and
|
|
24
|
+
* the router's binding map. Returns `null` when the route's path contains no
|
|
25
|
+
* bound params — callers skip installation in that case so unbound routes
|
|
26
|
+
* keep their original middleware chain.
|
|
27
|
+
*
|
|
28
|
+
* Takes the full `RouteDefinition` (not just `path`) so the closure can
|
|
29
|
+
* capture `def.missing` — the per-route 404 customisation set via
|
|
30
|
+
* `RouteBuilder.missing()`.
|
|
31
|
+
*/
|
|
32
|
+
export function buildBindingMiddleware(bindings, def) {
|
|
33
|
+
// Strip `{regex}` constraint segments from `where*()` before scanning for
|
|
34
|
+
// param names — otherwise a `:` inside a custom pattern could be misread
|
|
35
|
+
// as a route param. Uses balanced-brace stripping to support nested `{n}`
|
|
36
|
+
// quantifiers (e.g. UUID's `[0-9a-f]{8}-...`).
|
|
37
|
+
const stripped = stripRegexSegments(def.path);
|
|
38
|
+
const paramNames = [...stripped.matchAll(/:([a-zA-Z_][a-zA-Z0-9_]*)\??/g)].map(m => m[1]);
|
|
39
|
+
const matches = [];
|
|
40
|
+
for (const name of paramNames) {
|
|
41
|
+
const binding = bindings.get(name);
|
|
42
|
+
if (binding)
|
|
43
|
+
matches.push([name, binding]);
|
|
44
|
+
}
|
|
45
|
+
if (matches.length === 0)
|
|
46
|
+
return null;
|
|
47
|
+
return async (req, res, next) => {
|
|
48
|
+
// Lazy-init bound bag so handlers always see an object.
|
|
49
|
+
const bound = req.bound ?? {};
|
|
50
|
+
req.bound = bound;
|
|
51
|
+
for (const [name, binding] of matches) {
|
|
52
|
+
const raw = req.params[name];
|
|
53
|
+
let err = null;
|
|
54
|
+
if (raw === undefined || raw === '') {
|
|
55
|
+
if (binding.optional) {
|
|
56
|
+
bound[name] = null;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
err = new RouteModelNotFoundError(binding.resolver.name, name, '');
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
const resolved = await binding.resolver.findForRoute(raw);
|
|
63
|
+
if (resolved === null || resolved === undefined) {
|
|
64
|
+
if (binding.optional) {
|
|
65
|
+
bound[name] = null;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
err = new RouteModelNotFoundError(binding.resolver.name, name, raw);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
bound[name] = resolved;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (err) {
|
|
75
|
+
if (def.missing) {
|
|
76
|
+
// Route opted into a custom 404 — dispatch the result the same
|
|
77
|
+
// way registerRoute() handles a route handler's return value.
|
|
78
|
+
const result = await def.missing(req, err);
|
|
79
|
+
if (result instanceof Response) {
|
|
80
|
+
;
|
|
81
|
+
res.raw.res = result;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (typeof result === 'string') {
|
|
85
|
+
res.send(result);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (result !== undefined && result !== null) {
|
|
89
|
+
res.json(result);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// undefined → callback wrote to res directly; trust that.
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
throw err;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
await next();
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=binding-middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binding-middleware.js","sourceRoot":"","sources":["../src/binding-middleware.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
|
-
import type { ServerAdapter, RouteDefinition, RouteHandler, MiddlewareHandler, HttpMethod, RouteGroup
|
|
2
|
+
import type { ServerAdapter, RouteDefinition, RouteHandler, MiddlewareHandler, HttpMethod, RouteGroup } from '@rudderjs/contracts';
|
|
3
|
+
/**
|
|
4
|
+
* Tag every route registered while `fn` runs with `group` ('web' | 'api').
|
|
5
|
+
*
|
|
6
|
+
* **Synchronous bodies are the supported case.** Route loaders call
|
|
7
|
+
* `Route.get/post/...` at module-evaluation time — those calls complete
|
|
8
|
+
* before `fn` resolves, even when `fn` is `async`. The implementation
|
|
9
|
+
* supports an async `fn` (restoring the previous group in a `.finally()`),
|
|
10
|
+
* but two concurrent `runWithGroup` invocations on the same module instance
|
|
11
|
+
* will clobber each other: this is a single module-level variable, not an
|
|
12
|
+
* AsyncLocalStorage scope. Callers must run loaders **serially** — see
|
|
13
|
+
* `@rudderjs/core`'s `withRouting()` which sequentially `await`s each
|
|
14
|
+
* loader.
|
|
15
|
+
*
|
|
16
|
+
* Outside any `runWithGroup` scope, routes register without a group tag and
|
|
17
|
+
* receive only global `m.use(...)` middleware (no `m.web(...)` / `m.api(...)`
|
|
18
|
+
* stack).
|
|
19
|
+
*/
|
|
3
20
|
export declare function runWithGroup<R>(group: RouteGroup, fn: () => R | Promise<R>): R | Promise<R>;
|
|
21
|
+
/**
|
|
22
|
+
* Read the current group tag. Reads the module-level slot directly; returns
|
|
23
|
+
* `undefined` outside any `runWithGroup(...)` block. Called by route
|
|
24
|
+
* decorators to stamp each `RouteDefinition` with its group.
|
|
25
|
+
*/
|
|
4
26
|
export declare function currentGroup(): RouteGroup | undefined;
|
|
5
27
|
/** Mark a class as a controller with an optional route prefix */
|
|
6
28
|
export declare function Controller(prefix?: string): ClassDecorator;
|
|
@@ -12,6 +34,13 @@ export declare const Put: (path?: string) => MethodDecorator;
|
|
|
12
34
|
export declare const Patch: (path?: string) => MethodDecorator;
|
|
13
35
|
export declare const Delete: (path?: string) => MethodDecorator;
|
|
14
36
|
export declare const Options: (path?: string) => MethodDecorator;
|
|
37
|
+
/**
|
|
38
|
+
* Remove every balanced `{...}` block from a path. Used to peel off
|
|
39
|
+
* `where*()` regex constraint segments before scanning the path for `:param`
|
|
40
|
+
* names.
|
|
41
|
+
*/
|
|
42
|
+
/** @internal — exported so sibling modules (binding-middleware) can reuse. */
|
|
43
|
+
export declare function stripRegexSegments(path: string): string;
|
|
15
44
|
/** Matches one or more digits — `[0-9]+`. */
|
|
16
45
|
export declare const ROUTE_PATTERN_NUMBER = "[0-9]+";
|
|
17
46
|
/** Matches one or more ASCII letters — `[A-Za-z]+`. */
|
|
@@ -105,42 +134,9 @@ export interface RouteGroupOptions {
|
|
|
105
134
|
/** Middleware prepended to every route's chain (before per-route middleware). */
|
|
106
135
|
middleware?: MiddlewareHandler[];
|
|
107
136
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
* `@rudderjs/orm` — anything with a static `findForRoute` method works).
|
|
112
|
-
*
|
|
113
|
-
* Returning `null` signals "not found" — the router maps that to a thrown
|
|
114
|
-
* `RouteModelNotFoundError`, which the framework's HTTP layer renders as a 404.
|
|
115
|
-
*/
|
|
116
|
-
export interface RouteResolver {
|
|
117
|
-
/** Owning class name — used for error messages only. */
|
|
118
|
-
name: string;
|
|
119
|
-
/** Resolve the raw param value. Return `null` for not-found. */
|
|
120
|
-
findForRoute(value: string): Promise<unknown | null> | unknown | null;
|
|
121
|
-
}
|
|
122
|
-
export interface RouteBindingOptions {
|
|
123
|
-
/**
|
|
124
|
-
* When `true`, an absent or unresolvable param value silently sets
|
|
125
|
-
* `req.bound[name] = null` instead of throwing. Useful for shared routes
|
|
126
|
-
* that may or may not have a logged-in subject.
|
|
127
|
-
*/
|
|
128
|
-
optional?: boolean;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Thrown by route binding middleware when a required `{param}` cannot be
|
|
132
|
-
* resolved into a model instance. `@rudderjs/core` picks up the duck-typed
|
|
133
|
-
* `httpStatus` and renders this as an HTTP 404; apps can catch it explicitly
|
|
134
|
-
* to render a custom not-found page.
|
|
135
|
-
*/
|
|
136
|
-
export declare class RouteModelNotFoundError extends Error {
|
|
137
|
-
readonly model: string;
|
|
138
|
-
readonly param: string;
|
|
139
|
-
readonly value: string;
|
|
140
|
-
/** Duck-typed signal to `@rudderjs/core`'s exception handler. */
|
|
141
|
-
readonly httpStatus = 404;
|
|
142
|
-
constructor(model: string, param: string, value: string);
|
|
143
|
-
}
|
|
137
|
+
import { type RouteResolver, type RouteBindingOptions } from './binding-middleware.js';
|
|
138
|
+
export { RouteModelNotFoundError } from './binding-middleware.js';
|
|
139
|
+
export type { RouteResolver, RouteBindingOptions } from './binding-middleware.js';
|
|
144
140
|
export declare class Router {
|
|
145
141
|
private routes;
|
|
146
142
|
private globalMiddleware;
|
|
@@ -248,6 +244,14 @@ export declare class Router {
|
|
|
248
244
|
patch(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): RouteBuilder;
|
|
249
245
|
delete(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): RouteBuilder;
|
|
250
246
|
all(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): RouteBuilder;
|
|
247
|
+
/**
|
|
248
|
+
* Register a catch-all fallback route. Runs when no other route matches.
|
|
249
|
+
* Register it last — Hono evaluates routes in registration order.
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* router.fallback((_req, res) => res.status(404).json({ message: 'Not found' }))
|
|
253
|
+
*/
|
|
254
|
+
fallback(handler: RouteHandler, middleware?: MiddlewareHandler[]): RouteBuilder;
|
|
251
255
|
private _rb;
|
|
252
256
|
/** Register all routes from a decorator-based controller class. */
|
|
253
257
|
registerController(ControllerClass: new () => object): this;
|
|
@@ -300,63 +304,9 @@ export declare class Router {
|
|
|
300
304
|
/** @internal — shared registration loop for resource/apiResource/singleton. */
|
|
301
305
|
_registerResource(name: string, Ctrl: new () => object, table: readonly ResourceVerbSpec[], opts: ResourceOptions): ResourceRegistration;
|
|
302
306
|
}
|
|
303
|
-
|
|
304
|
-
export type ResourceVerb
|
|
305
|
-
|
|
306
|
-
verb: ResourceVerb;
|
|
307
|
-
method: HttpMethod;
|
|
308
|
-
path: (name: string, param: string) => string;
|
|
309
|
-
nameSuffix: string;
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Options accepted by `router.resource`/`apiResource`/`singleton`.
|
|
313
|
-
*
|
|
314
|
-
* - `only`/`except` — restrict the verbs registered.
|
|
315
|
-
* - `parameters` — override the `:param` segment name for a given resource
|
|
316
|
-
* (e.g. `{ posts: 'article' }` → `/posts/:article`).
|
|
317
|
-
* - `names` — override the generated route names per verb.
|
|
318
|
-
* - `middleware` — applied to every route registered by the resource.
|
|
319
|
-
*/
|
|
320
|
-
export interface ResourceOptions {
|
|
321
|
-
only?: readonly ResourceVerb[];
|
|
322
|
-
except?: readonly ResourceVerb[];
|
|
323
|
-
parameters?: Record<string, string>;
|
|
324
|
-
names?: Partial<Record<ResourceVerb, string>>;
|
|
325
|
-
middleware?: MiddlewareHandler[];
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* Returned by `router.resource()`/`apiResource()`. The `builders` array holds
|
|
329
|
-
* one `RouteBuilder` per registered route in declaration order — apply
|
|
330
|
-
* `where*()`, additional middleware, or rename individual routes by indexing
|
|
331
|
-
* directly. The `update` PATCH alias is included as a separate builder
|
|
332
|
-
* immediately after its PUT counterpart.
|
|
333
|
-
*/
|
|
334
|
-
export declare class ResourceRegistration {
|
|
335
|
-
readonly builders: RouteBuilder[];
|
|
336
|
-
constructor(builders: RouteBuilder[]);
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* Returned by `router.singleton()`. Adds two opt-in helpers on top of
|
|
340
|
-
* `ResourceRegistration` for resources that also expose a creation flow
|
|
341
|
-
* (`.creatable()`) or deletion flow (`.destroyable()`).
|
|
342
|
-
*/
|
|
343
|
-
export declare class SingletonRegistration extends ResourceRegistration {
|
|
344
|
-
private readonly _router;
|
|
345
|
-
private readonly _name;
|
|
346
|
-
private readonly _Ctrl;
|
|
347
|
-
private readonly _opts;
|
|
348
|
-
constructor(builders: RouteBuilder[], _router: Router, _name: string, _Ctrl: new () => object, _opts: ResourceOptions);
|
|
349
|
-
/**
|
|
350
|
-
* Add `GET /<name>/create` and `POST /<name>` — the create/store half of a
|
|
351
|
-
* full resource. Skipped for any verb the controller doesn't implement.
|
|
352
|
-
*/
|
|
353
|
-
creatable(): this;
|
|
354
|
-
/**
|
|
355
|
-
* Add `DELETE /<name>` — the destroy half of a full resource. Skipped if
|
|
356
|
-
* the controller doesn't implement `destroy()`.
|
|
357
|
-
*/
|
|
358
|
-
destroyable(): this;
|
|
359
|
-
}
|
|
307
|
+
import { ResourceRegistration, SingletonRegistration, type ResourceOptions, type ResourceVerbSpec } from './resource.js';
|
|
308
|
+
export type { ResourceVerb, ResourceOptions } from './resource.js';
|
|
309
|
+
export { ResourceRegistration, SingletonRegistration } from './resource.js';
|
|
360
310
|
export declare const router: Router;
|
|
361
311
|
/** Alias for router — Laravel-style capitalised name */
|
|
362
312
|
export declare const Route: Router;
|
|
@@ -372,49 +322,5 @@ export declare const Route: Router;
|
|
|
372
322
|
* route('search', { q: 'hello', page: 2 }) // '/search?q=hello&page=2'
|
|
373
323
|
*/
|
|
374
324
|
export declare function route(name: string, params?: Record<string, string | number>): string;
|
|
375
|
-
export
|
|
376
|
-
/**
|
|
377
|
-
* Override the HMAC signing key used for signed URLs.
|
|
378
|
-
* Falls back to `process.env.APP_KEY`.
|
|
379
|
-
*/
|
|
380
|
-
static setKey(key: string): void;
|
|
381
|
-
/** The full URL of the current request. */
|
|
382
|
-
static current(req: AppRequest): string;
|
|
383
|
-
/** The previous URL from the `Referer` header, or `fallback`. */
|
|
384
|
-
static previous(req: AppRequest, fallback?: string): string;
|
|
385
|
-
/**
|
|
386
|
-
* Generate a signed URL for a named route.
|
|
387
|
-
*
|
|
388
|
-
* @example
|
|
389
|
-
* Url.signedRoute('invoice.download', { id: 42 })
|
|
390
|
-
* // → '/invoice/42?signature=abc123'
|
|
391
|
-
*/
|
|
392
|
-
static signedRoute(name: string, params?: Record<string, string | number>, expiresAt?: Date): string;
|
|
393
|
-
/**
|
|
394
|
-
* Generate a signed URL that expires after `seconds` seconds.
|
|
395
|
-
*
|
|
396
|
-
* @example
|
|
397
|
-
* Url.temporarySignedRoute('invoice.download', 3600, { id: 42 })
|
|
398
|
-
* // → '/invoice/42?expires=1234567890&signature=abc123'
|
|
399
|
-
*/
|
|
400
|
-
static temporarySignedRoute(name: string, seconds: number, params?: Record<string, string | number>): string;
|
|
401
|
-
/**
|
|
402
|
-
* Sign an arbitrary path string.
|
|
403
|
-
* Appends `?signature=...` (and `?expires=...` if `expiresAt` given).
|
|
404
|
-
*/
|
|
405
|
-
static sign(path: string, expiresAt?: Date): string;
|
|
406
|
-
/**
|
|
407
|
-
* Return `true` if the request has a valid (and non-expired) signature.
|
|
408
|
-
*/
|
|
409
|
-
static isValidSignature(req: AppRequest): boolean;
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* Middleware that verifies a signed URL signature.
|
|
413
|
-
* Responds with 403 if the signature is missing, invalid, or expired.
|
|
414
|
-
*
|
|
415
|
-
* @example
|
|
416
|
-
* router.get('/invoice/:id/download', handler, [ValidateSignature()])
|
|
417
|
-
*/
|
|
418
|
-
export declare function ValidateSignature(): MiddlewareHandler;
|
|
419
|
-
export {};
|
|
325
|
+
export { Url, ValidateSignature } from './url-signing.js';
|
|
420
326
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|