rouzer 5.1.0 → 5.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -1
- package/dist/client/index.d.ts +3 -1
- package/dist/http.d.ts +7 -1
- package/dist/http.js +7 -1
- package/dist/types/args.d.ts +4 -2
- package/docs/context.md +32 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ that contract to:
|
|
|
14
14
|
- match and validate server requests before handlers run
|
|
15
15
|
- type handler context from path, query/body, headers, and middleware
|
|
16
16
|
- attach typed client action functions such as `client.profiles.get(...)`
|
|
17
|
+
- send JSON object request bodies or raw `BodyInit` payloads
|
|
17
18
|
- parse typed JSON responses, declared error responses, and NDJSON streams
|
|
18
19
|
|
|
19
20
|
Rouzer optimizes for shared TypeScript route modules over language-agnostic API
|
|
@@ -106,7 +107,8 @@ const { message } = await client.hello({
|
|
|
106
107
|
validate flat route arguments before `fetch`; server handlers validate matched
|
|
107
108
|
path, query, headers, and JSON bodies before your handler runs. Per-request
|
|
108
109
|
headers, abort signals, and other `RequestInit` options are passed as a second
|
|
109
|
-
client action argument.
|
|
110
|
+
client action argument. Routes declared with `body: http.rawBody()` pass a
|
|
111
|
+
`BodyInit` payload through to `fetch` without JSON encoding.
|
|
110
112
|
|
|
111
113
|
### Typed status responses
|
|
112
114
|
|
|
@@ -151,6 +153,34 @@ const [error, user, status] = await client.getUser({ id: '42' })
|
|
|
151
153
|
Success entries resolve as `[null, value, status]`; declared error entries
|
|
152
154
|
resolve as `[error, null, status]`.
|
|
153
155
|
|
|
156
|
+
### Raw request bodies
|
|
157
|
+
|
|
158
|
+
Use `http.rawBody()` when an action needs to send a `BodyInit` payload such as a
|
|
159
|
+
`Blob`, `Uint8Array`, `ReadableStream`, `FormData`, or string without JSON
|
|
160
|
+
encoding.
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
export const uploadAvatar = http.post('profiles/:id/avatar', {
|
|
164
|
+
body: http.rawBody(),
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
await client.uploadAvatar({ id: '42' }, { body: file })
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
For raw-body routes without path or query input, the generated client accepts the
|
|
171
|
+
body as the first argument:
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
export const upload = http.post('upload', {
|
|
175
|
+
body: http.rawBody(),
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
await client.upload(file, { headers: { 'content-type': file.type } })
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Server handlers for raw-body routes read from `ctx.request` directly with Fetch
|
|
182
|
+
APIs such as `arrayBuffer()`, `blob()`, `formData()`, or `text()`.
|
|
183
|
+
|
|
154
184
|
### NDJSON response streams
|
|
155
185
|
|
|
156
186
|
Use `response: ndjson.$type<T>()` for endpoints that stream
|
package/dist/client/index.d.ts
CHANGED
|
@@ -105,7 +105,9 @@ export type ClientTree<T extends HttpRouteTree, TPrefix extends string = ''> = {
|
|
|
105
105
|
* union of `[null, value, status]` success entries and `[error, null, status]`
|
|
106
106
|
* error entries. Actions whose schema has a plugin response marker return the
|
|
107
107
|
* plugin's client result type. Actions without a response marker return the raw
|
|
108
|
-
* `Response`.
|
|
108
|
+
* `Response`. Raw-body actions with no path or query input accept
|
|
109
|
+
* `(body, options)`; raw-body actions with route input accept
|
|
110
|
+
* `(input, { body, ...options })`.
|
|
109
111
|
*/
|
|
110
112
|
export type RouteFunction<T extends RouteSchema, P extends string> = T extends {
|
|
111
113
|
body: RawBodySchema;
|
package/dist/http.d.ts
CHANGED
|
@@ -62,6 +62,12 @@ export declare function patch<const T extends RouteSchema>(schema: T): HttpActio
|
|
|
62
62
|
declare function deleteAction<const P extends string, const T extends RouteSchema>(path: P, schema: T): HttpAction<P, T, 'DELETE'>;
|
|
63
63
|
declare function deleteAction<const T extends RouteSchema>(schema: T): HttpAction<'', T, 'DELETE'>;
|
|
64
64
|
export { deleteAction as delete };
|
|
65
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* Declare a request body that is passed through to `fetch` without JSON encoding.
|
|
67
|
+
*
|
|
68
|
+
* @remarks For routes with path or query input, pass the body as
|
|
69
|
+
* `options.body`. For raw-body routes without input, generated client actions
|
|
70
|
+
* accept the body as their first argument.
|
|
71
|
+
*/
|
|
66
72
|
export declare function rawBody(): RawBodySchema;
|
|
67
73
|
export declare function isRawBodySchema(schema: unknown): schema is RawBodySchema;
|
package/dist/http.js
CHANGED
|
@@ -29,7 +29,13 @@ function deleteAction(pathOrSchema, schema) {
|
|
|
29
29
|
return action('DELETE', pathOrSchema, schema);
|
|
30
30
|
}
|
|
31
31
|
export { deleteAction as delete };
|
|
32
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Declare a request body that is passed through to `fetch` without JSON encoding.
|
|
34
|
+
*
|
|
35
|
+
* @remarks For routes with path or query input, pass the body as
|
|
36
|
+
* `options.body`. For raw-body routes without input, generated client actions
|
|
37
|
+
* accept the body as their first argument.
|
|
38
|
+
*/
|
|
33
39
|
export function rawBody() {
|
|
34
40
|
return { __rawBody__: Symbol('rouzer.rawBody') };
|
|
35
41
|
}
|
package/dist/types/args.d.ts
CHANGED
|
@@ -25,10 +25,12 @@ type HeaderInput<T> = T extends {
|
|
|
25
25
|
*/
|
|
26
26
|
export type RouteInput<T extends RouteSchema = any, P extends string = string> = [T] extends [Any] ? any : PathInput<T, P> & QueryInput<T> & BodyInput<T>;
|
|
27
27
|
/**
|
|
28
|
-
* Fetch options accepted
|
|
28
|
+
* Fetch options accepted by a generated client action.
|
|
29
29
|
*
|
|
30
30
|
* @remarks `headers` remains optional because required route headers may be
|
|
31
|
-
* supplied by `createClient({ headers })` defaults.
|
|
31
|
+
* supplied by `createClient({ headers })` defaults. Raw-body routes with path or
|
|
32
|
+
* query input accept `body` here; raw-body routes without input accept the body
|
|
33
|
+
* as the first client action argument and these options as the second.
|
|
32
34
|
*/
|
|
33
35
|
export type RouteFetchOptions<T extends RouteSchema = any> = Omit<RequestInit, 'method' | 'body' | 'headers'> & {
|
|
34
36
|
/** Headers for this request. Undefined values are removed before `fetch`. */
|
package/docs/context.md
CHANGED
|
@@ -85,7 +85,7 @@ Method schemas describe the request pieces Rouzer should validate:
|
|
|
85
85
|
| Action helper | Request schemas | Notes |
|
|
86
86
|
| --------------------------------- | -------------------------------------- | ---------------- |
|
|
87
87
|
| `http.get(...)` | `path`, `query`, `headers`, `response` | No request body. |
|
|
88
|
-
| `http.post/put/patch/delete(...)` | `path`, `body`, `headers`, `response` | No query schema. |
|
|
88
|
+
| `http.post/put/patch/delete(...)` | `path`, `body`, `headers`, `response` | No query schema. `body` is a Zod object for JSON or `http.rawBody()` for pass-through payloads. |
|
|
89
89
|
|
|
90
90
|
If you omit a `path` schema, TypeScript infers path params from the pattern and
|
|
91
91
|
server handlers receive them as strings. Add a Zod `path` schema when you need
|
|
@@ -215,7 +215,9 @@ requests with an `Origin` header.
|
|
|
215
215
|
`routes`, with action functions such as `client.profiles.get(args)`.
|
|
216
216
|
Generated action functions accept a flattened first argument containing path,
|
|
217
217
|
query, and JSON body fields. Per-request `RequestInit` options, including
|
|
218
|
-
headers and abort signals, are passed as the optional second argument.
|
|
218
|
+
headers and abort signals, are passed as the optional second argument. For
|
|
219
|
+
`http.rawBody()` routes, the raw `BodyInit` payload is passed through to `fetch`
|
|
220
|
+
without JSON encoding.
|
|
219
221
|
|
|
220
222
|
Generated action functions include:
|
|
221
223
|
|
|
@@ -248,8 +250,8 @@ route actions named `config` remain available as `client.config(...)`.
|
|
|
248
250
|
are needed.
|
|
249
251
|
3. Create a client with the same route tree, plus matching client response
|
|
250
252
|
plugins when needed.
|
|
251
|
-
4. Client action calls validate `path`, `query`, `body`, and
|
|
252
|
-
`fetch`.
|
|
253
|
+
4. Client action calls validate `path`, `query`, JSON object `body`, and
|
|
254
|
+
`headers` before `fetch`. Raw bodies are passed through without validation.
|
|
253
255
|
5. The router matches the request, validates the matched inputs, and calls the
|
|
254
256
|
handler.
|
|
255
257
|
6. Plain handler results become JSON responses, response-map helpers choose
|
|
@@ -259,7 +261,8 @@ route actions named `config` remain available as `client.config(...)`.
|
|
|
259
261
|
On the server, `path`, `query`, and `headers` values originate as strings. Rouzer
|
|
260
262
|
coerces Zod `number` schemas with `Number(value)` and Zod `boolean` schemas from
|
|
261
263
|
`"true"` and `"false"`. JSON request bodies are parsed and validated without that
|
|
262
|
-
string-coercion step.
|
|
264
|
+
string-coercion step. Raw request bodies declared with `http.rawBody()` are not
|
|
265
|
+
parsed by Rouzer.
|
|
263
266
|
|
|
264
267
|
## Common tasks
|
|
265
268
|
|
|
@@ -412,8 +415,26 @@ await client.uploadAvatar(
|
|
|
412
415
|
)
|
|
413
416
|
```
|
|
414
417
|
|
|
415
|
-
|
|
416
|
-
|
|
418
|
+
When a raw-body route has path or query input, path/query fields still live in
|
|
419
|
+
the flat first argument. The raw body itself is passed as `body` in the second
|
|
420
|
+
argument because it is a `RequestInit` value.
|
|
421
|
+
|
|
422
|
+
For raw-body routes without path or query input, the generated client action
|
|
423
|
+
accepts the body as the first argument and fetch options as the second:
|
|
424
|
+
|
|
425
|
+
```ts
|
|
426
|
+
export const upload = http.post('uploads', {
|
|
427
|
+
body: http.rawBody(),
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
await client.upload(file, {
|
|
431
|
+
headers: { 'content-type': file.type },
|
|
432
|
+
})
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
Server handlers for raw-body routes read from `ctx.request` directly with Fetch
|
|
436
|
+
APIs such as `arrayBuffer()`, `blob()`, `formData()`, or `text()`. Rouzer does
|
|
437
|
+
not parse or validate raw request bodies.
|
|
417
438
|
|
|
418
439
|
### Return custom responses
|
|
419
440
|
|
|
@@ -515,8 +536,10 @@ await client.profiles.update({ id: '42', name: 'Ada' })
|
|
|
515
536
|
strings passed to `http.resource(...)` and action helpers.
|
|
516
537
|
- Path, query, and JSON body fields are flattened into the first client action
|
|
517
538
|
argument. Per-request `RequestInit` fields, such as `signal`, `credentials`,
|
|
518
|
-
and `headers`, belong in the second argument. `method` is reserved by Rouzer
|
|
519
|
-
`body` is
|
|
539
|
+
and `headers`, belong in the second argument. `method` is reserved by Rouzer.
|
|
540
|
+
For `http.rawBody()` actions, `body` is accepted in the second argument when
|
|
541
|
+
the route has path or query input; raw-body actions without route input accept
|
|
542
|
+
the body as the first argument.
|
|
520
543
|
- The HTTP action API has no `ALL` fallback route. Declare explicit actions for
|
|
521
544
|
supported methods.
|
|
522
545
|
- Rouzer does not automatically set `Access-Control-Allow-Credentials`; set it in
|