@react-router/express 7.16.0 → 8.0.0-pre.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/CHANGELOG.md +1 -1
- package/dist/index.d.ts +14 -10
- package/dist/index.js +58 -108
- package/package.json +19 -28
- package/dist/index.d.mts +0 -26
- package/dist/index.mjs +0 -103
package/CHANGELOG.md
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
7
|
- Ignore writes after Express responses close ([#15107](https://github.com/remix-run/react-router/pull/15107))
|
|
8
|
-
|
|
9
8
|
- Avoid surfacing client disconnects as adapter errors when the response stream has already been destroyed or ended.
|
|
9
|
+
|
|
10
10
|
- Updated dependencies:
|
|
11
11
|
- [`react-router@7.16.0`](https://github.com/remix-run/react-router/releases/tag/react-router@7.16.0)
|
|
12
12
|
- [`@react-router/node@7.16.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@7.16.0)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as express from 'express';
|
|
2
|
-
import { UNSAFE_MiddlewareEnabled, RouterContextProvider, AppLoadContext, ServerBuild } from 'react-router';
|
|
3
1
|
|
|
4
|
-
|
|
2
|
+
import { RouterContextProvider, ServerBuild } from "react-router";
|
|
3
|
+
import * as express from "express";
|
|
5
4
|
|
|
5
|
+
//#region server.d.ts
|
|
6
6
|
type MaybePromise<T> = T | Promise<T>;
|
|
7
7
|
/**
|
|
8
8
|
* A function that returns the value to use as `context` in route `loader` and
|
|
@@ -12,15 +12,19 @@ type MaybePromise<T> = T | Promise<T>;
|
|
|
12
12
|
* environment/platform-specific values through to your loader/action, such as
|
|
13
13
|
* values that are generated by Express middleware like `req.session`.
|
|
14
14
|
*/
|
|
15
|
-
type GetLoadContextFunction = (req: express.Request, res: express.Response) =>
|
|
15
|
+
type GetLoadContextFunction = (req: express.Request, res: express.Response) => MaybePromise<RouterContextProvider>;
|
|
16
16
|
type RequestHandler = (req: express.Request, res: express.Response, next: express.NextFunction) => Promise<void>;
|
|
17
17
|
/**
|
|
18
18
|
* Returns a request handler for Express that serves the response using Remix.
|
|
19
19
|
*/
|
|
20
|
-
declare function createRequestHandler({
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
declare function createRequestHandler({
|
|
21
|
+
build,
|
|
22
|
+
getLoadContext,
|
|
23
|
+
mode
|
|
24
|
+
}: {
|
|
25
|
+
build: ServerBuild | (() => Promise<ServerBuild>);
|
|
26
|
+
getLoadContext?: GetLoadContextFunction;
|
|
27
|
+
mode?: string;
|
|
24
28
|
}): RequestHandler;
|
|
25
|
-
|
|
26
|
-
export { type GetLoadContextFunction, type RequestHandler, createRequestHandler };
|
|
29
|
+
//#endregion
|
|
30
|
+
export { type GetLoadContextFunction, type RequestHandler, createRequestHandler };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @react-router/express
|
|
2
|
+
* @react-router/express v8.0.0-pre.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -8,119 +8,69 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return to;
|
|
27
|
-
};
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// index.ts
|
|
31
|
-
var index_exports = {};
|
|
32
|
-
__export(index_exports, {
|
|
33
|
-
createRequestHandler: () => createRequestHandler
|
|
34
|
-
});
|
|
35
|
-
module.exports = __toCommonJS(index_exports);
|
|
36
|
-
|
|
37
|
-
// server.ts
|
|
38
|
-
var import_react_router = require("react-router");
|
|
39
|
-
var import_node = require("@react-router/node");
|
|
40
|
-
function createRequestHandler({
|
|
41
|
-
build,
|
|
42
|
-
getLoadContext,
|
|
43
|
-
mode = process.env.NODE_ENV
|
|
44
|
-
}) {
|
|
45
|
-
let handleRequest = (0, import_react_router.createRequestHandler)(build, mode);
|
|
46
|
-
return async (req, res, next) => {
|
|
47
|
-
try {
|
|
48
|
-
let request = createRemixRequest(req, res);
|
|
49
|
-
let loadContext = await getLoadContext?.(req, res);
|
|
50
|
-
let response = await handleRequest(request, loadContext);
|
|
51
|
-
await sendRemixResponse(res, response);
|
|
52
|
-
} catch (error) {
|
|
53
|
-
next(error);
|
|
54
|
-
}
|
|
55
|
-
};
|
|
11
|
+
import { createRequestHandler as createRequestHandler$1 } from "react-router";
|
|
12
|
+
import { createReadableStreamFromReadable, writeReadableStreamToWritable } from "@react-router/node";
|
|
13
|
+
//#region server.ts
|
|
14
|
+
/**
|
|
15
|
+
* Returns a request handler for Express that serves the response using Remix.
|
|
16
|
+
*/
|
|
17
|
+
function createRequestHandler({ build, getLoadContext, mode = process.env.NODE_ENV }) {
|
|
18
|
+
let handleRequest = createRequestHandler$1(build, mode);
|
|
19
|
+
return async (req, res, next) => {
|
|
20
|
+
try {
|
|
21
|
+
await sendRemixResponse(res, await handleRequest(createRemixRequest(req, res), await getLoadContext?.(req, res)));
|
|
22
|
+
} catch (error) {
|
|
23
|
+
next(error);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
56
26
|
}
|
|
57
27
|
function createRemixHeaders(requestHeaders) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
for (let value of values) {
|
|
63
|
-
headers.append(key, value);
|
|
64
|
-
}
|
|
65
|
-
} else {
|
|
66
|
-
headers.set(key, values);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return headers;
|
|
28
|
+
let headers = new Headers();
|
|
29
|
+
for (let [key, values] of Object.entries(requestHeaders)) if (values) if (Array.isArray(values)) for (let value of values) headers.append(key, value);
|
|
30
|
+
else headers.set(key, values);
|
|
31
|
+
return headers;
|
|
71
32
|
}
|
|
72
33
|
function createRemixRequest(req, res) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
34
|
+
let [, hostnamePortStr] = req.get("X-Forwarded-Host")?.split(":") ?? [];
|
|
35
|
+
let [, hostPortStr] = req.get("host")?.split(":") ?? [];
|
|
36
|
+
let hostnamePort = Number.parseInt(hostnamePortStr, 10);
|
|
37
|
+
let hostPort = Number.parseInt(hostPortStr, 10);
|
|
38
|
+
let port = Number.isSafeInteger(hostnamePort) ? hostnamePort : Number.isSafeInteger(hostPort) ? hostPort : "";
|
|
39
|
+
let resolvedHost = `${req.hostname}${port ? `:${port}` : ""}`;
|
|
40
|
+
let url = new URL(`${req.protocol}://${resolvedHost}${req.originalUrl}`);
|
|
41
|
+
let controller = new AbortController();
|
|
42
|
+
let init = {
|
|
43
|
+
method: req.method,
|
|
44
|
+
headers: createRemixHeaders(req.headers),
|
|
45
|
+
signal: controller.signal
|
|
46
|
+
};
|
|
47
|
+
res.on("finish", () => controller = null);
|
|
48
|
+
res.on("close", () => controller?.abort());
|
|
49
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
50
|
+
init.body = createReadableStreamFromReadable(req);
|
|
51
|
+
init.duplex = "half";
|
|
52
|
+
}
|
|
53
|
+
return new Request(url.href, init);
|
|
93
54
|
}
|
|
94
55
|
async function sendRemixResponse(res, nodeResponse) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
} catch (error) {
|
|
111
|
-
if (isResponseClosed(res)) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
throw error;
|
|
115
|
-
}
|
|
116
|
-
} else {
|
|
117
|
-
res.end();
|
|
118
|
-
}
|
|
56
|
+
if (isResponseClosed(res)) {
|
|
57
|
+
await nodeResponse.body?.cancel();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
res.statusMessage = nodeResponse.statusText;
|
|
61
|
+
res.status(nodeResponse.status);
|
|
62
|
+
for (let [key, value] of nodeResponse.headers.entries()) res.append(key, value);
|
|
63
|
+
if (nodeResponse.headers.get("Content-Type")?.match(/text\/event-stream/i)) res.flushHeaders();
|
|
64
|
+
if (nodeResponse.body) try {
|
|
65
|
+
await writeReadableStreamToWritable(nodeResponse.body, res);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
if (isResponseClosed(res)) return;
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
else res.end();
|
|
119
71
|
}
|
|
120
72
|
function isResponseClosed(res) {
|
|
121
|
-
|
|
73
|
+
return res.destroyed || res.writableEnded;
|
|
122
74
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
createRequestHandler
|
|
126
|
-
});
|
|
75
|
+
//#endregion
|
|
76
|
+
export { createRequestHandler };
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-router/express",
|
|
3
|
-
"
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "8.0.0-pre.0",
|
|
4
5
|
"description": "Express server request handler for React Router",
|
|
5
6
|
"bugs": {
|
|
6
7
|
"url": "https://github.com/remix-run/react-router/issues"
|
|
@@ -15,25 +16,15 @@
|
|
|
15
16
|
"typings": "dist/index.d.ts",
|
|
16
17
|
"exports": {
|
|
17
18
|
".": {
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"default": "./dist/index.js"
|
|
22
|
-
},
|
|
23
|
-
"import": {
|
|
24
|
-
"types": "./dist/index.d.mts",
|
|
25
|
-
"default": "./dist/index.mjs"
|
|
26
|
-
},
|
|
27
|
-
"default": {
|
|
28
|
-
"types": "./dist/index.d.ts",
|
|
29
|
-
"default": "./dist/index.js"
|
|
30
|
-
}
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"module-sync": "./dist/index.js",
|
|
21
|
+
"default": "./dist/index.js"
|
|
31
22
|
},
|
|
32
23
|
"./package.json": "./package.json"
|
|
33
24
|
},
|
|
34
25
|
"wireit": {
|
|
35
26
|
"build": {
|
|
36
|
-
"command": "
|
|
27
|
+
"command": "tsdown",
|
|
37
28
|
"files": [
|
|
38
29
|
"../../pnpm-workspace.yaml",
|
|
39
30
|
"*.ts",
|
|
@@ -46,23 +37,23 @@
|
|
|
46
37
|
}
|
|
47
38
|
},
|
|
48
39
|
"dependencies": {
|
|
49
|
-
"@react-router/node": "
|
|
40
|
+
"@react-router/node": "8.0.0-pre.0"
|
|
50
41
|
},
|
|
51
42
|
"devDependencies": {
|
|
52
|
-
"@types/express": "^4.17.
|
|
53
|
-
"@types/node": "^
|
|
54
|
-
"@types/supertest": "^2.0
|
|
55
|
-
"express": "^4.
|
|
56
|
-
"node-mocks-http": "^1.
|
|
57
|
-
"supertest": "^
|
|
58
|
-
"
|
|
59
|
-
"typescript": "^
|
|
60
|
-
"wireit": "0.14.
|
|
43
|
+
"@types/express": "^4.17.25",
|
|
44
|
+
"@types/node": "^22.19.19",
|
|
45
|
+
"@types/supertest": "^7.2.0",
|
|
46
|
+
"express": "^4.22.2",
|
|
47
|
+
"node-mocks-http": "^1.17.2",
|
|
48
|
+
"supertest": "^7.2.2",
|
|
49
|
+
"tsdown": "^0.22.0",
|
|
50
|
+
"typescript": "^6.0.3",
|
|
51
|
+
"wireit": "0.14.12"
|
|
61
52
|
},
|
|
62
53
|
"peerDependencies": {
|
|
63
|
-
"express": "^4.
|
|
54
|
+
"express": "^4.22.2 || ^5",
|
|
64
55
|
"typescript": "^5.1.0 || ^6.0.0",
|
|
65
|
-
"react-router": "
|
|
56
|
+
"react-router": "8.0.0-pre.0"
|
|
66
57
|
},
|
|
67
58
|
"peerDependenciesMeta": {
|
|
68
59
|
"typescript": {
|
|
@@ -70,7 +61,7 @@
|
|
|
70
61
|
}
|
|
71
62
|
},
|
|
72
63
|
"engines": {
|
|
73
|
-
"node": ">=
|
|
64
|
+
"node": ">=22.12.0"
|
|
74
65
|
},
|
|
75
66
|
"files": [
|
|
76
67
|
"dist/",
|
package/dist/index.d.mts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import * as express from 'express';
|
|
2
|
-
import { UNSAFE_MiddlewareEnabled, RouterContextProvider, AppLoadContext, ServerBuild } from 'react-router';
|
|
3
|
-
|
|
4
|
-
/// <reference lib="dom.iterable" />
|
|
5
|
-
|
|
6
|
-
type MaybePromise<T> = T | Promise<T>;
|
|
7
|
-
/**
|
|
8
|
-
* A function that returns the value to use as `context` in route `loader` and
|
|
9
|
-
* `action` functions.
|
|
10
|
-
*
|
|
11
|
-
* You can think of this as an escape hatch that allows you to pass
|
|
12
|
-
* environment/platform-specific values through to your loader/action, such as
|
|
13
|
-
* values that are generated by Express middleware like `req.session`.
|
|
14
|
-
*/
|
|
15
|
-
type GetLoadContextFunction = (req: express.Request, res: express.Response) => UNSAFE_MiddlewareEnabled extends true ? MaybePromise<RouterContextProvider> : MaybePromise<AppLoadContext>;
|
|
16
|
-
type RequestHandler = (req: express.Request, res: express.Response, next: express.NextFunction) => Promise<void>;
|
|
17
|
-
/**
|
|
18
|
-
* Returns a request handler for Express that serves the response using Remix.
|
|
19
|
-
*/
|
|
20
|
-
declare function createRequestHandler({ build, getLoadContext, mode, }: {
|
|
21
|
-
build: ServerBuild | (() => Promise<ServerBuild>);
|
|
22
|
-
getLoadContext?: GetLoadContextFunction;
|
|
23
|
-
mode?: string;
|
|
24
|
-
}): RequestHandler;
|
|
25
|
-
|
|
26
|
-
export { type GetLoadContextFunction, type RequestHandler, createRequestHandler };
|
package/dist/index.mjs
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @react-router/express v7.16.0
|
|
3
|
-
*
|
|
4
|
-
* Copyright (c) Remix Software Inc.
|
|
5
|
-
*
|
|
6
|
-
* This source code is licensed under the MIT license found in the
|
|
7
|
-
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
-
*
|
|
9
|
-
* @license MIT
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
// server.ts
|
|
13
|
-
import { createRequestHandler as createRemixRequestHandler } from "react-router";
|
|
14
|
-
import {
|
|
15
|
-
createReadableStreamFromReadable,
|
|
16
|
-
writeReadableStreamToWritable
|
|
17
|
-
} from "@react-router/node";
|
|
18
|
-
function createRequestHandler({
|
|
19
|
-
build,
|
|
20
|
-
getLoadContext,
|
|
21
|
-
mode = process.env.NODE_ENV
|
|
22
|
-
}) {
|
|
23
|
-
let handleRequest = createRemixRequestHandler(build, mode);
|
|
24
|
-
return async (req, res, next) => {
|
|
25
|
-
try {
|
|
26
|
-
let request = createRemixRequest(req, res);
|
|
27
|
-
let loadContext = await getLoadContext?.(req, res);
|
|
28
|
-
let response = await handleRequest(request, loadContext);
|
|
29
|
-
await sendRemixResponse(res, response);
|
|
30
|
-
} catch (error) {
|
|
31
|
-
next(error);
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
function createRemixHeaders(requestHeaders) {
|
|
36
|
-
let headers = new Headers();
|
|
37
|
-
for (let [key, values] of Object.entries(requestHeaders)) {
|
|
38
|
-
if (values) {
|
|
39
|
-
if (Array.isArray(values)) {
|
|
40
|
-
for (let value of values) {
|
|
41
|
-
headers.append(key, value);
|
|
42
|
-
}
|
|
43
|
-
} else {
|
|
44
|
-
headers.set(key, values);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return headers;
|
|
49
|
-
}
|
|
50
|
-
function createRemixRequest(req, res) {
|
|
51
|
-
let [, hostnamePortStr] = req.get("X-Forwarded-Host")?.split(":") ?? [];
|
|
52
|
-
let [, hostPortStr] = req.get("host")?.split(":") ?? [];
|
|
53
|
-
let hostnamePort = Number.parseInt(hostnamePortStr, 10);
|
|
54
|
-
let hostPort = Number.parseInt(hostPortStr, 10);
|
|
55
|
-
let port = Number.isSafeInteger(hostnamePort) ? hostnamePort : Number.isSafeInteger(hostPort) ? hostPort : "";
|
|
56
|
-
let resolvedHost = `${req.hostname}${port ? `:${port}` : ""}`;
|
|
57
|
-
let url = new URL(`${req.protocol}://${resolvedHost}${req.originalUrl}`);
|
|
58
|
-
let controller = new AbortController();
|
|
59
|
-
let init = {
|
|
60
|
-
method: req.method,
|
|
61
|
-
headers: createRemixHeaders(req.headers),
|
|
62
|
-
signal: controller.signal
|
|
63
|
-
};
|
|
64
|
-
res.on("finish", () => controller = null);
|
|
65
|
-
res.on("close", () => controller?.abort());
|
|
66
|
-
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
67
|
-
init.body = createReadableStreamFromReadable(req);
|
|
68
|
-
init.duplex = "half";
|
|
69
|
-
}
|
|
70
|
-
return new Request(url.href, init);
|
|
71
|
-
}
|
|
72
|
-
async function sendRemixResponse(res, nodeResponse) {
|
|
73
|
-
if (isResponseClosed(res)) {
|
|
74
|
-
await nodeResponse.body?.cancel();
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
res.statusMessage = nodeResponse.statusText;
|
|
78
|
-
res.status(nodeResponse.status);
|
|
79
|
-
for (let [key, value] of nodeResponse.headers.entries()) {
|
|
80
|
-
res.append(key, value);
|
|
81
|
-
}
|
|
82
|
-
if (nodeResponse.headers.get("Content-Type")?.match(/text\/event-stream/i)) {
|
|
83
|
-
res.flushHeaders();
|
|
84
|
-
}
|
|
85
|
-
if (nodeResponse.body) {
|
|
86
|
-
try {
|
|
87
|
-
await writeReadableStreamToWritable(nodeResponse.body, res);
|
|
88
|
-
} catch (error) {
|
|
89
|
-
if (isResponseClosed(res)) {
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
throw error;
|
|
93
|
-
}
|
|
94
|
-
} else {
|
|
95
|
-
res.end();
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
function isResponseClosed(res) {
|
|
99
|
-
return res.destroyed || res.writableEnded;
|
|
100
|
-
}
|
|
101
|
-
export {
|
|
102
|
-
createRequestHandler
|
|
103
|
-
};
|