@dunx/http 2.3.0 → 2.4.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/dist/health/controller.d.ts +15 -3
- package/dist/health/module.d.ts +5 -4
- package/dist/health/registry.d.ts +8 -0
- package/dist/health/report-schema.d.ts +14 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +118 -12
- package/dist/index.js.map +12 -10
- package/dist/route/schema.d.ts +21 -1
- package/dist/server/context.d.ts +10 -0
- package/dist/server/raw-body.d.ts +21 -0
- package/dist/server/request-logging.d.ts +26 -6
- package/package.json +2 -2
package/dist/route/schema.d.ts
CHANGED
|
@@ -33,6 +33,14 @@ export interface StandardSchemaIssue {
|
|
|
33
33
|
}
|
|
34
34
|
/** The validated output of a schema - `InferOutput<typeof CreateNote>` is `Note`. */
|
|
35
35
|
export type InferOutput<S> = S extends StandardSchemaV1<unknown, infer Out> ? Out : never;
|
|
36
|
+
/**
|
|
37
|
+
* A JSON Schema, as JSON. OpenAPI 3.1 embeds draft 2020-12 verbatim.
|
|
38
|
+
*
|
|
39
|
+
* Declared here rather than in `@dunx/openapi` because {@link RouteSchemas} names
|
|
40
|
+
* it and that package depends on this one, so this is the lowest common owner.
|
|
41
|
+
* `@dunx/openapi` re-exports it.
|
|
42
|
+
*/
|
|
43
|
+
export type JsonSchema = Readonly<Record<string, unknown>>;
|
|
36
44
|
/**
|
|
37
45
|
* The second argument to `@Get`/`@Post`/... Declaring a schema is what makes the
|
|
38
46
|
* matching `input` field appear, get parsed, and get validated; omitting one
|
|
@@ -62,8 +70,20 @@ export interface RouteSchemas {
|
|
|
62
70
|
* cost paid for a documentation feature, which is the wrong trade - the
|
|
63
71
|
* handler's own return type is what checks the answer, at compile time and for
|
|
64
72
|
* free. Nothing in the request path reads this key.
|
|
73
|
+
*
|
|
74
|
+
* A plain {@link JsonSchema} is accepted here too, and only here: a JSON Schema
|
|
75
|
+
* needs no conversion, so documenting a response costs no validator. `$id` names
|
|
76
|
+
* it, hoisting it into `components/schemas` the way `.meta({ id })` does for a
|
|
77
|
+
* zod schema. `body`, `query` and `params` still take a Standard Schema, because
|
|
78
|
+
* those are parsed.
|
|
79
|
+
*
|
|
80
|
+
* ```ts
|
|
81
|
+
* response: {
|
|
82
|
+
* 200: Object.freeze({ $id: 'Pong', type: 'object' }),
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
65
85
|
*/
|
|
66
|
-
readonly response?: Readonly<Record<number, StandardSchemaV1>>;
|
|
86
|
+
readonly response?: Readonly<Record<number, StandardSchemaV1 | JsonSchema>>;
|
|
67
87
|
}
|
|
68
88
|
/**
|
|
69
89
|
* The handler's parameter type, derived from its own options object. It has to be
|
package/dist/server/context.d.ts
CHANGED
|
@@ -11,6 +11,16 @@ export interface RouteContext {
|
|
|
11
11
|
readonly handler: string;
|
|
12
12
|
readonly method: HttpMethod;
|
|
13
13
|
readonly path: string;
|
|
14
|
+
/**
|
|
15
|
+
* Whether this route declares a `body` schema, and therefore whether the input
|
|
16
|
+
* reader will parse the body and record it for anything else that wants it.
|
|
17
|
+
*
|
|
18
|
+
* Resolved here because it is a property of the route, known when the table is
|
|
19
|
+
* built. `RequestLoggingMiddleware` reads it to decide once - not per request -
|
|
20
|
+
* whether logging the body needs a `Request.clone()`, which is the single most
|
|
21
|
+
* expensive thing it can do. See `raw-body.ts`.
|
|
22
|
+
*/
|
|
23
|
+
readonly parsesBody: boolean;
|
|
14
24
|
get<T>(key: MetaKey<T>): T | undefined;
|
|
15
25
|
}
|
|
16
26
|
/**
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BunRequest } from 'bun';
|
|
2
|
+
export declare class RawBody {
|
|
3
|
+
/**
|
|
4
|
+
* Called by `RequestLoggingMiddleware` before the chain runs, when it intends to
|
|
5
|
+
* log this body and the route is going to parse it anyway.
|
|
6
|
+
*/
|
|
7
|
+
static want(req: BunRequest): void;
|
|
8
|
+
/** Whether the body reader should buffer the text on the way past. */
|
|
9
|
+
static wanted(req: BunRequest): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Called by the body reader with the text it buffered, **before** validating it.
|
|
12
|
+
*
|
|
13
|
+
* Before, on purpose, and for two reasons. Validation applies defaults, coerces
|
|
14
|
+
* and strips unknown keys, so the validated object is not what the caller sent.
|
|
15
|
+
* And a body that fails to parse at all still has text - which is the case the
|
|
16
|
+
* clone used to cover and the reason this holds text rather than a value.
|
|
17
|
+
*/
|
|
18
|
+
static record(req: BunRequest, text: string): void;
|
|
19
|
+
/** The buffered text, or `undefined` when nothing read one. */
|
|
20
|
+
static read(req: BunRequest): string | undefined;
|
|
21
|
+
}
|
|
@@ -8,15 +8,35 @@ export interface RequestLoggingOptions {
|
|
|
8
8
|
/**
|
|
9
9
|
* Log the request body. Default **`false`**.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* throughput. It is also the field most likely to contain a password.
|
|
11
|
+
* **What it costs depends on whether the route declares a `body` schema**, and by
|
|
12
|
+
* a factor of fifteen. `bun run logging:bodies` in `internal/bench`, round-robin
|
|
13
|
+
* over 3 runs against `POST /validate`:
|
|
15
14
|
*
|
|
16
|
-
*
|
|
15
|
+
* | setting | us/req | vs the default |
|
|
16
|
+
* | ---------------------------------------- | -----: | -------------: |
|
|
17
|
+
* | `requestLogging: false` | 12.80 | -4.45 us |
|
|
18
|
+
* | the shipped default, both bodies off | 17.25 | - |
|
|
19
|
+
* | **`requestBody: true`, schema route** | **19.12** | **+1.87 us** |
|
|
20
|
+
* | `responseBody: true` | 19.80 | +2.55 us |
|
|
21
|
+
* | both bodies, schema route | 20.03 | +2.78 us |
|
|
22
|
+
* | **`requestBody: true`, no schema** | **46.06** | **+28.81 us** |
|
|
23
|
+
*
|
|
24
|
+
* A route with a schema has already had its body buffered by the input reader, so
|
|
25
|
+
* the logger reads that text and nothing is cloned. A route without one leaves the
|
|
26
|
+
* logger to `req.clone()`, and cloning a request whose body is an unread network
|
|
27
|
+
* stream is the entire cost - not the second `JSON.parse`, which is 0.32 us.
|
|
28
|
+
* `raw-body.ts` has that decomposition.
|
|
29
|
+
*
|
|
30
|
+
* It is the field most likely to contain a password. Turn it on in development,
|
|
31
|
+
* where seeing the payload is the point.
|
|
17
32
|
*/
|
|
18
33
|
readonly requestBody?: boolean;
|
|
19
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* Log the response body. Default **`false`**, +2.55 us - see the table above.
|
|
36
|
+
*
|
|
37
|
+
* No equivalent trick here and none needed: a response is already a materialised
|
|
38
|
+
* string by the time this clones it, which is why it was never the expensive half.
|
|
39
|
+
*/
|
|
20
40
|
readonly responseBody?: boolean;
|
|
21
41
|
/**
|
|
22
42
|
* Paths to skip entirely - a health check polled every second, say.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dunx/http",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Bun.serve adapter for the dunx framework: controllers, middleware and WebSocket gateways",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"@dunx/core": "workspace:*"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"@dunx/core": "^2.
|
|
61
|
+
"@dunx/core": "^2.4.0",
|
|
62
62
|
"@types/bun": ">=1.3.0"
|
|
63
63
|
},
|
|
64
64
|
"peerDependenciesMeta": {
|