@molecule/api-resource 1.0.7 → 1.1.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 +88 -2
- package/dist/createRequestHandler.d.ts +41 -1
- package/dist/createRequestHandler.d.ts.map +1 -1
- package/dist/createRequestHandler.js +39 -15
- package/dist/createRequestHandler.js.map +1 -1
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
|
|
|
3
3
|
Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
|
|
4
4
|
Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
|
|
5
5
|
To change this document, edit the module-level JSDoc in src/index.ts.
|
|
6
|
-
Generated: 2026-
|
|
6
|
+
Generated: 2026-11-06T22:08:33.809Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/api-resource
|
|
@@ -30,6 +30,33 @@ res.status(statusCode).send(body)
|
|
|
30
30
|
Monkey-patching `res.json` (or `res.send`/`res.end`) to re-shape a handler's answer intercepts
|
|
31
31
|
nothing the handler produces, so the request it was meant to answer is left unanswered and hangs.
|
|
32
32
|
|
|
33
|
+
**A different request or response envelope is configuration.** Pass
|
|
34
|
+
`mapRequest` and/or `mapResponse` as the second argument to `createRequestHandler`.
|
|
35
|
+
Both may be asynchronous. The existing handler still validates and authorizes
|
|
36
|
+
the adapted input. A response mapper sees the handler's errors and partial
|
|
37
|
+
responses too: preserve them and its headers instead of treating every result
|
|
38
|
+
as a success. `adaptHandler(handler, options)` offers the same mappings when
|
|
39
|
+
another HTTP adapter will send the structured response.
|
|
40
|
+
A request mapper can return `{ response: { statusCode, body } }` to answer
|
|
41
|
+
before calling the handler, for example when extra validation fails or a
|
|
42
|
+
filter lookup finds nothing. That response still passes through mapResponse.
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { createRequestHandler } from '@molecule/api-resource'
|
|
46
|
+
import { handlers } from '@molecule/api-resource-user'
|
|
47
|
+
|
|
48
|
+
const register = createRequestHandler(handlers.create({ name: 'User', tableName: 'users' }), {
|
|
49
|
+
// Return overrides. The adapter retains framework methods and getters.
|
|
50
|
+
mapRequest: (req) => ({ body: req.body?.account }),
|
|
51
|
+
mapResponse: (result) =>
|
|
52
|
+
result.statusCode === 201
|
|
53
|
+
? { ...result, body: { account: result.body.props, accessToken: result.body.accessToken } }
|
|
54
|
+
: result,
|
|
55
|
+
})
|
|
56
|
+
// Keep the route's existing rate limiter and authorization around register.
|
|
57
|
+
// No mapping is inferred: a flat-body API keeps createRequestHandler(handler).
|
|
58
|
+
```
|
|
59
|
+
|
|
33
60
|
> **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
|
|
34
61
|
> It is written to be read by coding agents as much as by people, and is generated from this
|
|
35
62
|
> package's source — edit `src/index.ts` JSDoc, not this file.
|
|
@@ -114,6 +141,38 @@ interface Response {
|
|
|
114
141
|
}
|
|
115
142
|
```
|
|
116
143
|
|
|
144
|
+
#### `RequestHandlerOptions`
|
|
145
|
+
|
|
146
|
+
Per-route wire-format adapters. Validation and authorization still belong to
|
|
147
|
+
the original handler. Omit these options to retain its native contract.
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
interface RequestHandlerOptions {
|
|
151
|
+
/**
|
|
152
|
+
* Return the fields to replace before the handler validates the request.
|
|
153
|
+
* The adapter preserves the original request's methods and getters, and does
|
|
154
|
+
* not mutate it. Returning `{ body }` or `{ query }` is sufficient, including
|
|
155
|
+
* frameworks whose request properties have read-only accessors.
|
|
156
|
+
* Return `{ response: { statusCode, headers?, body } }` to answer before the
|
|
157
|
+
* handler runs. That result still goes through mapResponse, with the original request.
|
|
158
|
+
*/
|
|
159
|
+
mapRequest?: (
|
|
160
|
+
req: MoleculeRequest,
|
|
161
|
+
res: MoleculeResponse,
|
|
162
|
+
) => RequestMappingResult | Promise<RequestMappingResult>
|
|
163
|
+
/**
|
|
164
|
+
* Adapt the returned status, headers or body. This sees error and partial
|
|
165
|
+
* responses too: narrow the success shape before changing it, and preserve
|
|
166
|
+
* headers with `{ ...response, body }`. It never runs for fall-through.
|
|
167
|
+
*/
|
|
168
|
+
mapResponse?: (
|
|
169
|
+
response: Response,
|
|
170
|
+
req: MoleculeRequest,
|
|
171
|
+
res: MoleculeResponse,
|
|
172
|
+
) => Response | Promise<Response>
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
117
176
|
#### `MoleculeRequest`
|
|
118
177
|
|
|
119
178
|
Framework-agnostic HTTP request interface. Structurally compatible with Express's
|
|
@@ -258,6 +317,16 @@ type Handler = (
|
|
|
258
317
|
- `req` — The incoming HTTP request.
|
|
259
318
|
- `res` — The HTTP response (available but handlers should return a Response instead of calling `res` directly).
|
|
260
319
|
|
|
320
|
+
#### `RequestMappingResult`
|
|
321
|
+
|
|
322
|
+
Request overrides, or an explicit response that stops before the handler.
|
|
323
|
+
The response form supports extra validation and unresolved external filters
|
|
324
|
+
without writing data or inventing a placeholder identifier.
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
type RequestMappingResult = Partial<MoleculeRequest> | { response: Response }
|
|
328
|
+
```
|
|
329
|
+
|
|
261
330
|
#### `MoleculeNextFunction`
|
|
262
331
|
|
|
263
332
|
Framework-agnostic next function. Call with no arguments to pass to the next
|
|
@@ -333,7 +402,22 @@ function create<
|
|
|
333
402
|
|
|
334
403
|
**Returns:** A curried async function that accepts `{ props, id? }` and returns a `{ statusCode, body }` response.
|
|
335
404
|
|
|
336
|
-
#### `
|
|
405
|
+
#### `adaptHandler(handler, options)`
|
|
406
|
+
|
|
407
|
+
Compose wire-format adapters around a structured resource handler without
|
|
408
|
+
sending its response. The response mapper receives the adapted request.
|
|
409
|
+
Exceptions propagate to the caller's normal error boundary.
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
function adaptHandler(handler: Handler, options?: RequestHandlerOptions): Handler
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
- `handler` — The existing resource handler, including its checks.
|
|
416
|
+
- `options` — Request and response mappings for this route only.
|
|
417
|
+
|
|
418
|
+
**Returns:** A structured handler that keeps null/undefined fall-through intact.
|
|
419
|
+
|
|
420
|
+
#### `createRequestHandler(handler, options)`
|
|
337
421
|
|
|
338
422
|
Wraps a resource handler into Express-compatible middleware. Calls the handler,
|
|
339
423
|
then applies `statusCode`, `headers`, and `body` to the response. If the handler
|
|
@@ -343,10 +427,12 @@ i18n-translated error messages.
|
|
|
343
427
|
```typescript
|
|
344
428
|
function createRequestHandler(
|
|
345
429
|
handler: Handler,
|
|
430
|
+
options?: RequestHandlerOptions,
|
|
346
431
|
): (req: MoleculeRequest, res: MoleculeResponse, next: MoleculeNextFunction) => Promise<void>
|
|
347
432
|
```
|
|
348
433
|
|
|
349
434
|
- `handler` — The resource handler function to wrap.
|
|
435
|
+
- `options` — Optional wire-format mappings; neither mutates the shared handler.
|
|
350
436
|
|
|
351
437
|
**Returns:** An Express-compatible middleware function `(req, res, next) => void`.
|
|
352
438
|
|
|
@@ -35,6 +35,45 @@ export interface Response {
|
|
|
35
35
|
*/
|
|
36
36
|
body: any;
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Request overrides, or an explicit response that stops before the handler.
|
|
40
|
+
* The response form supports extra validation and unresolved external filters
|
|
41
|
+
* without writing data or inventing a placeholder identifier.
|
|
42
|
+
*/
|
|
43
|
+
export type RequestMappingResult = Partial<MoleculeRequest> | {
|
|
44
|
+
response: Response;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Per-route wire-format adapters. Validation and authorization still belong to
|
|
48
|
+
* the original handler. Omit these options to retain its native contract.
|
|
49
|
+
*/
|
|
50
|
+
export interface RequestHandlerOptions {
|
|
51
|
+
/**
|
|
52
|
+
* Return the fields to replace before the handler validates the request.
|
|
53
|
+
* The adapter preserves the original request's methods and getters, and does
|
|
54
|
+
* not mutate it. Returning `{ body }` or `{ query }` is sufficient, including
|
|
55
|
+
* frameworks whose request properties have read-only accessors.
|
|
56
|
+
* Return `{ response: { statusCode, headers?, body } }` to answer before the
|
|
57
|
+
* handler runs. That result still goes through mapResponse, with the original request.
|
|
58
|
+
*/
|
|
59
|
+
mapRequest?: (req: MoleculeRequest, res: MoleculeResponse) => RequestMappingResult | Promise<RequestMappingResult>;
|
|
60
|
+
/**
|
|
61
|
+
* Adapt the returned status, headers or body. This sees error and partial
|
|
62
|
+
* responses too: narrow the success shape before changing it, and preserve
|
|
63
|
+
* headers with `{ ...response, body }`. It never runs for fall-through.
|
|
64
|
+
*/
|
|
65
|
+
mapResponse?: (response: Response, req: MoleculeRequest, res: MoleculeResponse) => Response | Promise<Response>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Compose wire-format adapters around a structured resource handler without
|
|
69
|
+
* sending its response. The response mapper receives the adapted request.
|
|
70
|
+
* Exceptions propagate to the caller's normal error boundary.
|
|
71
|
+
*
|
|
72
|
+
* @param handler - The existing resource handler, including its checks.
|
|
73
|
+
* @param options - Request and response mappings for this route only.
|
|
74
|
+
* @returns A structured handler that keeps null/undefined fall-through intact.
|
|
75
|
+
*/
|
|
76
|
+
export declare const adaptHandler: (handler: Handler, options?: RequestHandlerOptions) => Handler;
|
|
38
77
|
/**
|
|
39
78
|
* Wraps a resource handler into Express-compatible middleware. Calls the handler,
|
|
40
79
|
* then applies `statusCode`, `headers`, and `body` to the response. If the handler
|
|
@@ -42,7 +81,8 @@ export interface Response {
|
|
|
42
81
|
* i18n-translated error messages.
|
|
43
82
|
*
|
|
44
83
|
* @param handler - The resource handler function to wrap.
|
|
84
|
+
* @param options - Optional wire-format mappings; neither mutates the shared handler.
|
|
45
85
|
* @returns An Express-compatible middleware function `(req, res, next) => void`.
|
|
46
86
|
*/
|
|
47
|
-
export declare const createRequestHandler: (handler: Handler) => (req: MoleculeRequest, res: MoleculeResponse, next: MoleculeNextFunction) => Promise<void>;
|
|
87
|
+
export declare const createRequestHandler: (handler: Handler, options?: RequestHandlerOptions) => (req: MoleculeRequest, res: MoleculeResponse, next: MoleculeNextFunction) => Promise<void>;
|
|
48
88
|
//# sourceMappingURL=createRequestHandler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createRequestHandler.d.ts","sourceRoot":"","sources":["../src/createRequestHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAI9F;;;;;;;GAOG;AACH,MAAM,MAAM,OAAO,GAAG,CACpB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,gBAAgB,KAClB,OAAO,CAAC,QAAQ,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,QAAQ,GAAG,IAAI,GAAG,SAAS,CAAA;AAEvE;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC;;OAEG;IACH,IAAI,EAAE,GAAG,CAAA;CACV;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"createRequestHandler.d.ts","sourceRoot":"","sources":["../src/createRequestHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAI9F;;;;;;;GAOG;AACH,MAAM,MAAM,OAAO,GAAG,CACpB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,gBAAgB,KAClB,OAAO,CAAC,QAAQ,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,QAAQ,GAAG,IAAI,GAAG,SAAS,CAAA;AAEvE;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC;;OAEG;IACH,IAAI,EAAE,GAAG,CAAA;CACV;AAED;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAA;AAEpF;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,CACX,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,gBAAgB,KAClB,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA;IACzD;;;;OAIG;IACH,WAAW,CAAC,EAAE,CACZ,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,gBAAgB,KAClB,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CAClC;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GACtB,SAAS,OAAO,EAAE,UAAS,qBAA0B,KAAG,OAYxD,CAAA;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAS,OAAO,EAAE,UAAS,qBAA0B,MAE1E,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,kBAmBtF,CAAA"}
|
|
@@ -11,6 +11,26 @@
|
|
|
11
11
|
import { getLogger } from '@molecule/api-bond';
|
|
12
12
|
const logger = getLogger();
|
|
13
13
|
import { t } from '@molecule/api-i18n';
|
|
14
|
+
/**
|
|
15
|
+
* Compose wire-format adapters around a structured resource handler without
|
|
16
|
+
* sending its response. The response mapper receives the adapted request.
|
|
17
|
+
* Exceptions propagate to the caller's normal error boundary.
|
|
18
|
+
*
|
|
19
|
+
* @param handler - The existing resource handler, including its checks.
|
|
20
|
+
* @param options - Request and response mappings for this route only.
|
|
21
|
+
* @returns A structured handler that keeps null/undefined fall-through intact.
|
|
22
|
+
*/
|
|
23
|
+
export const adaptHandler = (handler, options = {}) => async (req, res) => {
|
|
24
|
+
const overrides = options.mapRequest ? await options.mapRequest(req, res) : undefined;
|
|
25
|
+
const earlyResponse = overrides && 'response' in overrides ? overrides.response : undefined;
|
|
26
|
+
const request = overrides && !earlyResponse
|
|
27
|
+
? Object.create(req, Object.getOwnPropertyDescriptors(overrides))
|
|
28
|
+
: req;
|
|
29
|
+
const response = earlyResponse ?? (await handler(request, res));
|
|
30
|
+
return response && options.mapResponse
|
|
31
|
+
? await options.mapResponse(response, request, res)
|
|
32
|
+
: response;
|
|
33
|
+
};
|
|
14
34
|
/**
|
|
15
35
|
* Wraps a resource handler into Express-compatible middleware. Calls the handler,
|
|
16
36
|
* then applies `statusCode`, `headers`, and `body` to the response. If the handler
|
|
@@ -18,25 +38,29 @@ import { t } from '@molecule/api-i18n';
|
|
|
18
38
|
* i18n-translated error messages.
|
|
19
39
|
*
|
|
20
40
|
* @param handler - The resource handler function to wrap.
|
|
41
|
+
* @param options - Optional wire-format mappings; neither mutates the shared handler.
|
|
21
42
|
* @returns An Express-compatible middleware function `(req, res, next) => void`.
|
|
22
43
|
*/
|
|
23
|
-
export const createRequestHandler = (handler
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
44
|
+
export const createRequestHandler = (handler, options = {}) => {
|
|
45
|
+
const adapted = adaptHandler(handler, options);
|
|
46
|
+
return async (req, res, next) => {
|
|
47
|
+
try {
|
|
48
|
+
const response = await adapted(req, res);
|
|
49
|
+
if (response) {
|
|
50
|
+
if (response.headers) {
|
|
51
|
+
res.set(response.headers);
|
|
52
|
+
}
|
|
53
|
+
res.status(response.statusCode);
|
|
54
|
+
res.send(response.body);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
next();
|
|
29
58
|
}
|
|
30
|
-
res.status(response.statusCode);
|
|
31
|
-
res.send(response.body);
|
|
32
59
|
}
|
|
33
|
-
|
|
34
|
-
|
|
60
|
+
catch (error) {
|
|
61
|
+
logger.error(error);
|
|
62
|
+
next(t('resource.error.unknownError', undefined, { defaultValue: 'Something went wrong.' }));
|
|
35
63
|
}
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
logger.error(error);
|
|
39
|
-
next(t('resource.error.unknownError', undefined, { defaultValue: 'Something went wrong.' }));
|
|
40
|
-
}
|
|
64
|
+
};
|
|
41
65
|
};
|
|
42
66
|
//# sourceMappingURL=createRequestHandler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createRequestHandler.js","sourceRoot":"","sources":["../src/createRequestHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,uDAAuD;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAG9C,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;AAC1B,OAAO,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"createRequestHandler.js","sourceRoot":"","sources":["../src/createRequestHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,uDAAuD;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAG9C,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;AAC1B,OAAO,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAA;AAsEtC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,YAAY,GACvB,CAAC,OAAgB,EAAE,UAAiC,EAAE,EAAW,EAAE,CACnE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IACjB,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACrF,MAAM,aAAa,GAAG,SAAS,IAAI,UAAU,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;IAC3F,MAAM,OAAO,GACX,SAAS,IAAI,CAAC,aAAa;QACzB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,yBAAyB,CAAC,SAAS,CAAC,CAAC;QACjE,CAAC,CAAC,GAAG,CAAA;IACT,MAAM,QAAQ,GAAG,aAAa,IAAI,CAAC,MAAM,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAA;IAC/D,OAAO,QAAQ,IAAI,OAAO,CAAC,WAAW;QACpC,CAAC,CAAC,MAAM,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC;QACnD,CAAC,CAAC,QAAQ,CAAA;AACd,CAAC,CAAA;AAEH;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,OAAgB,EAAE,UAAiC,EAAE,EAAE,EAAE;IAC5F,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAC9C,OAAO,KAAK,EAAE,GAAoB,EAAE,GAAqB,EAAE,IAA0B,EAAE,EAAE;QACvF,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;YAExC,IAAI,QAAQ,EAAE,CAAC;gBACb,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;oBACrB,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;gBAC3B,CAAC;gBAED,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;gBAC/B,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;YACzB,CAAC;iBAAM,CAAC;gBACN,IAAI,EAAE,CAAA;YACR,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YACnB,IAAI,CAAC,CAAC,CAAC,6BAA6B,EAAE,SAAS,EAAE,EAAE,YAAY,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAA;QAC9F,CAAC;IACH,CAAC,CAAA;AACH,CAAC,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -21,6 +21,32 @@
|
|
|
21
21
|
* Monkey-patching `res.json` (or `res.send`/`res.end`) to re-shape a handler's answer intercepts
|
|
22
22
|
* nothing the handler produces, so the request it was meant to answer is left unanswered and hangs.
|
|
23
23
|
*
|
|
24
|
+
* **A different request or response envelope is configuration.** Pass
|
|
25
|
+
* `mapRequest` and/or `mapResponse` as the second argument to `createRequestHandler`.
|
|
26
|
+
* Both may be asynchronous. The existing handler still validates and authorizes
|
|
27
|
+
* the adapted input. A response mapper sees the handler's errors and partial
|
|
28
|
+
* responses too: preserve them and its headers instead of treating every result
|
|
29
|
+
* as a success. `adaptHandler(handler, options)` offers the same mappings when
|
|
30
|
+
* another HTTP adapter will send the structured response.
|
|
31
|
+
* A request mapper can return `{ response: { statusCode, body } }` to answer
|
|
32
|
+
* before calling the handler, for example when extra validation fails or a
|
|
33
|
+
* filter lookup finds nothing. That response still passes through mapResponse.
|
|
34
|
+
*
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import { createRequestHandler } from '@molecule/api-resource'
|
|
37
|
+
* import { handlers } from '@molecule/api-resource-user'
|
|
38
|
+
*
|
|
39
|
+
* const register = createRequestHandler(handlers.create({ name: 'User', tableName: 'users' }), {
|
|
40
|
+
* // Return overrides. The adapter retains framework methods and getters.
|
|
41
|
+
* mapRequest: (req) => ({ body: req.body?.account }),
|
|
42
|
+
* mapResponse: (result) => result.statusCode === 201
|
|
43
|
+
* ? { ...result, body: { account: result.body.props, accessToken: result.body.accessToken } }
|
|
44
|
+
* : result,
|
|
45
|
+
* })
|
|
46
|
+
* // Keep the route's existing rate limiter and authorization around register.
|
|
47
|
+
* // No mapping is inferred: a flat-body API keeps createRequestHandler(handler).
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
24
50
|
* @example
|
|
25
51
|
* ```typescript
|
|
26
52
|
* import { z } from 'zod'
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+HG;AAEH,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,2BAA2B,CAAA;AACzC,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,oBAAoB,CAAA;AAClC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,32 @@
|
|
|
21
21
|
* Monkey-patching `res.json` (or `res.send`/`res.end`) to re-shape a handler's answer intercepts
|
|
22
22
|
* nothing the handler produces, so the request it was meant to answer is left unanswered and hangs.
|
|
23
23
|
*
|
|
24
|
+
* **A different request or response envelope is configuration.** Pass
|
|
25
|
+
* `mapRequest` and/or `mapResponse` as the second argument to `createRequestHandler`.
|
|
26
|
+
* Both may be asynchronous. The existing handler still validates and authorizes
|
|
27
|
+
* the adapted input. A response mapper sees the handler's errors and partial
|
|
28
|
+
* responses too: preserve them and its headers instead of treating every result
|
|
29
|
+
* as a success. `adaptHandler(handler, options)` offers the same mappings when
|
|
30
|
+
* another HTTP adapter will send the structured response.
|
|
31
|
+
* A request mapper can return `{ response: { statusCode, body } }` to answer
|
|
32
|
+
* before calling the handler, for example when extra validation fails or a
|
|
33
|
+
* filter lookup finds nothing. That response still passes through mapResponse.
|
|
34
|
+
*
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import { createRequestHandler } from '@molecule/api-resource'
|
|
37
|
+
* import { handlers } from '@molecule/api-resource-user'
|
|
38
|
+
*
|
|
39
|
+
* const register = createRequestHandler(handlers.create({ name: 'User', tableName: 'users' }), {
|
|
40
|
+
* // Return overrides. The adapter retains framework methods and getters.
|
|
41
|
+
* mapRequest: (req) => ({ body: req.body?.account }),
|
|
42
|
+
* mapResponse: (result) => result.statusCode === 201
|
|
43
|
+
* ? { ...result, body: { account: result.body.props, accessToken: result.body.accessToken } }
|
|
44
|
+
* : result,
|
|
45
|
+
* })
|
|
46
|
+
* // Keep the route's existing rate limiter and authorization around register.
|
|
47
|
+
* // No mapping is inferred: a flat-body API keeps createRequestHandler(handler).
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
24
50
|
* @example
|
|
25
51
|
* ```typescript
|
|
26
52
|
* import { z } from 'zod'
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+HG;AAEH,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,2BAA2B,CAAA;AACzC,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,oBAAoB,CAAA;AAClC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@molecule/api-resource",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Resource CRUD operations and utilities for molecule.dev.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@molecule/api-bond": "1.0.4",
|
|
43
|
-
"@molecule/api-database": "1.2.
|
|
43
|
+
"@molecule/api-database": "1.2.2",
|
|
44
44
|
"@molecule/api-locales-resource": "1.0.2",
|
|
45
45
|
"@molecule/api-utilities-validation": "1.0.4",
|
|
46
46
|
"@types/node": "26.6.5",
|