@thednp/rpc 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +43 -26
- package/CHANGELOG.md +100 -0
- package/README.md +39 -31
- package/dist/express/express.d.mts +14 -2
- package/dist/express/express.d.mts.map +1 -1
- package/dist/express/express.mjs +103 -70
- package/dist/express/express.mjs.map +1 -1
- package/dist/fastify/fastify.d.mts +16 -1
- package/dist/fastify/fastify.d.mts.map +1 -1
- package/dist/fastify/fastify.mjs +61 -63
- package/dist/fastify/fastify.mjs.map +1 -1
- package/dist/fastify/plugin/fastify/plugin.d.mts +20 -3
- package/dist/fastify/plugin/fastify/plugin.d.mts.map +1 -1
- package/dist/fastify/plugin/fastify/plugin.mjs +60 -62
- package/dist/fastify/plugin/fastify/plugin.mjs.map +1 -1
- package/dist/h3/h3.d.mts +94 -0
- package/dist/h3/h3.d.mts.map +1 -0
- package/dist/h3/h3.mjs +267 -0
- package/dist/h3/h3.mjs.map +1 -0
- package/dist/helpers/helpers.d.mts +2 -0
- package/dist/helpers/helpers.d.mts.map +1 -1
- package/dist/helpers/helpers.mjs.map +1 -1
- package/dist/hono/hono.d.mts +14 -40
- package/dist/hono/hono.d.mts.map +1 -1
- package/dist/hono/hono.mjs +61 -73
- package/dist/hono/hono.mjs.map +1 -1
- package/dist/index.d.mts +36 -5
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -0
- package/dist/index.mjs.map +1 -1
- package/dist/koa/koa.d.mts +12 -1
- package/dist/koa/koa.d.mts.map +1 -1
- package/dist/koa/koa.mjs +69 -64
- package/dist/koa/koa.mjs.map +1 -1
- package/dist/server/server.d.mts +180 -3
- package/dist/server/server.d.mts.map +1 -1
- package/dist/server/server.mjs +157 -1
- package/dist/server/server.mjs.map +1 -1
- package/package.json +10 -4
package/AGENTS.md
CHANGED
|
@@ -6,8 +6,11 @@
|
|
|
6
6
|
pnpm dev # Run examples/spa dev server
|
|
7
7
|
pnpm dev:express # Run examples/express dev server
|
|
8
8
|
pnpm dev:fastify # Run examples/fastify dev server
|
|
9
|
+
pnpm dev:h3 # Run examples/h3 dev server
|
|
9
10
|
pnpm dev:hono # Run examples/hono dev server
|
|
10
11
|
pnpm dev:koa # Run examples/koa dev server
|
|
12
|
+
pnpm dev:react-query # Run examples/react-query dev server
|
|
13
|
+
pnpm dev:solid-query # Run examples/solid-query dev server
|
|
11
14
|
pnpm dev:ssr # Run examples/ssr dev server
|
|
12
15
|
pnpm lint # Lint + typecheck (deno lint + tsc)
|
|
13
16
|
pnpm test # Run tests with coverage
|
|
@@ -32,32 +35,39 @@ pnpm release # Publish npm + jsr (scripts/release.js)
|
|
|
32
35
|
|
|
33
36
|
## Examples
|
|
34
37
|
|
|
35
|
-
The `examples/` directory contains
|
|
38
|
+
The `examples/` directory contains 9 example apps:
|
|
36
39
|
|
|
37
|
-
| Example
|
|
38
|
-
|
|
|
39
|
-
| `spa`
|
|
40
|
-
| `express`
|
|
41
|
-
| `fastify`
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
40
|
+
| Example | Adapter | Type | Run Command | Config |
|
|
41
|
+
| ----------------| -------------------------------------------------------------------| ------| -------------------------| -----------------------------------------|
|
|
42
|
+
| `spa` | Vite dev server (no adapter) | SPA | `pnpm dev` | `examples/spa/rpc.config.ts` |
|
|
43
|
+
| `express` | Express | SSR | `pnpm dev:express` | `examples/express/rpc.config.ts` |
|
|
44
|
+
| `fastify` | Fastify | SSR | `pnpm dev:fastify` | `examples/fastify/rpc.config.ts` |
|
|
45
|
+
| `h3` | h3 | SSR | `pnpm dev:h3` | `examples/h3/rpc.config.ts` |
|
|
46
|
+
| `hono` | Hono | SSR | `pnpm dev:hono` | `examples/hono/rpc.config.ts` |
|
|
47
|
+
| `koa` | Koa | SSR | `pnpm dev:koa` | `examples/koa/rpc.config.ts` |
|
|
48
|
+
| `react-query` | Express (React + @tanstack/react-query SSR) | SSR | `pnpm dev:react-query` | `examples/react-query/rpc.config.ts` |
|
|
49
|
+
| `solid-query` | Express (Solid + @tanstack/solid-query SSR) | SSR | `pnpm dev:solid-query` | `examples/solid-query/rpc.config.ts` |
|
|
50
|
+
| `ssr` | Custom `http-express.ts` (Express-compatible `node:http` server ) | SSR | `pnpm dev:ssr` | `examples/ssr/rpc.config.ts` |
|
|
45
51
|
|
|
46
52
|
Each example follows the same structure:
|
|
47
53
|
|
|
48
54
|
- `server.js` / `server.ts` — production server with Vite middleware in dev, static serving in prod
|
|
49
55
|
- `src/api/server.ts` — RPC server functions (auto-scanned by the plugin)
|
|
50
|
-
- `src/entry-server.ts` — SSR entry (hydrates on client)
|
|
51
|
-
- `src/entry-client.ts` — Client entry
|
|
56
|
+
- `src/entry-server.ts` / `src/entry-server.tsx` — SSR entry (hydrates on client)
|
|
57
|
+
- `src/entry-client.ts` / `src/entry-client.tsx` — Client entry
|
|
52
58
|
- `vite.config.ts` + `rpc.config.ts` — Configuration files
|
|
53
59
|
|
|
60
|
+
> Note: the `react-query` example is SSR with React 19 + `@tanstack/react-query` (Express adapter). It prefetches queries in `entry-server.tsx`, dehydrates them into `window.__REACT_QUERY_STATE__`, and hydrates on the client via `HydrationBoundary`.
|
|
61
|
+
>
|
|
62
|
+
> Note: the `solid-query` example is SSR with Solid + `@tanstack/solid-query` (Express adapter). The greeting is prefetched and serialized with `renderToStringAsync`; the GET form does **not** use a disabled `createQuery` (which would hang SSR — see `wiki/client-usage.md`), it calls `queryClient.fetchQuery()` on submit instead.
|
|
63
|
+
|
|
54
64
|
## Key Directories
|
|
55
65
|
|
|
56
|
-
- `src/` — source for all packages (vite plugin, server, express, fastify, hono, koa adapters)
|
|
66
|
+
- `src/` — source for all packages (vite plugin, server, express, fastify, h3, hono, koa adapters)
|
|
57
67
|
- `dist/` — build output (not committed, generated by tsdown)
|
|
58
|
-
- `tests/` — test files (one per adapter + plugin)
|
|
68
|
+
- `tests/` — test files (one per adapter + plugin + helpers)
|
|
59
69
|
- `tests/fixtures/` — test fixtures (config files, vite-mock.ts)
|
|
60
|
-
- `examples/` — example apps (spa, express, fastify, hono, koa, ssr)
|
|
70
|
+
- `examples/` — example apps (spa, express, fastify, h3, hono, koa, react-query, solid-query, ssr)
|
|
61
71
|
|
|
62
72
|
## Build Output (tsdown)
|
|
63
73
|
|
|
@@ -67,19 +77,24 @@ The tsdown.config.ts produces multiple entries:
|
|
|
67
77
|
- `dist/server/server.mjs` — standalone server
|
|
68
78
|
- `dist/express/express.mjs` — Express middleware
|
|
69
79
|
- `dist/fastify/fastify.mjs` — Fastify middleware
|
|
80
|
+
- `dist/h3/h3.mjs` — h3 middleware
|
|
70
81
|
- `dist/hono/hono.mjs` — Hono middleware
|
|
71
82
|
- `dist/koa/koa.mjs` — Koa middleware
|
|
72
83
|
|
|
73
84
|
## Test Files
|
|
74
85
|
|
|
75
|
-
| File
|
|
76
|
-
|
|
|
77
|
-
| `tests/plugin.test.ts`
|
|
78
|
-
| `tests/
|
|
79
|
-
| `tests/
|
|
80
|
-
| `tests/
|
|
81
|
-
| `tests/
|
|
82
|
-
| `tests/
|
|
86
|
+
| File | Tests | |
|
|
87
|
+
| ---------------------------------| --------------------------------------------------------------------| -----|
|
|
88
|
+
| `tests/plugin.test.ts` | Plugin init, loadRPCConfig, createServerFunction, getClientModules | |
|
|
89
|
+
| `tests/scan.test.ts` | scanForServerFiles (real scan, skip, devServer, error handling) | |
|
|
90
|
+
| `tests/server-helpers.test.ts` | RPCError, formatError, redirect, glob walking | |
|
|
91
|
+
| `tests/client-helpers.test.ts` | Client fetch stubs and retrieval helpers | |
|
|
92
|
+
| `tests/context.test.ts` | provideRequestContext / getRequestContext (AsyncLocalStorage) | |
|
|
93
|
+
| `tests/express.test.ts` | Express helpers, createMiddleware, createRPCMiddleware | |
|
|
94
|
+
| `tests/fastify.test.ts` | Fastify helpers, plugin, createMiddleware, createRPCMiddleware | |
|
|
95
|
+
| `tests/h3.test.ts` | h3 helpers, viteMiddleware, createMiddleware, createRPCMiddleware | |
|
|
96
|
+
| `tests/hono.test.ts` | Hono helpers, createMiddleware, createRPCMiddleware | |
|
|
97
|
+
| `tests/koa.test.ts` | Koa helpers, createMiddleware, createRPCMiddleware | |
|
|
83
98
|
|
|
84
99
|
## Important Notes
|
|
85
100
|
|
|
@@ -105,7 +120,7 @@ The tsdown.config.ts produces multiple entries:
|
|
|
105
120
|
- **Koa URL normalization**: Koa adapter parses `ctx.url` through `new URL()` to strip query strings and normalize encoding before prefix checking
|
|
106
121
|
- **Code injection prevention in client module generation**: `getClientModules.ts` validates all interpolated identifiers (`fnName`, `fnEntry`, `rpcPrefix`) against `/^[A-Za-z_$][A-Za-z0-9_$]*$/` (and a path-safe variant allowing `/`) before interpolating into the generated client bundle. This prevents code injection via malicious export names or prefixes containing template literal interpolations (`${...}`), backticks, or `</script>` sequences.
|
|
107
122
|
- **Body size limits**: Host frameworks cap parsed JSON bodies — Express (`express.json({ limit })`), Fastify (`bodyLimit`), Koa (`koa-body`), Hono (`hono/body-limit`). Rely on your framework's body parser middleware for size limits (see wiki/best-practices.md). The raw stream path in `readBody` does not impose a built-in limit — use framework middleware or a custom body limit handler for defense-in-depth.
|
|
108
|
-
- **Generic 404 responses**: Error messages
|
|
123
|
+
- **Generic 404 responses**: Error messages never echo the requested function name (no message-based function enumeration). Note the status code still distinguishes unknown (`404`) from known functions (`405`/`415`/`403`); function names ship in the client bundle so they are not secret — see `wiki/security.md`
|
|
109
124
|
- **Auth is middleware's responsibility**: Authentication should be handled by middleware registered before `createRPCMiddleware()`. The middleware chain naturally composes — no built-in auth hook is needed.
|
|
110
125
|
- **No client-side secrets or stack traces**: Error responses always return `"Internal Server Error"` regardless of the underlying error; `console.error(String(err))` is server-side only for debugging and does not surface internals to the client
|
|
111
126
|
|
|
@@ -129,16 +144,18 @@ The framework's security boundary is the **RPC prefix-gated HTTP endpoint**. Inp
|
|
|
129
144
|
**Attackers are expected to**:
|
|
130
145
|
- Be free to send as many requests as the host allows (no rate limiting — host's responsibility)
|
|
131
146
|
- Be free to hit any URL (no auth — host's responsibility via prior middleware)
|
|
132
|
-
- Be rejected with generic
|
|
147
|
+
- Be rejected with generic error bodies (no function-name disclosure in messages, no stack traces); status-code differential still reveals existence — see `wiki/security.md`
|
|
133
148
|
|
|
134
149
|
## Documentation
|
|
135
150
|
|
|
136
151
|
- `wiki/quickstart.md` — Rebuild the Express SSR example from `create-vite` in under a minute (copy-paste)
|
|
137
152
|
- `wiki/getting-started.md` — Installation, project structure, auto-scanning, and your first function
|
|
138
153
|
- `wiki/configuration.md` — Configuration reference (`rpc.config.ts`, `vite.config.ts`, options)
|
|
139
|
-
- `wiki/server-functions.md` — `createServerFunction` API, methods, validation
|
|
154
|
+
- `wiki/server-functions.md` — `createServerFunction` API, methods, validation, **request context (`getRequestContext`/`provideRequestContext`)** for per-request data access across async call stacks
|
|
155
|
+
- `wiki/middleware.md` — universal adapter-agnostic middleware via the request context (`locals` bridge, `getRequestMeta`, `sendResponse`, `functionName`)
|
|
156
|
+
- `wiki/nojs-fallback.md` — native (no-JS) `<form>` fallback / progressive enhancement pattern
|
|
140
157
|
- `wiki/client-usage.md` — Client-side usage, type safety, react-query integration
|
|
141
158
|
- `wiki/wire-protocol.md` — HTTP contract, request/response bodies, curl debugging
|
|
142
|
-
- `wiki/adapters.md` — Framework adapters (Express, Fastify, Hono, Koa)
|
|
159
|
+
- `wiki/adapters.md` — Framework adapters (Express, Fastify, Hono, Koa, h3)
|
|
143
160
|
- `wiki/security.md` — Security hardening
|
|
144
161
|
- `wiki/best-practices.md` — Production patterns (auth, rate limiting, body limits, CSRF)
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,105 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.1] - 2026-08-10
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- **`send` on the request context**: `RequestEvent.send(status, body, headers?)` (plus the `sent` flag) lets middleware and server functions short-circuit the RPC dispatch with a full HTTP response instead of the `{ data }` envelope, mirroring the existing `redirect`/`redirected` pair. All five adapters bind it and skip their JSON send when `sent` is set: Express (via `getResponseDetails().sendResponse`), Fastify (`reply.header()` loop + `reply.status().send()`), Koa (`ctx.set()` loop + `ctx.status`/`ctx.body`), Hono (records only — the post-dispatch handler returns `c.body(JSON.stringify(body), status, { "content-type": "application/json", ...headers })`), and h3 (records only — the post-dispatch handler sets `event.res.status` and `event.res.headers` then returns the body)
|
|
8
|
+
- **`functionName` on the request context**: `RequestEvent.functionName` exposes the dispatched function name so universal middleware can branch per function (e.g. rate limits, per-function authorization)
|
|
9
|
+
- **`sendResponse` helper**: a `sendResponse(status, body, headers?)` context helper, the response counterpart to the `redirect` helper, delegating to the same adapter-bound write path
|
|
10
|
+
- **`getRequestMeta(event)`**: a normalized request reader returning `{ method, pathname, search, searchParams, headers, host, ip, protocol }`, duck-typed across all five adapter request shapes — feature-detects fetch-like `Headers` (h3/Hono) vs plain maps (Express/Fastify/Koa), resolves the URL from `originalUrl ?? url ?? path`, and derives `host`/`protocol`/`ip` with safe fallbacks
|
|
11
|
+
|
|
12
|
+
### Examples
|
|
13
|
+
|
|
14
|
+
- **h3 example**: extract `middleware/bodyLimit.js` — delegates to h3's native `assertBodySize`, which swaps `event.req` for a bounded stream so the cap is enforced while streaming (never fully buffered) and the RPC `readBody` can still consume it afterwards; oversized bodies reject with `413` JSON. Extract `middleware/serveStatic.js` — aliases h3's `serveStatic` from `h3/node`, adds `Content-Length`, `Last-Modified`, and `Cache-Control: public, max-age=31536000, immutable`, and is registered **after** `createRPCMiddleware()` so asset requests never reach server functions; missing files fall through to the SSR handler
|
|
15
|
+
- **demo**: the prerender plugin now writes the app content between `<!-- app-content -->` markers and gains a `configurePreviewServer` middleware that re-renders just that region from the URL query — nojs form state (values + errors) is recovered in `vite preview`, where the baked `dist/index.html` shell otherwise skips `transformIndexHtml`
|
|
16
|
+
- **demo**: `body-limit.ts` stashes multipart bodies as `{ raw: body }` to mirror `@thednp/rpc/express`'s `readBody` streaming semantics; the render page and `getLibraryInfo` now count 9 examples and list the h3 adapter; the features grid grows to 9 cards (3×3) with request-context, no-JS form-fallback, and boundary-enforcement entries
|
|
17
|
+
- **fastify example**: switch the production server to `@fastify/compress` (gzip) for the RPC endpoint and static HTML. `@fastify/compress` attaches its per-route `onSend` hook via `onRoute`, which never fires for the RPC plugin's global `preHandler` handling, so the example registers a scoped `app.post("/_server/*")` catch-all route — the RPC `preHandler` short-circuits before the handler runs, letting compress's hook attach to RPC POSTs while non-RPC POSTs still get a 404. Verified with curl: HTML and RPC POST responses (200 and 404) compress (gzip) with byte-identical decompression (md5 match), and non-RPC POSTs keep their 404
|
|
18
|
+
- Sync all 9 examples to `@thednp/rpc ^0.2.0`
|
|
19
|
+
|
|
20
|
+
### Docs
|
|
21
|
+
|
|
22
|
+
- **New `wiki/middleware.md`** — universal adapter-agnostic middleware via the request context: the `locals` bridge table (Express `res.locals`, Koa `ctx.state`, h3 `event.context`, Fastify/Hono `{}` with `decorateRequest`/`c.set` workarounds), `getRequestMeta`, `functionName`, `sendResponse` per-adapter mapping, and wrap recipes for official framework middleware (Express session, Koa `ctx.state`, h3 `event.context`, Fastify `decorateRequest`, Hono `c.set`/`c.get`)
|
|
23
|
+
- TOC sweep: `- [Middleware](./middleware.md)` entry added to all 11 wiki pages after Server Functions; cross-linked from `server-functions.md` (RequestEvent shape + "Writing Universal Middleware" section), `best-practices.md` (Authentication, Rate Limiting), and `adapters.md`; `wiki/index.md` updated
|
|
24
|
+
- Update `wiki/server-functions.md` RequestEvent reference for `send`/`sent`/`functionName` and re-point its "Next" pointer to `middleware.md`
|
|
25
|
+
- `wiki/nojs-fallback.md`: explain the form markup and detection rule without embedding the whole `createFormFallback` implementation (now links to `demo/src/lib/form-fallback.ts`)
|
|
26
|
+
- `wiki/adapters.md`: replace the h3 body-limit snippet with h3's native `assertBodySize` pattern (bounded stream, never buffered) and add a **Static Assets** section for the extracted `serveStatic` middleware; `wiki/best-practices.md` h3 body limit now recommends `assertBodySize` and warns against iterating `event.req` (which breaks the RPC `readBody` with "Body is unusable")
|
|
27
|
+
- Update `AGENTS.md` (9 examples, h3 adapter, test files table), `llms.txt`, and `README.md` (five adapters, 10 test files, `nojs-fallback` doc link, `pmpm` → `pnpm` typo) for the new adapter, examples, and context API
|
|
28
|
+
- Example READMEs: add the `wiki/middleware.md` resource link to all 9 example READMEs; rewrite `examples/solid-query/README.md` (was a copy-paste of the react-query README — now describes Solid's `createQuery`/`createMutation`, `renderToStringAsync` SSR, and the disabled-query gotcha); expand the h3 example README's production flow for the extracted `bodyLimit`/`serveStatic` middleware
|
|
29
|
+
|
|
30
|
+
### Tests
|
|
31
|
+
|
|
32
|
+
- **100% coverage across all adapters**: 1001/1001 statements, 608/608 branches, 155/155 functions, 981/981 lines (412 tests)
|
|
33
|
+
- Add `send` short-circuit tests to the Express, Fastify, and Koa suites — both with headers (asserting the `headers` loop) and without (covering the `if (headers)` false branch that had dropped branch coverage below 100%)
|
|
34
|
+
- Add `tests/context.test.ts` suite: `sendResponse` delegation (with/without headers, outside-request throw), `getRequestMeta` normalization (Express-style, fetch-like `Headers`, `ip`/`protocol` derivation, bare request, plain-map headers, array-valued header, URL protocol fallback), and `functionName` passthrough
|
|
35
|
+
- Adapter suites assert `functionName` exposure via `getRequestContext()` and `send` short-circuits the JSON dispatch on all five adapters
|
|
36
|
+
- Add `?args=` non-array rejection tests (400 Bad Request) and bare-GET (no `?args=`) dispatch tests to all five adapter suites — **100/100% coverage, 412 tests**
|
|
37
|
+
|
|
38
|
+
### Security
|
|
39
|
+
|
|
40
|
+
- **`safeURL` defensive URL parsing**: `getRequestDetails()` and every adapter's inline `new URL(rawUrl, ...)` call now parse through `safeURL` (`src/server-helpers.ts`), which never throws — a malformed request-target like `/\` or `//` used to trigger an unhandled `TypeError: Invalid URL` rejection outside the dispatch `try` block and **crash raw `node:http` hosts** (and Express 4). Malformed URLs now fall back to a safe root pathname that never matches the RPC prefix, so the request degrades to `next()`/404 instead of crashing the process (High)
|
|
41
|
+
- **GET `?args=` is now validated as a JSON array**: a non-array value (e.g. `?args={"a":1}`) previously spread into `handler(...args)` and threw a confusing `TypeError: object is not iterable` 500; all five adapters now reject it with `400 { error: "Bad Request" }` before dispatch
|
|
42
|
+
- **`wiki/security.md` enumeration claim corrected**: the "prevents function enumeration" wording was overstated — the status code still distinguishes unknown (`404`) from known (`405`/`415`/`403`) functions. Documented that enumeration is mitigated against *message* disclosure only; function names ship in the client bundle so they are not secret. `AGENTS.md` and `llms.txt` updated to match
|
|
43
|
+
- Full source security audit recorded in `SECURITY-AUDIT.md` (High crash finding fixed; remaining findings are LOW/INFO/design notes)
|
|
44
|
+
|
|
45
|
+
### Chores
|
|
46
|
+
|
|
47
|
+
- Bump version to `0.2.1` (package.json + deno.json)
|
|
48
|
+
- Add `@thednp/rpc@0.2.0` to `minimumReleaseAgeExclude` in `pnpm-workspace.yaml`
|
|
49
|
+
|
|
50
|
+
## [0.2.0] - 2026-08-09
|
|
51
|
+
|
|
52
|
+
### Features
|
|
53
|
+
|
|
54
|
+
- **h3 adapter**: new `@thednp/rpc/h3` adapter with `createRPCMiddleware`, `viteMiddleware`, `attachRPC`, `attachVite`, `readBody`, `redirect` — fully typed, 100% test coverage, SSR example at `examples/h3`
|
|
55
|
+
- **Request Context API**: `provideRequestContext(init, cb)` / `getRequestContext()` — per-request `AsyncLocalStorage` context available to all server function code; `RequestEvent` includes `nativeEvent`, `locals`, adapter-bound `redirect`; works across Express, Fastify, Hono, Koa, and h3
|
|
56
|
+
- **`redirect` helper**: a new `redirect(res, location, status?)` server utility exported from `@thednp/rpc/server` and every adapter. It defaults to `303 See Other` for Post/Redirect/Get flows. The core version accepts an Express `Response` or a raw Node `ServerResponse`, delegating to native `res.redirect()` when available and otherwise writing the status code and `Location` header directly — the raw path is safe on Connect-compatible middlewares and serverless adapters (e.g. Netlify's `serverless-http` mock). Each adapter exports a redirect typed for its response object: Fastify `reply.redirect(location, status)` (v5 URL-first), Koa `ctx.redirect(location)` then `ctx.status = status` (setting status *after*, per koajs/koa#857), and Hono `return redirect(c, location, status)` (the `Response` is returned from the handler)
|
|
57
|
+
|
|
58
|
+
- **`application/x-www-form-urlencoded` content type**: the `contentType` option and `BodyResult` now include urlencoded. The generated client serializes the single object argument with `new URLSearchParams(args[0]).toString()`, so native HTML forms can POST straight to an RPC endpoint without client-side serialization. Adapters parse `key=value&key2=value2` into an object via `URLSearchParams` (every value arrives as a string; repeated keys collapse to the last value) and use the framework's pre-parsed body (`express.urlencoded()`, `@fastify/formbody`, `koa-body`) when one ran first
|
|
59
|
+
- **Content-type enforcement**: the RPC middleware now validates the request's `Content-Type` against the function's declared `contentType` before parsing the body, rejecting mismatches with `415 Unsupported Media Type` on all four adapters. JSON and text functions are enforced strictly (exact match wins after stripping `charset`/`boundary` parameters); form functions (`multipart/form-data` or `application/x-www-form-urlencoded`) are lenient between the two encodings so native urlencoded form submissions keep working on multipart-declared endpoints. Requests without a `Content-Type` header (curl, GET, legacy clients) are exempt from enforcement. The check lives in the new `hasContentTypeMismatch`/`isFormContentType` helpers exported from `@thednp/rpc/server`
|
|
60
|
+
|
|
61
|
+
### Examples
|
|
62
|
+
|
|
63
|
+
- Add the `h3` example (`examples/h3`): SSR with [h3](https://h3.unjs.io/) using `createRPCMiddleware`, `serveStatic`, `toNodeListener`, and `viteMiddleware`. Dev mode bridges Vite's connect stack; prod serves static assets via `serveStatic` and falls through to SSR.
|
|
64
|
+
- The `demo` form-fallback middleware now uses the new `redirect` helper from `@thednp/rpc/express` instead of hand-writing the `303` + `Location` response
|
|
65
|
+
- Add a nojs fallback to the `demo` contact form (progressive enhancement): the form now carries native `action="/@demo/submit-contact" method="post"` attributes, and a small app-layer `createFormFallback` middleware (mounted before the RPC middleware) intercepts browser form navigations — recognized by `POST` + `application/x-www-form-urlencoded` + `Accept: text/html`, which the JS client never sends. Valid submissions get a `303` redirect to the pre-filled GitHub issue URL; invalid ones get a `303` redirect back to `/?name=..&errors=..`, where the server-rendered page (and hydration) recover the form values and show the same field-level error messages the RPC path would have returned. Validation, issue-URL building, and field lists are shared with the server function via the new `demo/src/lib/contact-form.ts`, and the server function now normalizes both multipart (`{ raw }`) and plain-object (urlencoded/JSON-with-fields) payloads
|
|
66
|
+
- Add the `react-query` example (Express + React 19 + `@tanstack/react-query` SSR): prefetches the greeting in `entry-server.tsx`, dehydrates it into `window.__REACT_QUERY_STATE__`, and hydrates on the client via `HydrationBoundary`
|
|
67
|
+
- Add the `solid-query` example (Express + Solid + `@tanstack/solid-query` SSR): prefetches the greeting, serializes it with `renderToStringAsync`, and documents the disabled-query SSR gotcha — a disabled `createQuery` hangs `renderToStringAsync` because the observer result carries a never-settling `promise` (from `experimental_prefetchInRender`) that seroval awaits forever; the example calls `queryClient.fetchQuery()` on submit instead
|
|
68
|
+
|
|
69
|
+
### Docs
|
|
70
|
+
|
|
71
|
+
- Document Request Context API (`provideRequestContext`/`getRequestContext`) in `wiki/server-functions.md` — per-request `AsyncLocalStorage` context with `nativeEvent`, `locals`, adapter-bound `redirect` across all 5 adapters
|
|
72
|
+
- Document urlencoded content type in `wiki/server-functions.md` and `wiki/wire-protocol.md` (new `POST + application/x-www-form-urlencoded` section)
|
|
73
|
+
- Document the `415 Unsupported Media Type` response and content-type enforcement rules in `wiki/wire-protocol.md`
|
|
74
|
+
- Document the strict/lenient content-type behavior in `wiki/server-functions.md`
|
|
75
|
+
- Add a "Content-Type Enforcement" section to `wiki/security.md`
|
|
76
|
+
- Document the `redirect` helper in `wiki/server-functions.md` (new "Redirects (`redirect`)" section) and cross-reference it from `wiki/adapters.md`
|
|
77
|
+
- Add h3 adapter section to `wiki/adapters.md` (installation, usage, body limits)
|
|
78
|
+
- Add h3 body limits to `wiki/best-practices.md` (Content-Length fast path + streaming cap via `for await (const chunk of event.req.body)`)
|
|
79
|
+
- Update `llms.txt`, `AGENTS.md`, and `README.md` for the new adapter, examples, content type, enforcement behavior, redirect helper, and request context
|
|
80
|
+
|
|
81
|
+
### Tests
|
|
82
|
+
|
|
83
|
+
- **100% coverage achieved** across all adapters (express, fastify, h3, hono, koa) — 920/920 statements, 559/559 branches, 144/144 functions, 898/898 lines
|
|
84
|
+
- Add h3 adapter test suite (`tests/h3.test.ts`): viteMiddleware (node/web runtime paths, settle-twice guard), createMiddleware (prefix/path filtering, name deduplication), createRPCMiddleware (dispatch, content-type enforcement, origin check, redirect default 303, cancel on close, error handling)
|
|
85
|
+
- Add redirect default-status tests to Express, Fastify, Hono, and Koa adapter suites (covers `status = 303` default param branch)
|
|
86
|
+
- Add urlencoded `readBody` tests for all four adapters (pre-parsed and raw stream paths), a urlencoded client-module codegen test in `plugin.test.ts`, and an end-to-end RPC middleware dispatch test
|
|
87
|
+
- Add content-type enforcement tests to the Express, Fastify, Hono, and Koa adapter suites (415 on json↔urlencoded/text↔json mismatch, lenient acceptance of urlencoded on multipart-declared functions) and unit tests for `hasContentTypeMismatch`/`isFormContentType` (parameter stripping, case insensitivity, no-header exemption, form leniency both directions)
|
|
88
|
+
- Add `redirect` tests: raw `ServerResponse` write path and native `.redirect()` delegation in `server-helpers.test.ts`, plus per-adapter suites asserting each framework API (Express `res.redirect(status, url)` vs raw write, Fastify URL-first `reply.redirect`, Koa status-after-`ctx.redirect`, Hono returning `c.redirect`'s `Response`)
|
|
89
|
+
- Fix `scripts/dev-test.js` to verify the query-framework examples' dynamically rendered greeting (`Hello Jane!`) instead of only the static `Hello World!` SSR marker; register the `solid-query` example prefix
|
|
90
|
+
|
|
91
|
+
### Chores
|
|
92
|
+
|
|
93
|
+
- Bump version to `0.2.0`
|
|
94
|
+
- Sync `deno.json` version with `package.json`
|
|
95
|
+
|
|
96
|
+
### Security
|
|
97
|
+
|
|
98
|
+
- **Content-type check moved before body read**: all four adapters now evaluate `hasContentTypeMismatch` *before* calling `readBody`, so mismatched requests are rejected with `415 Unsupported Media Type` without ever buffering/parsing the body (previously the body was read first, contradicting the documented behavior)
|
|
99
|
+
- **Streaming body-limit in the demo**: `demo/body-limit.ts` no longer buffers the entire body via `readBody` before checking the cap. It enforces the 1MB limit while the request stream is being read (dropping buffered chunks and destroying the request on overflow) and adds a `Content-Length` fast-path for obviously oversized requests — closing a memory-exhaustion gap on the demo's raw `node:http` and Netlify entry points
|
|
100
|
+
- **Netlify URL rewrite tightened**: `demo/netlify/functions/rpc.ts` now matches the `/.netlify/functions/rpc/` marker against the parsed `pathname` only (prefix match), instead of `indexOf` on the raw URL which could match inside a query string and rewrite unintended requests
|
|
101
|
+
- **`@hono/node-server` dedupe**: add a workspace `overrides: { '@hono/node-server': '>=2.0.5' }` in `pnpm-workspace.yaml` to collapse the vulnerable `1.19.17` transitive dependency (via `@hono/vite-dev-server`, which pins `^1.19.11`) onto the already-used patched `2.1.0`. `pnpm audit` is now clean
|
|
102
|
+
|
|
3
103
|
## [0.1.1] - 2026-08-07
|
|
4
104
|
|
|
5
105
|
### Security
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[](https://jsr.io/@thednp/rpc)
|
|
7
7
|
[](http://npm-stat.com/charts.html?package=@thednp/rpc)
|
|
8
8
|
|
|
9
|
-
A Vite plugin for automatic RPC generation —
|
|
9
|
+
A Vite plugin for automatic RPC generation — write server functions, re-export them, call them. Simple and framework agnostic.
|
|
10
10
|
|
|
11
11
|
## Isomorphic Design
|
|
12
12
|
|
|
@@ -35,7 +35,7 @@ You define them in a file, import and call them where you need them. The plugin
|
|
|
35
35
|
* `createFunction.ts` — server-side definition (wrapped handler with `AbortController`)
|
|
36
36
|
* `getClientModules.ts` — build-time code generation (string template with validation)
|
|
37
37
|
* `client-helpers.ts` — client-side runtime (thin `fetch` based modules)
|
|
38
|
-
* `server-helpers.ts` — server-only utilities (`RPCError`, error formatting, glob file walking)
|
|
38
|
+
* `server-helpers.ts` — server-only utilities (`RPCError`, error formatting, `redirect`, glob file walking)
|
|
39
39
|
* `scanForServerFiles.ts` — file discovery
|
|
40
40
|
* **Adapters** — thin middleware wrappers
|
|
41
41
|
</details>
|
|
@@ -78,7 +78,7 @@ Every server function call returns a handle with a `cancel()` helper. Under the
|
|
|
78
78
|
<details>
|
|
79
79
|
<summary><b>Your server framework is your business</b></summary>
|
|
80
80
|
|
|
81
|
-
The core plugin doesn't care whether you're running Express, Fastify, Hono, or
|
|
81
|
+
The core plugin doesn't care whether you're running Express, Fastify, Hono, Koa, or h3. Adapters for all five are bundled with the package — you import the one you need, register it as middleware, and you're done. If you're building a plain SPA with no server framework at all, the Vite dev server handles RPC requests directly in development. No adapter needed.
|
|
82
82
|
</details>
|
|
83
83
|
|
|
84
84
|
<details>
|
|
@@ -90,7 +90,7 @@ Scan `src/api/` for classic `server.ts|js|mjs|mts` files, or switch to glob mode
|
|
|
90
90
|
<details>
|
|
91
91
|
<summary><b>Typed errors, safe by default</b></summary>
|
|
92
92
|
|
|
93
|
-
Server errors return a generic `Internal Server Error` — no messages, codes, or stacks leak to clients, in any environment. Only `RPCError` payloads (developer-authored `message`/`code`/`data`) reach the client, and only in development, so you can debug instantly. `multipart/form-data` content type is supported for file uploads via your framework's multipart parser.
|
|
93
|
+
Server errors return a generic `Internal Server Error` — no messages, codes, or stacks leak to clients, in any environment. Only `RPCError` payloads (developer-authored `message`/`code`/`data`) reach the client, and only in development, so you can debug instantly. `multipart/form-data` content type is supported for file uploads via your framework's multipart parser, and json/text/urlencoded requests are validated against the function's declared content type (`415 Unsupported Media Type` on mismatch; form encodings are interchangeable for nojs form fallbacks).
|
|
94
94
|
</details>
|
|
95
95
|
|
|
96
96
|
<details>
|
|
@@ -99,29 +99,29 @@ Server errors return a generic `Internal Server Error` — no messages, codes, o
|
|
|
99
99
|
Generic type inference flows from your server function's arguments and return type all the way to the client stub. You get autocomplete for function names, argument types, and return types without writing a single type annotation on the client side.
|
|
100
100
|
</details>
|
|
101
101
|
|
|
102
|
-
##
|
|
103
|
-
|
|
104
|
-
| Example | Source Code | Try online |
|
|
105
|
-
| -----------------| --------------------------------------------------------------------------------| ------------------------------------------------------------------------------------------|
|
|
106
|
-
| SPA - node:http | [examples/spa](https://github.com/thednp/rpc/tree/master/examples/spa) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/spa) |
|
|
107
|
-
| SSR - node:http | [examples/ssr](https://github.com/thednp/rpc/tree/master/examples/ssr) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/ssr) |
|
|
108
|
-
| Express | [examples/express](https://github.com/thednp/rpc/tree/master/examples/express) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/express) |
|
|
109
|
-
| Fastify | [examples/fastify](https://github.com/thednp/rpc/tree/master/examples/fastify) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/fastify) |
|
|
110
|
-
| Hono | [examples/hono](https://github.com/thednp/rpc/tree/master/examples/hono) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/hono) |
|
|
111
|
-
| Koa | [examples/koa](https://github.com/thednp/rpc/tree/master/examples/koa) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/koa) |
|
|
102
|
+
## Examples
|
|
112
103
|
|
|
113
|
-
|
|
104
|
+
| Source | Demo | Clone |
|
|
105
|
+
| ----------------------------------------------------------------------------------------| ----------------------------------------------------------------------------------------------| ---------------------------------------------------------|
|
|
106
|
+
| [examples/spa](https://github.com/thednp/rpc/tree/master/examples/spa) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/spa) | `pnpm dlx degit thednp/rpc/examples/spa my-app` |
|
|
107
|
+
| [examples/ssr](https://github.com/thednp/rpc/tree/master/examples/ssr) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/ssr) | `pnpm dlx degit thednp/rpc/examples/ssr my-app` |
|
|
108
|
+
| [examples/express](https://github.com/thednp/rpc/tree/master/examples/express) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/express) | `pnpm dlx degit thednp/rpc/examples/express my-app` |
|
|
109
|
+
| [examples/fastify](https://github.com/thednp/rpc/tree/master/examples/fastify) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/fastify) | `pnpm dlx degit thednp/rpc/examples/fastify my-app` |
|
|
110
|
+
| [examples/h3](https://github.com/thednp/rpc/tree/master/examples/h3) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/h3) | `pnpm dlx degit thednp/rpc/examples/h3 my-app` |
|
|
111
|
+
| [examples/hono](https://github.com/thednp/rpc/tree/master/examples/hono) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/hono) | `pnpm dlx degit thednp/rpc/examples/hono my-app` |
|
|
112
|
+
| [examples/koa](https://github.com/thednp/rpc/tree/master/examples/koa) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/koa) | `pnpm dlx degit thednp/rpc/examples/koa my-app` |
|
|
113
|
+
| [examples/react-query](https://github.com/thednp/rpc/tree/master/examples/react-query) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/react-query) | `pnpm dlx degit thednp/rpc/examples/react-query my-app` |
|
|
114
|
+
| [examples/solid-query](https://github.com/thednp/rpc/tree/master/examples/solid-query) | [StackBlitz](https://stackblitz.com/fork/github/thednp/rpc/tree/master/examples/solid-query) | `pnpm dlx degit thednp/rpc/examples/solid-query my-app` |
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
> **Clone an example**: `degit` scaffolds a fresh copy straight from the repo — no git history, ready to run:
|
|
116
117
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
| ssr | Custom `node:http` (Express-compatible) | SSR | `pnpm dev:ssr` | Direct import (SSR) + client stubs |
|
|
118
|
+
```bash
|
|
119
|
+
# Scaffold the Express example
|
|
120
|
+
pnpm dlx degit thednp/rpc/examples/express my-rpc-app
|
|
121
|
+
cd my-rpc-app
|
|
122
|
+
pnpm install
|
|
123
|
+
pnpm dev
|
|
124
|
+
```
|
|
125
125
|
|
|
126
126
|
SSR examples demonstrate isomorphic usage: server functions are imported directly during server-side rendering (`entry-server.ts`) and also called from the client via auto-generated fetch stubs. The SPA example uses only the client-side stubs.
|
|
127
127
|
|
|
@@ -249,7 +249,7 @@ pnpm test-ui # Run tests with UI
|
|
|
249
249
|
pnpm test --run # Single run
|
|
250
250
|
```
|
|
251
251
|
|
|
252
|
-
Tests use **Vitest** with **Istanbul** coverage —
|
|
252
|
+
Tests use **Vitest** with **Istanbul** coverage — 10 test files covering the plugin, scanning, server/client helpers, request context, and all five adapters, at 100% coverage.
|
|
253
253
|
|
|
254
254
|
### Live Testing
|
|
255
255
|
|
|
@@ -319,6 +319,12 @@ The `readBody` utility of each adapter doesn't cap raw request bodies by default
|
|
|
319
319
|
Server functions only support `GET` and `POST` (default `POST`). RPC dispatch is not REST — `PUT`/`PATCH`/`DELETE` carry resource semantics that don't apply to function calls, and `OPTIONS` must stay reserved for CORS preflight. Every accepted method is another dispatch path to validate; keeping the surface minimal (and defaulting to `POST`) reduces CSRF and parsing attack surface. See [Server Functions Guide](./wiki/server-functions.md) for details.
|
|
320
320
|
</details>
|
|
321
321
|
|
|
322
|
+
<details>
|
|
323
|
+
<summary><b>Content-type enforcement</b></summary>
|
|
324
|
+
|
|
325
|
+
Request bodies are validated against the function's declared `contentType` before parsing — mismatches get a `415 Unsupported Media Type`. JSON and text functions require an exact match (after stripping `charset`/`boundary` parameters); the two form encodings are interchangeable so native urlencoded `<form>` submissions keep working on multipart-declared endpoints (nojs progressive enhancement). Requests without a `Content-Type` header are exempt, so curl and `GET` keep working unchanged. See [Wire Protocol](./wiki/wire-protocol.md) for details.
|
|
326
|
+
</details>
|
|
327
|
+
|
|
322
328
|
---
|
|
323
329
|
The full threat model, including edge cases and configuration options for tightening things further, is documented in [Security](./wiki/security.md).
|
|
324
330
|
|
|
@@ -327,13 +333,15 @@ The full threat model, including edge cases and configuration options for tighte
|
|
|
327
333
|
|
|
328
334
|
- [Quick Start](./wiki/quickstart.md) — Rebuild the Express SSR example from `create-vite` in under a minute
|
|
329
335
|
- [Getting Started](./wiki/getting-started.md) — Installation, project structure, and your first function
|
|
330
|
-
- [Configuration](./wiki/configuration.md)
|
|
331
|
-
- [Server Functions](./wiki/server-functions.md)
|
|
332
|
-
- [
|
|
336
|
+
- [Configuration](./wiki/configuration.md) — Full configuration reference
|
|
337
|
+
- [Server Functions](./wiki/server-functions.md) — Creating server functions
|
|
338
|
+
- [Middleware](./wiki/middleware.md) — Universal middleware via the request context
|
|
339
|
+
- [Native Form Fallback](./wiki/nojs-fallback.md) — Making RPC endpoints work as a no-JS `<form>` action
|
|
340
|
+
- [Client Usage](./wiki/client-usage.md) — Client-side usage
|
|
333
341
|
- [Wire Protocol](./wiki/wire-protocol.md) — The HTTP contract behind the generated clients (curl debugging)
|
|
334
|
-
- [Adapters](./wiki/adapters.md)
|
|
335
|
-
- [Best Practices](./wiki/best-practices.md)
|
|
336
|
-
- [Security](./wiki/security.md)
|
|
342
|
+
- [Adapters](./wiki/adapters.md) — Framework adapters
|
|
343
|
+
- [Best Practices](./wiki/best-practices.md) — Tips and best practices
|
|
344
|
+
- [Security](./wiki/security.md) — Security hardening
|
|
337
345
|
|
|
338
346
|
## License
|
|
339
347
|
|
|
@@ -38,7 +38,7 @@ type ResponseDetails = {
|
|
|
38
38
|
/** Sets the response status code */
|
|
39
39
|
setStatusCode: (code: number) => void;
|
|
40
40
|
/** Sends a JSON response with the given status code and output */
|
|
41
|
-
sendResponse: (code: number, output:
|
|
41
|
+
sendResponse: (code: number, output: JsonValue) => void;
|
|
42
42
|
};
|
|
43
43
|
/**
|
|
44
44
|
* Normalized view of an incoming request: URL parts, headers, and method.
|
|
@@ -107,6 +107,18 @@ declare const isExpressRequest: (req: IncomingMessage | Request) => req is Reque
|
|
|
107
107
|
* @returns True if the response is an Express Response
|
|
108
108
|
*/
|
|
109
109
|
declare const isExpressResponse: (res: ServerResponse | Response) => res is Response;
|
|
110
|
+
/**
|
|
111
|
+
* Issues an HTTP redirect on an Express or raw Node ServerResponse.
|
|
112
|
+
* Uses Express's native `res.redirect(status, location)` when an Express
|
|
113
|
+
* Response is provided, otherwise writes the status code and `Location`
|
|
114
|
+
* header directly on the raw `ServerResponse` (safe for Connect-compatible
|
|
115
|
+
* middlewares and serverless adapters whose mock responses lack `.redirect`).
|
|
116
|
+
* Defaults to `303 See Other` for convention (Post/Redirect/Get).
|
|
117
|
+
* @param res - Express Response or raw Node ServerResponse
|
|
118
|
+
* @param location - The URL to redirect to
|
|
119
|
+
* @param status - HTTP status code, defaults to 303
|
|
120
|
+
*/
|
|
121
|
+
declare const redirect: (res: ServerResponse | Response, location: string, status?: number) => void;
|
|
110
122
|
/**
|
|
111
123
|
* Type guard that checks whether a request has a pre-parsed body (`body` property).
|
|
112
124
|
* Used to detect if a body-parser middleware already consumed the stream.
|
|
@@ -129,5 +141,5 @@ declare const getRequestDetails: (request: Request | IncomingMessage) => Request
|
|
|
129
141
|
*/
|
|
130
142
|
declare const getResponseDetails: (response: Response | ServerResponse) => ResponseDetails;
|
|
131
143
|
//#endregion
|
|
132
|
-
export { type ExpressMiddlewareFn, type ExpressMiddlewareHooks, type ExpressMiddlewareOptions, type RequestDetails, type ResponseDetails, attachRPC, attachVite, createMiddleware, createRPCMiddleware, getRequestDetails, getResponseDetails, hasPreParsedBody, isExpressRequest, isExpressResponse, readBody };
|
|
144
|
+
export { type ExpressMiddlewareFn, type ExpressMiddlewareHooks, type ExpressMiddlewareOptions, type RequestDetails, type ResponseDetails, attachRPC, attachVite, createMiddleware, createRPCMiddleware, getRequestDetails, getResponseDetails, hasPreParsedBody, isExpressRequest, isExpressResponse, readBody, redirect };
|
|
133
145
|
//# sourceMappingURL=express.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express.d.mts","names":[],"sources":["../../src/express/types.d.ts","../../src/express/createMiddleware.ts","../../src/express/helpers.ts"],"mappings":";;;;;;;;KAgBY,2BAA2B;;;;;KAM3B,uBACV,UAAU,yCAEV,iBAAiB,QAAQ,8BACtB;;;;UAKY;;;;;;;EAOf,UACE,KAAK,kBAAkB,SACvB,KAAK,iBAAiB,UACtB,MAAM,QAAQ,eAAe,iBAC1B;;;;;;KAOK;;EAEV;;EAEA,YAAY,cAAc;;EAE1B;;EAEA,gBAAgB;;EAEhB,eAAe,cAAc,QAAQ
|
|
1
|
+
{"version":3,"file":"express.d.mts","names":[],"sources":["../../src/express/types.d.ts","../../src/express/createMiddleware.ts","../../src/express/helpers.ts"],"mappings":";;;;;;;;KAgBY,2BAA2B;;;;;KAM3B,uBACV,UAAU,yCAEV,iBAAiB,QAAQ,8BACtB;;;;UAKY;;;;;;;EAOf,UACE,KAAK,kBAAkB,SACvB,KAAK,iBAAiB,UACtB,MAAM,QAAQ,eAAe,iBAC1B;;;;;;KAOK;;EAEV;;EAEA,YAAY,cAAc;;EAE1B;;EAEA,gBAAgB;;EAEhB,eAAe,cAAc,QAAQ;;;;;KAM3B;;EAEV;;EAEA;;EAEA,cAAc;;EAEd,SAAS;;EAET;;;;;;;;;;;cC1BW,kBAAkB;;;;;;;;cAyElB,qBAAqB;;;;;;;;iBCvGZ,UAAU,KAAK,UAAO;;;;;;iBAc5B,WAAW,KAAK,SAAS,MAAM;;;;;;;;cAWlC,WAAQ,KACd,UAAiB,oBACrB,QAAQ;;;;;;cAqFE,mBAAgB,KACtB,kBAAkB,YACtB,OAAO;;;;;;cASG,oBAAiB,KACvB,iBAAiB,aACrB,OAAO;;;;;;;;;;;;cAeG,WAAQ,KACd,iBAAiB,UAAe,kBACrB;;;;;;;cAkBL,mBAAgB,KACtB,kBAAkB,YACtB,OAAO;;;;;;;cAUG,oBAAiB,SACnB,UAAiB,oBACzB;;;;;;;cAqBU,qBAAkB,UACnB,WAAkB,mBAC3B"}
|