@web-ts-toolkit/express-json-router 0.43.0 → 0.44.0
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 +75 -0
- package/index.d.mts +50 -11
- package/index.d.ts +50 -11
- package/index.js +40 -1
- package/index.mjs +40 -1
- package/llms.txt +4 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -89,6 +89,7 @@ These behave as defaults for future `new JsonRouter(...)` instances.
|
|
|
89
89
|
- Updating a static property affects routers created after that change.
|
|
90
90
|
- Existing routers keep the response-handler instance they were constructed with.
|
|
91
91
|
- `JsonRouter.defaultHandler` returns a newly configured handler each time it is read.
|
|
92
|
+
- Mutating a handler retrieved via `JsonRouter.defaultHandler` does not reconfigure existing routers or future defaults.
|
|
92
93
|
- For fully isolated behavior, pass an explicit handler instance as the third constructor argument.
|
|
93
94
|
|
|
94
95
|
```ts
|
|
@@ -107,6 +108,80 @@ handler.errorMessageProvider = () => 'custom-error';
|
|
|
107
108
|
const routerUsingCustomHandler = new JsonRouter('/admin', undefined, handler);
|
|
108
109
|
```
|
|
109
110
|
|
|
111
|
+
## Native Middleware And Error Boundaries
|
|
112
|
+
|
|
113
|
+
Thrown or rejected JSON callbacks are JSON-formatted by the router's response
|
|
114
|
+
handler and never reach application error middleware. Explicit `next(error)`
|
|
115
|
+
instead delegates to native Express error middleware, which owns the response:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import express from 'express';
|
|
119
|
+
import JsonRouter from '@web-ts-toolkit/express-json-router';
|
|
120
|
+
|
|
121
|
+
const app = express();
|
|
122
|
+
const router = new JsonRouter('/api');
|
|
123
|
+
|
|
124
|
+
router.get('/throw', () => {
|
|
125
|
+
throw new Error('formatted as a JSON 500 by the router');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
router.get(
|
|
129
|
+
'/guarded',
|
|
130
|
+
(req, res, next) => {
|
|
131
|
+
next(new Error('owned by the app final handler'));
|
|
132
|
+
return { unreachable: true };
|
|
133
|
+
},
|
|
134
|
+
() => ({ unreachable: true }),
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
app.use(router.original);
|
|
138
|
+
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
139
|
+
res.status(500).json({ ownedBy: 'app-final-handler', message: err.message });
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`use` and `param` delegate directly to the underlying native router:
|
|
144
|
+
|
|
145
|
+
- Callbacks are native Express middleware: sync/async failures reach
|
|
146
|
+
application error middleware and guarded JSON handlers do not run.
|
|
147
|
+
- Malformed `express.json()` input mounted before the router likewise reaches
|
|
148
|
+
application error middleware; `JsonRouter` does not sanitize upstream
|
|
149
|
+
body-parser failures.
|
|
150
|
+
- `basePath` is not prepended to `use`/`param` arguments; pass an explicit
|
|
151
|
+
mount path for scoped middleware. Broadly mounted `use` middleware runs
|
|
152
|
+
before JSON routes on the same underlying router in mount order.
|
|
153
|
+
- Both methods return the native router (`router.original`), not the
|
|
154
|
+
`JsonRouter`, so `.use(...).get(...)` is native registration. Write separate
|
|
155
|
+
`router.get(...)` statements for JSON routes. Native registrations never
|
|
156
|
+
appear in `getEndpoints()`.
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import express from 'express';
|
|
160
|
+
import JsonRouter from '@web-ts-toolkit/express-json-router';
|
|
161
|
+
|
|
162
|
+
const authMiddleware: express.RequestHandler = (req, res, next) => next();
|
|
163
|
+
const router = new JsonRouter('/api', authMiddleware);
|
|
164
|
+
|
|
165
|
+
router.param('userId', (req, res, next, id) => next());
|
|
166
|
+
|
|
167
|
+
router.get('/health', () => ({ ok: true }));
|
|
168
|
+
router.get('/users/:id', () => ({ ok: true }));
|
|
169
|
+
|
|
170
|
+
router.getEndpoints();
|
|
171
|
+
// [{ method: 'GET', path: '/api/health' }, { method: 'GET', path: '/api/users/:id' }]
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Route Builder Contract
|
|
175
|
+
|
|
176
|
+
`router.route(path)` is independent-registration sugar: each builder call equals
|
|
177
|
+
a direct `router.METHOD(path, ...)` call with its own native route,
|
|
178
|
+
response-handler wrapper (including constructor-middleware copies), and
|
|
179
|
+
`getEndpoints()` entry. It is not native `express.Router().route(path)`
|
|
180
|
+
grouping: an `.all()` guard calling `next('route')` does not skip a later
|
|
181
|
+
builder registration, HEAD requests fall back to the separately registered GET
|
|
182
|
+
handler, and constructor middleware re-runs for each chained registration
|
|
183
|
+
crossed by `next()`.
|
|
184
|
+
|
|
110
185
|
## Documentation
|
|
111
186
|
|
|
112
187
|
Full package documentation lives in `website/docs/packages/express-json-router.md`.
|
package/index.d.mts
CHANGED
|
@@ -71,16 +71,16 @@ declare class JsonRouterBase {
|
|
|
71
71
|
IMUsed: typeof IMUsed;
|
|
72
72
|
};
|
|
73
73
|
static readonly HttpResponse: {
|
|
74
|
-
ok: (data:
|
|
75
|
-
created: (data:
|
|
76
|
-
accepted: (data:
|
|
77
|
-
nonAuthoritativeInfo: (data:
|
|
74
|
+
ok: <T>(data: T) => OK<T>;
|
|
75
|
+
created: <T>(data: T) => Created<T>;
|
|
76
|
+
accepted: <T>(data: T) => Accepted<T>;
|
|
77
|
+
nonAuthoritativeInfo: <T>(data: T) => NonAuthoritativeInfo<T>;
|
|
78
78
|
noContent: () => NoContent;
|
|
79
|
-
resetContent: (data:
|
|
80
|
-
partialContent: (data:
|
|
81
|
-
multiStatus: (data:
|
|
82
|
-
alreadyReported: (data:
|
|
83
|
-
imUsed: (data:
|
|
79
|
+
resetContent: <T>(data: T) => ResetContent<T>;
|
|
80
|
+
partialContent: <T>(data: T) => PartialContent<T>;
|
|
81
|
+
multiStatus: <T>(data: T) => MultiStatus<T>;
|
|
82
|
+
alreadyReported: <T>(data: T) => AlreadyReported<T>;
|
|
83
|
+
imUsed: <T>(data: T) => IMUsed<T>;
|
|
84
84
|
badRequest: (message?: string | undefined, options?: clientErrors.HttpErrorOptions | undefined) => clientErrors.BadRequestError;
|
|
85
85
|
unauthorized: (message?: string | undefined, options?: clientErrors.HttpErrorOptions | undefined) => clientErrors.UnauthorizedError;
|
|
86
86
|
forbidden: (message?: string | undefined, options?: clientErrors.HttpErrorOptions | undefined) => clientErrors.ForbiddenError;
|
|
@@ -108,7 +108,7 @@ declare class JsonRouterBase {
|
|
|
108
108
|
tooManyRequests: (message?: string | undefined, options?: clientErrors.HttpErrorOptions | undefined) => clientErrors.TooManyRequestsError;
|
|
109
109
|
requestHeaderFieldsTooLarge: (message?: string | undefined, options?: clientErrors.HttpErrorOptions | undefined) => clientErrors.RequestHeaderFieldsTooLargeError;
|
|
110
110
|
unavailableForLegalReasons: (message?: string | undefined, options?: clientErrors.HttpErrorOptions | undefined) => clientErrors.UnavailableForLegalReasonsError;
|
|
111
|
-
json: (data:
|
|
111
|
+
json: <T>(data: T) => OK<T>;
|
|
112
112
|
csv: (dataset?: unknown, options?: _web_ts_toolkit_express_response_handler_responses_csv.CsvResponseOptions | undefined) => _web_ts_toolkit_express_response_handler.CSVResponse;
|
|
113
113
|
};
|
|
114
114
|
static readonly ErrorFormats: {
|
|
@@ -142,15 +142,54 @@ declare class JsonRouterBase {
|
|
|
142
142
|
get middlewares(): JsonRouterCallback[];
|
|
143
143
|
/** Underlying Express router to mount with `app.use(router.original)`. */
|
|
144
144
|
get original(): ExpressRouter;
|
|
145
|
+
/**
|
|
146
|
+
* Native `param` delegation to the underlying Express router.
|
|
147
|
+
*
|
|
148
|
+
* Boundary: `param` callbacks are native Express callbacks, not JSON-wrapped
|
|
149
|
+
* registrations. Thrown/rejected `param` failures reach application error
|
|
150
|
+
* middleware; they are not JSON-formatted by this router's response handler.
|
|
151
|
+
* Returns the underlying native router (`router.original`), not this
|
|
152
|
+
* `JsonRouter`, so chaining continues with native Express registration.
|
|
153
|
+
* Nothing registered here appears in `getEndpoints()`.
|
|
154
|
+
*/
|
|
145
155
|
param(...args: Parameters<ExpressRouter['param']>): ReturnType<ExpressRouter['param']>;
|
|
156
|
+
/**
|
|
157
|
+
* Native `use` delegation to the underlying Express router.
|
|
158
|
+
*
|
|
159
|
+
* Boundary: `use` callbacks are native Express middleware, not JSON-wrapped
|
|
160
|
+
* registrations. Thrown/rejected `use` failures and explicit `next(error)`
|
|
161
|
+
* reach application error middleware; they are not JSON-formatted by this
|
|
162
|
+
* router's response handler. `basePath` is not prepended here, so pass an
|
|
163
|
+
* explicit mount path for scoped middleware. Native middleware mounted
|
|
164
|
+
* without a path runs before JSON routes on the same underlying router in
|
|
165
|
+
* mount order. Returns the underlying native router (`router.original`),
|
|
166
|
+
* not this `JsonRouter`, so `.use(...).get(...)` continues with native
|
|
167
|
+
* Express registration. Use separate `router.get(...)` statements for JSON
|
|
168
|
+
* routes. Nothing registered here appears in `getEndpoints()`.
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* const router = new JsonRouter('/api');
|
|
172
|
+
* router.use('/', authMiddleware);
|
|
173
|
+
* router.get('/health', () => ({ ok: true }));
|
|
174
|
+
*/
|
|
146
175
|
use(...args: Parameters<ExpressRouter['use']>): ReturnType<ExpressRouter['use']>;
|
|
147
176
|
/**
|
|
148
177
|
* Starts a fluent route builder for one path.
|
|
178
|
+
*
|
|
179
|
+
* Retained contract (independent-registration sugar): each builder method
|
|
180
|
+
* call is exactly equivalent to a direct `router.METHOD(path, ...)` call.
|
|
181
|
+
* Every call creates a separate native route with its own response-handler
|
|
182
|
+
* wrapper (including constructor-middleware copies) and its own
|
|
183
|
+
* `getEndpoints()` entry in call order. This is not native
|
|
184
|
+
* `express.Router().route(path)` grouping, so `next('route')` from an
|
|
185
|
+
* `.all()` guard cannot skip a later builder registration, HEAD requests
|
|
186
|
+
* fall back to the separately registered GET handler, and constructor
|
|
187
|
+
* middleware re-runs for each chained registration crossed by `next()`.
|
|
149
188
|
* Registered handlers still pass through this router's response handler.
|
|
150
189
|
*/
|
|
151
190
|
route(path: string): JsonRouteBuilder;
|
|
152
191
|
private addEndpoint;
|
|
153
|
-
/** Returns a defensive copy of registered endpoint method/path metadata. */
|
|
192
|
+
/** Returns a defensive copy of registered JSON endpoint method/path metadata. Native `use`/`param`/router registrations are not recorded. */
|
|
154
193
|
getEndpoints(): JsonRouterEndpoint[];
|
|
155
194
|
private normalizePath;
|
|
156
195
|
}
|
package/index.d.ts
CHANGED
|
@@ -71,16 +71,16 @@ declare class JsonRouterBase {
|
|
|
71
71
|
IMUsed: typeof IMUsed;
|
|
72
72
|
};
|
|
73
73
|
static readonly HttpResponse: {
|
|
74
|
-
ok: (data:
|
|
75
|
-
created: (data:
|
|
76
|
-
accepted: (data:
|
|
77
|
-
nonAuthoritativeInfo: (data:
|
|
74
|
+
ok: <T>(data: T) => OK<T>;
|
|
75
|
+
created: <T>(data: T) => Created<T>;
|
|
76
|
+
accepted: <T>(data: T) => Accepted<T>;
|
|
77
|
+
nonAuthoritativeInfo: <T>(data: T) => NonAuthoritativeInfo<T>;
|
|
78
78
|
noContent: () => NoContent;
|
|
79
|
-
resetContent: (data:
|
|
80
|
-
partialContent: (data:
|
|
81
|
-
multiStatus: (data:
|
|
82
|
-
alreadyReported: (data:
|
|
83
|
-
imUsed: (data:
|
|
79
|
+
resetContent: <T>(data: T) => ResetContent<T>;
|
|
80
|
+
partialContent: <T>(data: T) => PartialContent<T>;
|
|
81
|
+
multiStatus: <T>(data: T) => MultiStatus<T>;
|
|
82
|
+
alreadyReported: <T>(data: T) => AlreadyReported<T>;
|
|
83
|
+
imUsed: <T>(data: T) => IMUsed<T>;
|
|
84
84
|
badRequest: (message?: string | undefined, options?: clientErrors.HttpErrorOptions | undefined) => clientErrors.BadRequestError;
|
|
85
85
|
unauthorized: (message?: string | undefined, options?: clientErrors.HttpErrorOptions | undefined) => clientErrors.UnauthorizedError;
|
|
86
86
|
forbidden: (message?: string | undefined, options?: clientErrors.HttpErrorOptions | undefined) => clientErrors.ForbiddenError;
|
|
@@ -108,7 +108,7 @@ declare class JsonRouterBase {
|
|
|
108
108
|
tooManyRequests: (message?: string | undefined, options?: clientErrors.HttpErrorOptions | undefined) => clientErrors.TooManyRequestsError;
|
|
109
109
|
requestHeaderFieldsTooLarge: (message?: string | undefined, options?: clientErrors.HttpErrorOptions | undefined) => clientErrors.RequestHeaderFieldsTooLargeError;
|
|
110
110
|
unavailableForLegalReasons: (message?: string | undefined, options?: clientErrors.HttpErrorOptions | undefined) => clientErrors.UnavailableForLegalReasonsError;
|
|
111
|
-
json: (data:
|
|
111
|
+
json: <T>(data: T) => OK<T>;
|
|
112
112
|
csv: (dataset?: unknown, options?: _web_ts_toolkit_express_response_handler_responses_csv.CsvResponseOptions | undefined) => _web_ts_toolkit_express_response_handler.CSVResponse;
|
|
113
113
|
};
|
|
114
114
|
static readonly ErrorFormats: {
|
|
@@ -142,15 +142,54 @@ declare class JsonRouterBase {
|
|
|
142
142
|
get middlewares(): JsonRouterCallback[];
|
|
143
143
|
/** Underlying Express router to mount with `app.use(router.original)`. */
|
|
144
144
|
get original(): ExpressRouter;
|
|
145
|
+
/**
|
|
146
|
+
* Native `param` delegation to the underlying Express router.
|
|
147
|
+
*
|
|
148
|
+
* Boundary: `param` callbacks are native Express callbacks, not JSON-wrapped
|
|
149
|
+
* registrations. Thrown/rejected `param` failures reach application error
|
|
150
|
+
* middleware; they are not JSON-formatted by this router's response handler.
|
|
151
|
+
* Returns the underlying native router (`router.original`), not this
|
|
152
|
+
* `JsonRouter`, so chaining continues with native Express registration.
|
|
153
|
+
* Nothing registered here appears in `getEndpoints()`.
|
|
154
|
+
*/
|
|
145
155
|
param(...args: Parameters<ExpressRouter['param']>): ReturnType<ExpressRouter['param']>;
|
|
156
|
+
/**
|
|
157
|
+
* Native `use` delegation to the underlying Express router.
|
|
158
|
+
*
|
|
159
|
+
* Boundary: `use` callbacks are native Express middleware, not JSON-wrapped
|
|
160
|
+
* registrations. Thrown/rejected `use` failures and explicit `next(error)`
|
|
161
|
+
* reach application error middleware; they are not JSON-formatted by this
|
|
162
|
+
* router's response handler. `basePath` is not prepended here, so pass an
|
|
163
|
+
* explicit mount path for scoped middleware. Native middleware mounted
|
|
164
|
+
* without a path runs before JSON routes on the same underlying router in
|
|
165
|
+
* mount order. Returns the underlying native router (`router.original`),
|
|
166
|
+
* not this `JsonRouter`, so `.use(...).get(...)` continues with native
|
|
167
|
+
* Express registration. Use separate `router.get(...)` statements for JSON
|
|
168
|
+
* routes. Nothing registered here appears in `getEndpoints()`.
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* const router = new JsonRouter('/api');
|
|
172
|
+
* router.use('/', authMiddleware);
|
|
173
|
+
* router.get('/health', () => ({ ok: true }));
|
|
174
|
+
*/
|
|
146
175
|
use(...args: Parameters<ExpressRouter['use']>): ReturnType<ExpressRouter['use']>;
|
|
147
176
|
/**
|
|
148
177
|
* Starts a fluent route builder for one path.
|
|
178
|
+
*
|
|
179
|
+
* Retained contract (independent-registration sugar): each builder method
|
|
180
|
+
* call is exactly equivalent to a direct `router.METHOD(path, ...)` call.
|
|
181
|
+
* Every call creates a separate native route with its own response-handler
|
|
182
|
+
* wrapper (including constructor-middleware copies) and its own
|
|
183
|
+
* `getEndpoints()` entry in call order. This is not native
|
|
184
|
+
* `express.Router().route(path)` grouping, so `next('route')` from an
|
|
185
|
+
* `.all()` guard cannot skip a later builder registration, HEAD requests
|
|
186
|
+
* fall back to the separately registered GET handler, and constructor
|
|
187
|
+
* middleware re-runs for each chained registration crossed by `next()`.
|
|
149
188
|
* Registered handlers still pass through this router's response handler.
|
|
150
189
|
*/
|
|
151
190
|
route(path: string): JsonRouteBuilder;
|
|
152
191
|
private addEndpoint;
|
|
153
|
-
/** Returns a defensive copy of registered endpoint method/path metadata. */
|
|
192
|
+
/** Returns a defensive copy of registered JSON endpoint method/path metadata. Native `use`/`param`/router registrations are not recorded. */
|
|
154
193
|
getEndpoints(): JsonRouterEndpoint[];
|
|
155
194
|
private normalizePath;
|
|
156
195
|
}
|
package/index.js
CHANGED
|
@@ -257,14 +257,53 @@ var JsonRouterBase = class _JsonRouterBase {
|
|
|
257
257
|
get original() {
|
|
258
258
|
return this._router;
|
|
259
259
|
}
|
|
260
|
+
/**
|
|
261
|
+
* Native `param` delegation to the underlying Express router.
|
|
262
|
+
*
|
|
263
|
+
* Boundary: `param` callbacks are native Express callbacks, not JSON-wrapped
|
|
264
|
+
* registrations. Thrown/rejected `param` failures reach application error
|
|
265
|
+
* middleware; they are not JSON-formatted by this router's response handler.
|
|
266
|
+
* Returns the underlying native router (`router.original`), not this
|
|
267
|
+
* `JsonRouter`, so chaining continues with native Express registration.
|
|
268
|
+
* Nothing registered here appears in `getEndpoints()`.
|
|
269
|
+
*/
|
|
260
270
|
param(...args) {
|
|
261
271
|
return this._router.param(...args);
|
|
262
272
|
}
|
|
273
|
+
/**
|
|
274
|
+
* Native `use` delegation to the underlying Express router.
|
|
275
|
+
*
|
|
276
|
+
* Boundary: `use` callbacks are native Express middleware, not JSON-wrapped
|
|
277
|
+
* registrations. Thrown/rejected `use` failures and explicit `next(error)`
|
|
278
|
+
* reach application error middleware; they are not JSON-formatted by this
|
|
279
|
+
* router's response handler. `basePath` is not prepended here, so pass an
|
|
280
|
+
* explicit mount path for scoped middleware. Native middleware mounted
|
|
281
|
+
* without a path runs before JSON routes on the same underlying router in
|
|
282
|
+
* mount order. Returns the underlying native router (`router.original`),
|
|
283
|
+
* not this `JsonRouter`, so `.use(...).get(...)` continues with native
|
|
284
|
+
* Express registration. Use separate `router.get(...)` statements for JSON
|
|
285
|
+
* routes. Nothing registered here appears in `getEndpoints()`.
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* const router = new JsonRouter('/api');
|
|
289
|
+
* router.use('/', authMiddleware);
|
|
290
|
+
* router.get('/health', () => ({ ok: true }));
|
|
291
|
+
*/
|
|
263
292
|
use(...args) {
|
|
264
293
|
return this._router.use(...args);
|
|
265
294
|
}
|
|
266
295
|
/**
|
|
267
296
|
* Starts a fluent route builder for one path.
|
|
297
|
+
*
|
|
298
|
+
* Retained contract (independent-registration sugar): each builder method
|
|
299
|
+
* call is exactly equivalent to a direct `router.METHOD(path, ...)` call.
|
|
300
|
+
* Every call creates a separate native route with its own response-handler
|
|
301
|
+
* wrapper (including constructor-middleware copies) and its own
|
|
302
|
+
* `getEndpoints()` entry in call order. This is not native
|
|
303
|
+
* `express.Router().route(path)` grouping, so `next('route')` from an
|
|
304
|
+
* `.all()` guard cannot skip a later builder registration, HEAD requests
|
|
305
|
+
* fall back to the separately registered GET handler, and constructor
|
|
306
|
+
* middleware re-runs for each chained registration crossed by `next()`.
|
|
268
307
|
* Registered handlers still pass through this router's response handler.
|
|
269
308
|
*/
|
|
270
309
|
route(path) {
|
|
@@ -289,7 +328,7 @@ var JsonRouterBase = class _JsonRouterBase {
|
|
|
289
328
|
path: this.normalizePath(path)
|
|
290
329
|
});
|
|
291
330
|
}
|
|
292
|
-
/** Returns a defensive copy of registered endpoint method/path metadata. */
|
|
331
|
+
/** Returns a defensive copy of registered JSON endpoint method/path metadata. Native `use`/`param`/router registrations are not recorded. */
|
|
293
332
|
getEndpoints() {
|
|
294
333
|
return this._endpoints.map((endpoint) => ({ ...endpoint }));
|
|
295
334
|
}
|
package/index.mjs
CHANGED
|
@@ -237,14 +237,53 @@ var JsonRouterBase = class _JsonRouterBase {
|
|
|
237
237
|
get original() {
|
|
238
238
|
return this._router;
|
|
239
239
|
}
|
|
240
|
+
/**
|
|
241
|
+
* Native `param` delegation to the underlying Express router.
|
|
242
|
+
*
|
|
243
|
+
* Boundary: `param` callbacks are native Express callbacks, not JSON-wrapped
|
|
244
|
+
* registrations. Thrown/rejected `param` failures reach application error
|
|
245
|
+
* middleware; they are not JSON-formatted by this router's response handler.
|
|
246
|
+
* Returns the underlying native router (`router.original`), not this
|
|
247
|
+
* `JsonRouter`, so chaining continues with native Express registration.
|
|
248
|
+
* Nothing registered here appears in `getEndpoints()`.
|
|
249
|
+
*/
|
|
240
250
|
param(...args) {
|
|
241
251
|
return this._router.param(...args);
|
|
242
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* Native `use` delegation to the underlying Express router.
|
|
255
|
+
*
|
|
256
|
+
* Boundary: `use` callbacks are native Express middleware, not JSON-wrapped
|
|
257
|
+
* registrations. Thrown/rejected `use` failures and explicit `next(error)`
|
|
258
|
+
* reach application error middleware; they are not JSON-formatted by this
|
|
259
|
+
* router's response handler. `basePath` is not prepended here, so pass an
|
|
260
|
+
* explicit mount path for scoped middleware. Native middleware mounted
|
|
261
|
+
* without a path runs before JSON routes on the same underlying router in
|
|
262
|
+
* mount order. Returns the underlying native router (`router.original`),
|
|
263
|
+
* not this `JsonRouter`, so `.use(...).get(...)` continues with native
|
|
264
|
+
* Express registration. Use separate `router.get(...)` statements for JSON
|
|
265
|
+
* routes. Nothing registered here appears in `getEndpoints()`.
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* const router = new JsonRouter('/api');
|
|
269
|
+
* router.use('/', authMiddleware);
|
|
270
|
+
* router.get('/health', () => ({ ok: true }));
|
|
271
|
+
*/
|
|
243
272
|
use(...args) {
|
|
244
273
|
return this._router.use(...args);
|
|
245
274
|
}
|
|
246
275
|
/**
|
|
247
276
|
* Starts a fluent route builder for one path.
|
|
277
|
+
*
|
|
278
|
+
* Retained contract (independent-registration sugar): each builder method
|
|
279
|
+
* call is exactly equivalent to a direct `router.METHOD(path, ...)` call.
|
|
280
|
+
* Every call creates a separate native route with its own response-handler
|
|
281
|
+
* wrapper (including constructor-middleware copies) and its own
|
|
282
|
+
* `getEndpoints()` entry in call order. This is not native
|
|
283
|
+
* `express.Router().route(path)` grouping, so `next('route')` from an
|
|
284
|
+
* `.all()` guard cannot skip a later builder registration, HEAD requests
|
|
285
|
+
* fall back to the separately registered GET handler, and constructor
|
|
286
|
+
* middleware re-runs for each chained registration crossed by `next()`.
|
|
248
287
|
* Registered handlers still pass through this router's response handler.
|
|
249
288
|
*/
|
|
250
289
|
route(path) {
|
|
@@ -269,7 +308,7 @@ var JsonRouterBase = class _JsonRouterBase {
|
|
|
269
308
|
path: this.normalizePath(path)
|
|
270
309
|
});
|
|
271
310
|
}
|
|
272
|
-
/** Returns a defensive copy of registered endpoint method/path metadata. */
|
|
311
|
+
/** Returns a defensive copy of registered JSON endpoint method/path metadata. Native `use`/`param`/router registrations are not recorded. */
|
|
273
312
|
getEndpoints() {
|
|
274
313
|
return this._endpoints.map((endpoint) => ({ ...endpoint }));
|
|
275
314
|
}
|
package/llms.txt
CHANGED
|
@@ -59,7 +59,10 @@ router.get('/users/:id', readUser);
|
|
|
59
59
|
- constructor middleware and `getEndpoints()` results are snapshots; mutating caller arrays or returned arrays does not change future route registration or endpoint metadata
|
|
60
60
|
- route-local Express error middleware with four arguments is rejected; mount error middleware with `router.use(...)`
|
|
61
61
|
- static defaults (`errorMessageProvider`, `preJson`, `postJson`, `preError`, `postError`) affect routers created after the change; existing routers keep their constructed response handler
|
|
62
|
-
- `JsonRouter.defaultHandler` returns a newly configured handler each time it is read; pass an explicit handler as the third constructor argument for isolated behavior
|
|
62
|
+
- `JsonRouter.defaultHandler` returns a newly configured handler each time it is read; mutating a retrieved handler does not reconfigure existing routers or future defaults; pass an explicit handler as the third constructor argument for isolated behavior
|
|
63
|
+
- `router.route(path)` is independent-registration sugar (one native route, wrapper, and `getEndpoints()` entry per builder call), not native `express.Router().route(path)` grouping: `next('route')` does not skip later builder calls, HEAD falls back to GET, constructor middleware re-runs per chained registration crossed by `next()`
|
|
64
|
+
- thrown/rejected JSON callbacks are JSON-formatted and never reach app error middleware; explicit `next(error)` delegates to native Express error middleware, which owns the response
|
|
65
|
+
- `router.use(...)`/`router.param(...)` delegate to the native router (`router.original`): native callbacks, `basePath` not prepended, nothing recorded in `getEndpoints()`; write separate `router.get(...)` statements for JSON routes
|
|
63
66
|
- Express is a direct runtime dependency because this package constructs `express.Router()` instances; `@types/express` is installed as a dependency for strict TypeScript consumers
|
|
64
67
|
|
|
65
68
|
## Pointers
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@web-ts-toolkit/express-json-router",
|
|
3
3
|
"description": "Express router wrapper for return-value JSON responses",
|
|
4
4
|
"homepage": "https://web-ts-toolkit.pages.dev/docs/packages/express-json-router",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.44.0",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"keywords": [
|
|
8
8
|
"express",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"node": ">=22"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@web-ts-toolkit/express-response-handler": "0.
|
|
34
|
-
"@web-ts-toolkit/http-errors": "0.
|
|
35
|
-
"@web-ts-toolkit/utils": "0.
|
|
33
|
+
"@web-ts-toolkit/express-response-handler": "0.44.0",
|
|
34
|
+
"@web-ts-toolkit/http-errors": "0.44.0",
|
|
35
|
+
"@web-ts-toolkit/utils": "0.44.0",
|
|
36
36
|
"@types/express": "^5.0.6",
|
|
37
37
|
"express": "^5.2.1"
|
|
38
38
|
},
|