@molecule/api-resource 1.0.3 → 1.0.5

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 CHANGED
@@ -3,21 +3,37 @@ 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-10-16T00:47:45.548Z
6
+ Generated: 2026-10-17T04:45:43.913Z
7
7
  -->
8
8
 
9
9
  # @molecule/api-resource
10
10
 
11
- > **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
12
- > It is written to be read by coding agents as much as by people, and is generated from this
13
- > package's source — edit `src/index.ts` JSDoc, not this file.
14
-
15
11
  Base resource patterns for molecule.dev.
16
12
 
17
13
  Provides CRUD operation factories and request handler utilities for
18
14
  building RESTful API resources. Every `@molecule/api-resource-*` package
19
15
  (user, project, device, ...) is built on these factories.
20
16
 
17
+ **A handler returns `{ statusCode, headers?, body }` and NEVER writes to `res`** — not through
18
+ `res.json`, not through `res.send`, not through `res.end`. `createRequestHandler` is the wrapper
19
+ that applies the returned object (`res.set(headers)`, `res.status(statusCode)`, `res.send(body)`),
20
+ and a handler returns `null` only when the request should fall through to `next()`. Calling a
21
+ handler directly from your own route is therefore only correct if you apply that return value
22
+ yourself:
23
+
24
+ ```typescript
25
+ const { statusCode, headers, body } = await handler(req, res)
26
+ if (headers) res.set(headers)
27
+ res.status(statusCode).send(body)
28
+ ```
29
+
30
+ Monkey-patching `res.json` (or `res.send`/`res.end`) to re-shape a handler's answer intercepts
31
+ nothing the handler produces, so the request it was meant to answer is left unanswered and hangs.
32
+
33
+ > **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
34
+ > It is written to be read by coding agents as much as by people, and is generated from this
35
+ > package's source — edit `src/index.ts` JSDoc, not this file.
36
+
21
37
  ## Quick Start
22
38
 
23
39
  ```typescript
@@ -104,10 +120,21 @@ Framework-agnostic HTTP request interface. Structurally compatible with Express'
104
120
  `Request` — Express objects satisfy this interface without adapters, but the type
105
121
  doesn't depend on Express, allowing use with Fastify, Hono, or Lambda.
106
122
 
123
+ `params` is `Record<string, any>` on purpose. Express 5 declares
124
+ `ParamsDictionary` as `{ [key: string]: string | string[] }` — a wildcard or a
125
+ repeated parameter yields an array — so `Record<string, string>` is NOT a
126
+ supertype of it, and every Express handler passing its own `Request` to a
127
+ function declared on this interface (`authorization.set(req, …)`) failed with
128
+ TS2345 and was told to cast. This is the same shape `body` and `query` already
129
+ use. A reader that needs one segment as a string checks it
130
+ (`typeof req.params.id === 'string'`) rather than trusting the annotation;
131
+ the packages that own the routes do exactly that where it matters (see
132
+ `@molecule/api-bonds-default-express`'s `getParamId`).
133
+
107
134
  ```typescript
108
135
  interface MoleculeRequest {
109
136
  body: any
110
- params: Record<string, string>
137
+ params: Record<string, any>
111
138
  query: Record<string, any>
112
139
  headers: Record<string, string | string[] | undefined>
113
140
  cookies?: Record<string, string>
@@ -11,10 +11,21 @@
11
11
  * Framework-agnostic HTTP request interface. Structurally compatible with Express's
12
12
  * `Request` — Express objects satisfy this interface without adapters, but the type
13
13
  * doesn't depend on Express, allowing use with Fastify, Hono, or Lambda.
14
+ *
15
+ * `params` is `Record<string, any>` on purpose. Express 5 declares
16
+ * `ParamsDictionary` as `{ [key: string]: string | string[] }` — a wildcard or a
17
+ * repeated parameter yields an array — so `Record<string, string>` is NOT a
18
+ * supertype of it, and every Express handler passing its own `Request` to a
19
+ * function declared on this interface (`authorization.set(req, …)`) failed with
20
+ * TS2345 and was told to cast. This is the same shape `body` and `query` already
21
+ * use. A reader that needs one segment as a string checks it
22
+ * (`typeof req.params.id === 'string'`) rather than trusting the annotation;
23
+ * the packages that own the routes do exactly that where it matters (see
24
+ * `@molecule/api-bonds-default-express`'s `getParamId`).
14
25
  */
15
26
  export interface MoleculeRequest {
16
27
  body: any;
17
- params: Record<string, string>;
28
+ params: Record<string, any>;
18
29
  query: Record<string, any>;
19
30
  headers: Record<string, string | string[] | undefined>;
20
31
  cookies?: Record<string, string>;
@@ -1 +1 @@
1
- {"version":3,"file":"http-types.d.ts","sourceRoot":"","sources":["../src/http-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,GAAG,CAAA;IACT,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC;;;;OAIG;IACH,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAA;CACjE;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACzB,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACzB,GAAG,IAAI,IAAI,CAAA;IACX,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;IAC1C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAC5E,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;IACtC,YAAY,CAAC,IAAI,IAAI,CAAA;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAC5B;AAED;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;AAE1D;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,CACnC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,oBAAoB,KACvB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA"}
1
+ {"version":3,"file":"http-types.d.ts","sourceRoot":"","sources":["../src/http-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,GAAG,CAAA;IACT,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC;;;;OAIG;IACH,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAA;CACjE;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACzB,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACzB,GAAG,IAAI,IAAI,CAAA;IACX,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;IAC1C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAC5E,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;IACtC,YAAY,CAAC,IAAI,IAAI,CAAA;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAC5B;AAED;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;AAE1D;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,CACnC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,oBAAoB,KACvB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA"}
package/dist/index.d.ts CHANGED
@@ -5,6 +5,22 @@
5
5
  * building RESTful API resources. Every `@molecule/api-resource-*` package
6
6
  * (user, project, device, ...) is built on these factories.
7
7
  *
8
+ * **A handler returns `{ statusCode, headers?, body }` and NEVER writes to `res`** — not through
9
+ * `res.json`, not through `res.send`, not through `res.end`. `createRequestHandler` is the wrapper
10
+ * that applies the returned object (`res.set(headers)`, `res.status(statusCode)`, `res.send(body)`),
11
+ * and a handler returns `null` only when the request should fall through to `next()`. Calling a
12
+ * handler directly from your own route is therefore only correct if you apply that return value
13
+ * yourself:
14
+ *
15
+ * ```typescript
16
+ * const { statusCode, headers, body } = await handler(req, res)
17
+ * if (headers) res.set(headers)
18
+ * res.status(statusCode).send(body)
19
+ * ```
20
+ *
21
+ * Monkey-patching `res.json` (or `res.send`/`res.end`) to re-shape a handler's answer intercepts
22
+ * nothing the handler produces, so the request it was meant to answer is left unanswered and hangs.
23
+ *
8
24
  * @example
9
25
  * ```typescript
10
26
  * import { z } from 'zod'
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqFG;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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqGG;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
@@ -5,6 +5,22 @@
5
5
  * building RESTful API resources. Every `@molecule/api-resource-*` package
6
6
  * (user, project, device, ...) is built on these factories.
7
7
  *
8
+ * **A handler returns `{ statusCode, headers?, body }` and NEVER writes to `res`** — not through
9
+ * `res.json`, not through `res.send`, not through `res.end`. `createRequestHandler` is the wrapper
10
+ * that applies the returned object (`res.set(headers)`, `res.status(statusCode)`, `res.send(body)`),
11
+ * and a handler returns `null` only when the request should fall through to `next()`. Calling a
12
+ * handler directly from your own route is therefore only correct if you apply that return value
13
+ * yourself:
14
+ *
15
+ * ```typescript
16
+ * const { statusCode, headers, body } = await handler(req, res)
17
+ * if (headers) res.set(headers)
18
+ * res.status(statusCode).send(body)
19
+ * ```
20
+ *
21
+ * Monkey-patching `res.json` (or `res.send`/`res.end`) to re-shape a handler's answer intercepts
22
+ * nothing the handler produces, so the request it was meant to answer is left unanswered and hangs.
23
+ *
8
24
  * @example
9
25
  * ```typescript
10
26
  * 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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqFG;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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqGG;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",
3
+ "version": "1.0.5",
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.2",
43
- "@molecule/api-database": "1.1.1",
43
+ "@molecule/api-database": "1.1.3",
44
44
  "@molecule/api-locales-resource": "1.0.2",
45
45
  "@molecule/api-utilities-validation": "1.0.2",
46
46
  "@types/node": "26.1.2",