@kizunajs/express 2.0.0-beta.2 → 2.0.0-beta.21
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 +0 -1
- package/dist/index.cjs +53 -4
- package/dist/index.d.cts +35 -2
- package/dist/index.d.mts +35 -2
- package/dist/index.mjs +55 -7
- package/package.json +5 -5
package/README.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -3,6 +3,51 @@ let express = require("express");
|
|
|
3
3
|
let node_stream = require("node:stream");
|
|
4
4
|
let kizunajs_adapter = require("kizunajs/adapter");
|
|
5
5
|
//#region src/server.ts
|
|
6
|
+
/**
|
|
7
|
+
* Keep the body as it was sent, for routes with `rawBody: true`. Pass it as the
|
|
8
|
+
* `verify` option of an `express.json()` your app runs before kizuna.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* app.use(
|
|
12
|
+
* express.json({
|
|
13
|
+
* verify: keepRawBody,
|
|
14
|
+
* })
|
|
15
|
+
* );
|
|
16
|
+
*/
|
|
17
|
+
const keepRawBody = (req, _res, buffer) => {
|
|
18
|
+
req.rawBody = buffer;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Parse a kizuna route's body, unless the app already parsed it. The parser
|
|
22
|
+
* keeps the text as well, for routes with `rawBody: true`.
|
|
23
|
+
*/
|
|
24
|
+
const bodyParserFor = (route, jsonOptions) => {
|
|
25
|
+
if (route.contentType === "multipart/form-data") return void 0;
|
|
26
|
+
const parse = route.contentType === "application/x-www-form-urlencoded" ? (0, express.urlencoded)({
|
|
27
|
+
extended: false,
|
|
28
|
+
verify: keepRawBody
|
|
29
|
+
}) : (0, express.json)({
|
|
30
|
+
...jsonOptions,
|
|
31
|
+
verify: keepRawBody
|
|
32
|
+
});
|
|
33
|
+
return (req, res, next) => {
|
|
34
|
+
if (req.body !== void 0) {
|
|
35
|
+
next();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
req.kizunaParsedBody = true;
|
|
39
|
+
parse(req, res, next);
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* The body text for a `rawBody` route: what the parser kept, an empty body when
|
|
44
|
+
* kizuna parsed and there was none, or `undefined` when the app's own parser
|
|
45
|
+
* consumed it without keeping it.
|
|
46
|
+
*/
|
|
47
|
+
const rawBodyOf = (req) => {
|
|
48
|
+
if (req.rawBody !== void 0) return req.rawBody.toString("utf8");
|
|
49
|
+
return req.kizunaParsedBody === true ? "" : void 0;
|
|
50
|
+
};
|
|
6
51
|
const writeStream = (open, res, validate) => {
|
|
7
52
|
const controller = new AbortController();
|
|
8
53
|
res.on("close", () => {
|
|
@@ -29,7 +74,7 @@ const writeWebResponse = async (response, res) => {
|
|
|
29
74
|
}
|
|
30
75
|
node_stream.Readable.fromWeb(response.body).pipe(res);
|
|
31
76
|
};
|
|
32
|
-
const adapter = (0, kizunajs_adapter.
|
|
77
|
+
const adapter = (0, kizunajs_adapter.defineAdapter)({
|
|
33
78
|
buildHandlerContext: (adapterRequest, { res }) => ({
|
|
34
79
|
req: adapterRequest.request,
|
|
35
80
|
res
|
|
@@ -81,10 +126,12 @@ function mountExpress(api, app, options) {
|
|
|
81
126
|
const jobRunner = (0, kizunajs_adapter.jobRunnerFrom)(jobsMeta);
|
|
82
127
|
const expressRouter = (0, express.Router)();
|
|
83
128
|
const mountRoute = (routeKey, route, routes, router) => {
|
|
84
|
-
|
|
129
|
+
const method = route.method.toLowerCase();
|
|
130
|
+
const parseBody = bodyParserFor(route, options?.json);
|
|
131
|
+
expressRouter[method](route.path, (req, _res, next) => {
|
|
85
132
|
req.kizunaRoute = route;
|
|
86
133
|
next();
|
|
87
|
-
}, async (req, res, next) => {
|
|
134
|
+
}, ...parseBody === void 0 ? [] : [parseBody], async (req, res, next) => {
|
|
88
135
|
const adapterRequest = {
|
|
89
136
|
request: req,
|
|
90
137
|
method: req.method,
|
|
@@ -96,7 +143,8 @@ function mountExpress(api, app, options) {
|
|
|
96
143
|
},
|
|
97
144
|
query: req.query,
|
|
98
145
|
headers: req.headers,
|
|
99
|
-
readBody: () => req.body
|
|
146
|
+
readBody: () => req.body,
|
|
147
|
+
readRawBody: () => rawBodyOf(req)
|
|
100
148
|
};
|
|
101
149
|
await adapter.handle({
|
|
102
150
|
routes,
|
|
@@ -153,4 +201,5 @@ const expressAdapter = (defaults) => ({
|
|
|
153
201
|
});
|
|
154
202
|
//#endregion
|
|
155
203
|
exports.expressAdapter = expressAdapter;
|
|
204
|
+
exports.keepRawBody = keepRawBody;
|
|
156
205
|
exports.mountExpress = mountExpress;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Request, Response, Router } from "express";
|
|
1
|
+
import { Request, Response, Router, json } from "express";
|
|
2
|
+
import { IncomingMessage, ServerResponse } from "node:http";
|
|
2
3
|
import { Adapter, ApiWithRouter, ErrorFormatter, GUARDS_META, JOBS_META, REQUEST_CONTEXT_META, RouteDefinition, Routes, SCHEMES_META } from "kizunajs/adapter";
|
|
3
4
|
|
|
4
5
|
//#region src/server.d.ts
|
|
@@ -23,9 +24,30 @@ declare global {
|
|
|
23
24
|
namespace Express {
|
|
24
25
|
interface Request {
|
|
25
26
|
kizunaRoute?: RouteDefinition;
|
|
27
|
+
/**
|
|
28
|
+
* The body as it was sent, kept by {@link keepRawBody}.
|
|
29
|
+
*/
|
|
30
|
+
rawBody?: Buffer;
|
|
31
|
+
/**
|
|
32
|
+
* Set when kizuna parsed this request's body itself.
|
|
33
|
+
*/
|
|
34
|
+
kizunaParsedBody?: true;
|
|
26
35
|
}
|
|
27
36
|
}
|
|
28
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Keep the body as it was sent, for routes with `rawBody: true`. Pass it as the
|
|
40
|
+
* `verify` option of an `express.json()` your app runs before kizuna.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* app.use(
|
|
44
|
+
* express.json({
|
|
45
|
+
* verify: keepRawBody,
|
|
46
|
+
* })
|
|
47
|
+
* );
|
|
48
|
+
*/
|
|
49
|
+
declare const keepRawBody: (req: IncomingMessage, _res: ServerResponse, buffer: Buffer) => void;
|
|
50
|
+
type JsonOptions = NonNullable<Parameters<typeof json>[0]>;
|
|
29
51
|
interface ExpressOptions {
|
|
30
52
|
/**
|
|
31
53
|
* Validate handler return values against the route's response schemas.
|
|
@@ -39,6 +61,17 @@ interface ExpressOptions {
|
|
|
39
61
|
* {@link ErrorFormatter}.
|
|
40
62
|
*/
|
|
41
63
|
formatError?: ErrorFormatter<Request>;
|
|
64
|
+
/**
|
|
65
|
+
* The options for `express.json()`, like `limit` and `strict`, used to parse
|
|
66
|
+
* the bodies of kizuna's own routes. An `express.json()` your app runs
|
|
67
|
+
* first takes precedence, and kizuna uses the body it parsed.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* json: {
|
|
71
|
+
* limit: '5mb',
|
|
72
|
+
* }
|
|
73
|
+
*/
|
|
74
|
+
json?: JsonOptions;
|
|
42
75
|
}
|
|
43
76
|
interface AppLike {
|
|
44
77
|
use: (router: Router) => unknown;
|
|
@@ -65,4 +98,4 @@ declare function mountExpress(api: ExpressApi, app: AppLike, options?: ExpressOp
|
|
|
65
98
|
*/
|
|
66
99
|
declare const expressAdapter: (defaults?: ExpressOptions) => Adapter<ExpressHandlerContext, [app: AppLike, options?: ExpressOptions], Router>;
|
|
67
100
|
//#endregion
|
|
68
|
-
export { AppLike, ExpressApi, ExpressHandlerContext, ExpressOptions, expressAdapter, mountExpress };
|
|
101
|
+
export { AppLike, ExpressApi, ExpressHandlerContext, ExpressOptions, expressAdapter, keepRawBody, mountExpress };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Request, Response, Router } from "express";
|
|
1
|
+
import { Request, Response, Router, json } from "express";
|
|
2
2
|
import { Adapter, ApiWithRouter, ErrorFormatter, GUARDS_META, JOBS_META, REQUEST_CONTEXT_META, RouteDefinition, Routes, SCHEMES_META } from "kizunajs/adapter";
|
|
3
|
+
import { IncomingMessage, ServerResponse } from "node:http";
|
|
3
4
|
|
|
4
5
|
//#region src/server.d.ts
|
|
5
6
|
type ExpressApi<R extends Routes = Routes> = ApiWithRouter<R> & {
|
|
@@ -23,9 +24,30 @@ declare global {
|
|
|
23
24
|
namespace Express {
|
|
24
25
|
interface Request {
|
|
25
26
|
kizunaRoute?: RouteDefinition;
|
|
27
|
+
/**
|
|
28
|
+
* The body as it was sent, kept by {@link keepRawBody}.
|
|
29
|
+
*/
|
|
30
|
+
rawBody?: Buffer;
|
|
31
|
+
/**
|
|
32
|
+
* Set when kizuna parsed this request's body itself.
|
|
33
|
+
*/
|
|
34
|
+
kizunaParsedBody?: true;
|
|
26
35
|
}
|
|
27
36
|
}
|
|
28
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Keep the body as it was sent, for routes with `rawBody: true`. Pass it as the
|
|
40
|
+
* `verify` option of an `express.json()` your app runs before kizuna.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* app.use(
|
|
44
|
+
* express.json({
|
|
45
|
+
* verify: keepRawBody,
|
|
46
|
+
* })
|
|
47
|
+
* );
|
|
48
|
+
*/
|
|
49
|
+
declare const keepRawBody: (req: IncomingMessage, _res: ServerResponse, buffer: Buffer) => void;
|
|
50
|
+
type JsonOptions = NonNullable<Parameters<typeof json>[0]>;
|
|
29
51
|
interface ExpressOptions {
|
|
30
52
|
/**
|
|
31
53
|
* Validate handler return values against the route's response schemas.
|
|
@@ -39,6 +61,17 @@ interface ExpressOptions {
|
|
|
39
61
|
* {@link ErrorFormatter}.
|
|
40
62
|
*/
|
|
41
63
|
formatError?: ErrorFormatter<Request>;
|
|
64
|
+
/**
|
|
65
|
+
* The options for `express.json()`, like `limit` and `strict`, used to parse
|
|
66
|
+
* the bodies of kizuna's own routes. An `express.json()` your app runs
|
|
67
|
+
* first takes precedence, and kizuna uses the body it parsed.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* json: {
|
|
71
|
+
* limit: '5mb',
|
|
72
|
+
* }
|
|
73
|
+
*/
|
|
74
|
+
json?: JsonOptions;
|
|
42
75
|
}
|
|
43
76
|
interface AppLike {
|
|
44
77
|
use: (router: Router) => unknown;
|
|
@@ -65,4 +98,4 @@ declare function mountExpress(api: ExpressApi, app: AppLike, options?: ExpressOp
|
|
|
65
98
|
*/
|
|
66
99
|
declare const expressAdapter: (defaults?: ExpressOptions) => Adapter<ExpressHandlerContext, [app: AppLike, options?: ExpressOptions], Router>;
|
|
67
100
|
//#endregion
|
|
68
|
-
export { AppLike, ExpressApi, ExpressHandlerContext, ExpressOptions, expressAdapter, mountExpress };
|
|
101
|
+
export { AppLike, ExpressApi, ExpressHandlerContext, ExpressOptions, expressAdapter, keepRawBody, mountExpress };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,52 @@
|
|
|
1
|
-
import { Router } from "express";
|
|
1
|
+
import { Router, json, urlencoded } from "express";
|
|
2
2
|
import { Readable, pipeline } from "node:stream";
|
|
3
|
-
import { GUARDS_META, JOBS_META, REQUEST_CONTEXT_META, ROUTER_META, SCHEMES_META,
|
|
3
|
+
import { GUARDS_META, JOBS_META, REQUEST_CONTEXT_META, ROUTER_META, SCHEMES_META, defineAdapter, jobRouter, jobRoutes, jobRunnerFrom, pluginExportsOf, pluginRouterOf, pluginRoutesOf, renderJsonResult } from "kizunajs/adapter";
|
|
4
4
|
//#region src/server.ts
|
|
5
|
+
/**
|
|
6
|
+
* Keep the body as it was sent, for routes with `rawBody: true`. Pass it as the
|
|
7
|
+
* `verify` option of an `express.json()` your app runs before kizuna.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* app.use(
|
|
11
|
+
* express.json({
|
|
12
|
+
* verify: keepRawBody,
|
|
13
|
+
* })
|
|
14
|
+
* );
|
|
15
|
+
*/
|
|
16
|
+
const keepRawBody = (req, _res, buffer) => {
|
|
17
|
+
req.rawBody = buffer;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Parse a kizuna route's body, unless the app already parsed it. The parser
|
|
21
|
+
* keeps the text as well, for routes with `rawBody: true`.
|
|
22
|
+
*/
|
|
23
|
+
const bodyParserFor = (route, jsonOptions) => {
|
|
24
|
+
if (route.contentType === "multipart/form-data") return void 0;
|
|
25
|
+
const parse = route.contentType === "application/x-www-form-urlencoded" ? urlencoded({
|
|
26
|
+
extended: false,
|
|
27
|
+
verify: keepRawBody
|
|
28
|
+
}) : json({
|
|
29
|
+
...jsonOptions,
|
|
30
|
+
verify: keepRawBody
|
|
31
|
+
});
|
|
32
|
+
return (req, res, next) => {
|
|
33
|
+
if (req.body !== void 0) {
|
|
34
|
+
next();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
req.kizunaParsedBody = true;
|
|
38
|
+
parse(req, res, next);
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The body text for a `rawBody` route: what the parser kept, an empty body when
|
|
43
|
+
* kizuna parsed and there was none, or `undefined` when the app's own parser
|
|
44
|
+
* consumed it without keeping it.
|
|
45
|
+
*/
|
|
46
|
+
const rawBodyOf = (req) => {
|
|
47
|
+
if (req.rawBody !== void 0) return req.rawBody.toString("utf8");
|
|
48
|
+
return req.kizunaParsedBody === true ? "" : void 0;
|
|
49
|
+
};
|
|
5
50
|
const writeStream = (open, res, validate) => {
|
|
6
51
|
const controller = new AbortController();
|
|
7
52
|
res.on("close", () => {
|
|
@@ -28,7 +73,7 @@ const writeWebResponse = async (response, res) => {
|
|
|
28
73
|
}
|
|
29
74
|
Readable.fromWeb(response.body).pipe(res);
|
|
30
75
|
};
|
|
31
|
-
const adapter =
|
|
76
|
+
const adapter = defineAdapter({
|
|
32
77
|
buildHandlerContext: (adapterRequest, { res }) => ({
|
|
33
78
|
req: adapterRequest.request,
|
|
34
79
|
res
|
|
@@ -80,10 +125,12 @@ function mountExpress(api, app, options) {
|
|
|
80
125
|
const jobRunner = jobRunnerFrom(jobsMeta);
|
|
81
126
|
const expressRouter = Router();
|
|
82
127
|
const mountRoute = (routeKey, route, routes, router) => {
|
|
83
|
-
|
|
128
|
+
const method = route.method.toLowerCase();
|
|
129
|
+
const parseBody = bodyParserFor(route, options?.json);
|
|
130
|
+
expressRouter[method](route.path, (req, _res, next) => {
|
|
84
131
|
req.kizunaRoute = route;
|
|
85
132
|
next();
|
|
86
|
-
}, async (req, res, next) => {
|
|
133
|
+
}, ...parseBody === void 0 ? [] : [parseBody], async (req, res, next) => {
|
|
87
134
|
const adapterRequest = {
|
|
88
135
|
request: req,
|
|
89
136
|
method: req.method,
|
|
@@ -95,7 +142,8 @@ function mountExpress(api, app, options) {
|
|
|
95
142
|
},
|
|
96
143
|
query: req.query,
|
|
97
144
|
headers: req.headers,
|
|
98
|
-
readBody: () => req.body
|
|
145
|
+
readBody: () => req.body,
|
|
146
|
+
readRawBody: () => rawBodyOf(req)
|
|
99
147
|
};
|
|
100
148
|
await adapter.handle({
|
|
101
149
|
routes,
|
|
@@ -151,4 +199,4 @@ const expressAdapter = (defaults) => ({
|
|
|
151
199
|
})
|
|
152
200
|
});
|
|
153
201
|
//#endregion
|
|
154
|
-
export { expressAdapter, mountExpress };
|
|
202
|
+
export { expressAdapter, keepRawBody, mountExpress };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kizunajs/express",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.21",
|
|
4
4
|
"description": "Express adapter for Kizuna.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kizunajs",
|
|
@@ -55,17 +55,17 @@
|
|
|
55
55
|
"access": "public"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
+
"kizunajs": "2.0.0-beta.21",
|
|
58
59
|
"express": "^5.0.0",
|
|
59
|
-
"zod": "^4.0.0"
|
|
60
|
-
"kizunajs": "2.0.0-beta.2"
|
|
60
|
+
"zod": "^4.0.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
+
"kizunajs": "2.0.0-beta.21",
|
|
63
64
|
"@types/express": "^5.0.0",
|
|
64
65
|
"express": "^5.0.0",
|
|
65
66
|
"tsdown": "^0.21.0",
|
|
66
67
|
"typescript": "^6.0.3",
|
|
67
|
-
"zod": "^4.0.0"
|
|
68
|
-
"kizunajs": "2.0.0-beta.2"
|
|
68
|
+
"zod": "^4.0.0"
|
|
69
69
|
},
|
|
70
70
|
"scripts": {
|
|
71
71
|
"build": "tsdown src/index.ts --format esm,cjs --dts --clean --external kizunajs --external express --external zod",
|