@react-router/express 0.0.0-experimental-8cee090e4 → 0.0.0-experimental-63fd291ad
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/index.d.mts +26 -0
- package/dist/index.d.ts +10 -14
- package/dist/index.js +108 -58
- package/dist/index.mjs +103 -0
- package/package.json +28 -19
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
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.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import * as express from 'express';
|
|
2
|
+
import { UNSAFE_MiddlewareEnabled, RouterContextProvider, AppLoadContext, ServerBuild } from 'react-router';
|
|
1
3
|
|
|
2
|
-
|
|
3
|
-
import * as express from "express";
|
|
4
|
+
/// <reference lib="dom.iterable" />
|
|
4
5
|
|
|
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,19 +12,15 @@ 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) => MaybePromise<RouterContextProvider>;
|
|
15
|
+
type GetLoadContextFunction = (req: express.Request, res: express.Response) => UNSAFE_MiddlewareEnabled extends true ? MaybePromise<RouterContextProvider> : MaybePromise<AppLoadContext>;
|
|
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
|
-
|
|
24
|
-
}: {
|
|
25
|
-
build: ServerBuild | (() => Promise<ServerBuild>);
|
|
26
|
-
getLoadContext?: GetLoadContextFunction;
|
|
27
|
-
mode?: string;
|
|
20
|
+
declare function createRequestHandler({ build, getLoadContext, mode, }: {
|
|
21
|
+
build: ServerBuild | (() => Promise<ServerBuild>);
|
|
22
|
+
getLoadContext?: GetLoadContextFunction;
|
|
23
|
+
mode?: string;
|
|
28
24
|
}): RequestHandler;
|
|
29
|
-
|
|
30
|
-
export { type GetLoadContextFunction, type RequestHandler, createRequestHandler };
|
|
25
|
+
|
|
26
|
+
export { type GetLoadContextFunction, type RequestHandler, createRequestHandler };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @react-router/express v0.0.0-experimental-
|
|
2
|
+
* @react-router/express v0.0.0-experimental-63fd291ad
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -8,69 +8,119 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
11
|
+
"use strict";
|
|
12
|
+
var __defProp = Object.defineProperty;
|
|
13
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
14
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
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
|
+
};
|
|
26
56
|
}
|
|
27
57
|
function createRemixHeaders(requestHeaders) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
58
|
+
let headers = new Headers();
|
|
59
|
+
for (let [key, values] of Object.entries(requestHeaders)) {
|
|
60
|
+
if (values) {
|
|
61
|
+
if (Array.isArray(values)) {
|
|
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;
|
|
32
71
|
}
|
|
33
72
|
function createRemixRequest(req, res) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
73
|
+
let [, hostnamePortStr] = req.get("X-Forwarded-Host")?.split(":") ?? [];
|
|
74
|
+
let [, hostPortStr] = req.get("host")?.split(":") ?? [];
|
|
75
|
+
let hostnamePort = Number.parseInt(hostnamePortStr, 10);
|
|
76
|
+
let hostPort = Number.parseInt(hostPortStr, 10);
|
|
77
|
+
let port = Number.isSafeInteger(hostnamePort) ? hostnamePort : Number.isSafeInteger(hostPort) ? hostPort : "";
|
|
78
|
+
let resolvedHost = `${req.hostname}${port ? `:${port}` : ""}`;
|
|
79
|
+
let url = new URL(`${req.protocol}://${resolvedHost}${req.originalUrl}`);
|
|
80
|
+
let controller = new AbortController();
|
|
81
|
+
let init = {
|
|
82
|
+
method: req.method,
|
|
83
|
+
headers: createRemixHeaders(req.headers),
|
|
84
|
+
signal: controller.signal
|
|
85
|
+
};
|
|
86
|
+
res.on("finish", () => controller = null);
|
|
87
|
+
res.on("close", () => controller?.abort());
|
|
88
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
89
|
+
init.body = (0, import_node.createReadableStreamFromReadable)(req);
|
|
90
|
+
init.duplex = "half";
|
|
91
|
+
}
|
|
92
|
+
return new Request(url.href, init);
|
|
54
93
|
}
|
|
55
94
|
async function sendRemixResponse(res, nodeResponse) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
95
|
+
if (isResponseClosed(res)) {
|
|
96
|
+
await nodeResponse.body?.cancel();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
res.statusMessage = nodeResponse.statusText;
|
|
100
|
+
res.status(nodeResponse.status);
|
|
101
|
+
for (let [key, value] of nodeResponse.headers.entries()) {
|
|
102
|
+
res.append(key, value);
|
|
103
|
+
}
|
|
104
|
+
if (nodeResponse.headers.get("Content-Type")?.match(/text\/event-stream/i)) {
|
|
105
|
+
res.flushHeaders();
|
|
106
|
+
}
|
|
107
|
+
if (nodeResponse.body) {
|
|
108
|
+
try {
|
|
109
|
+
await (0, import_node.writeReadableStreamToWritable)(nodeResponse.body, res);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (isResponseClosed(res)) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
res.end();
|
|
118
|
+
}
|
|
71
119
|
}
|
|
72
120
|
function isResponseClosed(res) {
|
|
73
|
-
|
|
121
|
+
return res.destroyed || res.writableEnded;
|
|
74
122
|
}
|
|
75
|
-
|
|
76
|
-
|
|
123
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
124
|
+
0 && (module.exports = {
|
|
125
|
+
createRequestHandler
|
|
126
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @react-router/express v0.0.0-experimental-63fd291ad
|
|
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
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-router/express",
|
|
3
|
-
"
|
|
4
|
-
"version": "0.0.0-experimental-8cee090e4",
|
|
3
|
+
"version": "0.0.0-experimental-63fd291ad",
|
|
5
4
|
"description": "Express server request handler for React Router",
|
|
6
5
|
"bugs": {
|
|
7
6
|
"url": "https://github.com/remix-run/react-router/issues"
|
|
@@ -16,15 +15,25 @@
|
|
|
16
15
|
"typings": "dist/index.d.ts",
|
|
17
16
|
"exports": {
|
|
18
17
|
".": {
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
"node": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"module-sync": "./dist/index.mjs",
|
|
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
|
+
}
|
|
22
31
|
},
|
|
23
32
|
"./package.json": "./package.json"
|
|
24
33
|
},
|
|
25
34
|
"wireit": {
|
|
26
35
|
"build": {
|
|
27
|
-
"command": "
|
|
36
|
+
"command": "tsup",
|
|
28
37
|
"files": [
|
|
29
38
|
"../../pnpm-workspace.yaml",
|
|
30
39
|
"*.ts",
|
|
@@ -37,23 +46,23 @@
|
|
|
37
46
|
}
|
|
38
47
|
},
|
|
39
48
|
"dependencies": {
|
|
40
|
-
"@react-router/node": "0.0.0-experimental-
|
|
49
|
+
"@react-router/node": "0.0.0-experimental-63fd291ad"
|
|
41
50
|
},
|
|
42
51
|
"devDependencies": {
|
|
43
|
-
"@types/express": "^4.17.
|
|
44
|
-
"@types/node": "^
|
|
45
|
-
"@types/supertest": "^
|
|
46
|
-
"express": "^4.
|
|
47
|
-
"node-mocks-http": "^1.
|
|
48
|
-
"supertest": "^
|
|
49
|
-
"
|
|
50
|
-
"typescript": "^
|
|
51
|
-
"wireit": "0.14.
|
|
52
|
+
"@types/express": "^4.17.9",
|
|
53
|
+
"@types/node": "^20.0.0",
|
|
54
|
+
"@types/supertest": "^2.0.10",
|
|
55
|
+
"express": "^4.19.2",
|
|
56
|
+
"node-mocks-http": "^1.10.1",
|
|
57
|
+
"supertest": "^6.3.3",
|
|
58
|
+
"tsup": "^8.3.0",
|
|
59
|
+
"typescript": "^5.4.5",
|
|
60
|
+
"wireit": "0.14.9"
|
|
52
61
|
},
|
|
53
62
|
"peerDependencies": {
|
|
54
|
-
"express": "^4.
|
|
63
|
+
"express": "^4.17.1 || ^5",
|
|
55
64
|
"typescript": "^5.1.0 || ^6.0.0",
|
|
56
|
-
"react-router": "0.0.0-experimental-
|
|
65
|
+
"react-router": "0.0.0-experimental-63fd291ad"
|
|
57
66
|
},
|
|
58
67
|
"peerDependenciesMeta": {
|
|
59
68
|
"typescript": {
|
|
@@ -61,7 +70,7 @@
|
|
|
61
70
|
}
|
|
62
71
|
},
|
|
63
72
|
"engines": {
|
|
64
|
-
"node": ">=
|
|
73
|
+
"node": ">=20.0.0"
|
|
65
74
|
},
|
|
66
75
|
"files": [
|
|
67
76
|
"dist/",
|