@modern-js/plugin-data-loader 2.5.0-alpha.0 → 2.6.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/cjs/cli/create-request.js +3 -14
- package/dist/cjs/cli/generate-client.js +4 -0
- package/dist/cjs/cli/loader.js +3 -0
- package/dist/cjs/server/index.js +185 -19
- package/dist/esm/cli/create-request.js +2 -41
- package/dist/esm/cli/loader.js +6 -0
- package/dist/esm/server/index.js +432 -29
- package/dist/esm-node/cli/create-request.js +3 -14
- package/dist/esm-node/cli/loader.js +3 -0
- package/dist/esm-node/server/index.js +181 -21
- package/dist/types/cli/create-request.d.ts +1 -2
- package/dist/types/server/index.d.ts +15 -0
- package/package.json +9 -20
- package/dist/cjs/cli/data.js +0 -162
- package/dist/cjs/runtime/index.js +0 -159
- package/dist/cjs/runtime/response.js +0 -102
- package/dist/esm/cli/data.js +0 -820
- package/dist/esm/runtime/index.js +0 -422
- package/dist/esm/runtime/response.js +0 -284
- package/dist/esm-node/cli/data.js +0 -142
- package/dist/esm-node/runtime/index.js +0 -143
- package/dist/esm-node/runtime/response.js +0 -79
- package/dist/types/cli/data.d.ts +0 -6
- package/dist/types/runtime/index.d.ts +0 -15
- package/dist/types/runtime/response.d.ts +0 -2
|
@@ -1,9 +1,179 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
installGlobals,
|
|
4
|
+
writeReadableStreamToWritable,
|
|
5
|
+
Response as NodeResponse
|
|
6
|
+
} from "@remix-run/node";
|
|
7
|
+
import {
|
|
8
|
+
matchRoutes
|
|
9
|
+
} from "react-router-dom";
|
|
10
|
+
import { MAIN_ENTRY_NAME, SERVER_BUNDLE_DIRECTORY } from "@modern-js/utils";
|
|
11
|
+
import { LOADER_ID_PARAM } from "../common/constants";
|
|
12
|
+
installGlobals();
|
|
13
|
+
const redirectStatusCodes = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
14
|
+
function isRedirectResponse(response) {
|
|
15
|
+
return redirectStatusCodes.has(response.status);
|
|
16
|
+
}
|
|
17
|
+
function isResponse(value) {
|
|
18
|
+
return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
|
|
19
|
+
}
|
|
20
|
+
const json = (data, init = {}) => {
|
|
21
|
+
const responseInit = typeof init === "number" ? { status: init } : init;
|
|
22
|
+
const headers = new Headers(responseInit.headers);
|
|
23
|
+
if (!headers.has("Content-Type")) {
|
|
24
|
+
headers.set("Content-Type", "application/json; charset=utf-8");
|
|
25
|
+
}
|
|
26
|
+
return new NodeResponse(JSON.stringify(data), {
|
|
27
|
+
...responseInit,
|
|
28
|
+
headers
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
const callRouteLoader = async ({
|
|
32
|
+
routeId,
|
|
33
|
+
loader,
|
|
34
|
+
params,
|
|
35
|
+
request,
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
37
|
+
loadContext
|
|
38
|
+
}) => {
|
|
39
|
+
if (!loader) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`You made a ${request.method} request to ${request.url} but did not provide a default component or \`loader\` for route "${routeId}", so there is no way to handle the request.`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
let result;
|
|
45
|
+
try {
|
|
46
|
+
result = await loader({
|
|
47
|
+
request,
|
|
48
|
+
params
|
|
49
|
+
});
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (!isResponse(error)) {
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
result = error;
|
|
55
|
+
}
|
|
56
|
+
if (result === void 0) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`You defined a loader for route "${routeId}" but didn't return anything from your \`loader\` function. Please return a value or \`null\`.`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
return isResponse(result) ? result : json(result);
|
|
62
|
+
};
|
|
63
|
+
const createLoaderHeaders = (requestHeaders) => {
|
|
64
|
+
const headers = new Headers();
|
|
65
|
+
for (const [key, values] of Object.entries(requestHeaders)) {
|
|
66
|
+
if (values) {
|
|
67
|
+
if (Array.isArray(values)) {
|
|
68
|
+
for (const value of values) {
|
|
69
|
+
headers.append(key, value);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
headers.set(key, values);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return headers;
|
|
77
|
+
};
|
|
78
|
+
const createLoaderRequest = (context) => {
|
|
79
|
+
const origin = `${context.protocol}://${context.host}`;
|
|
80
|
+
const url = new URL(context.url, origin);
|
|
81
|
+
const controller = new AbortController();
|
|
82
|
+
const init = {
|
|
83
|
+
method: context.method,
|
|
84
|
+
headers: createLoaderHeaders(context.headers),
|
|
85
|
+
signal: controller.signal
|
|
86
|
+
};
|
|
87
|
+
return new Request(url.href, init);
|
|
88
|
+
};
|
|
89
|
+
const sendLoaderResponse = async (res, nodeResponse) => {
|
|
90
|
+
res.statusMessage = nodeResponse.statusText;
|
|
91
|
+
res.statusCode = nodeResponse.status;
|
|
92
|
+
for (const [key, value] of nodeResponse.headers.entries()) {
|
|
93
|
+
res.setHeader(key, value);
|
|
94
|
+
}
|
|
95
|
+
if (nodeResponse.body) {
|
|
96
|
+
await writeReadableStreamToWritable(nodeResponse.body, res);
|
|
97
|
+
} else {
|
|
98
|
+
res.end();
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const getPathWithoutEntry = (pathname, entryPath) => {
|
|
102
|
+
if (entryPath === "/") {
|
|
103
|
+
return pathname;
|
|
104
|
+
}
|
|
105
|
+
return pathname.replace(entryPath, "");
|
|
106
|
+
};
|
|
107
|
+
const matchEntry = (pathname, entries) => {
|
|
108
|
+
return entries.find((entry) => pathname.startsWith(entry.urlPath));
|
|
109
|
+
};
|
|
110
|
+
const handleRequest = async ({
|
|
111
|
+
context,
|
|
112
|
+
serverRoutes,
|
|
113
|
+
distDir
|
|
114
|
+
}) => {
|
|
115
|
+
const { method, query } = context;
|
|
116
|
+
const routeId = query[LOADER_ID_PARAM];
|
|
117
|
+
if (!routeId || method.toLowerCase() !== "get") {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const entry = matchEntry(context.path, serverRoutes);
|
|
121
|
+
if (!entry) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const routesPath = path.join(
|
|
125
|
+
distDir,
|
|
126
|
+
SERVER_BUNDLE_DIRECTORY,
|
|
127
|
+
`${entry.entryName || MAIN_ENTRY_NAME}-server-loaders`
|
|
128
|
+
);
|
|
129
|
+
const { routes } = await import(routesPath);
|
|
130
|
+
if (!routes) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const { res } = context;
|
|
134
|
+
const pathname = getPathWithoutEntry(context.path, entry.urlPath);
|
|
135
|
+
const matches = matchRoutes(routes, pathname);
|
|
136
|
+
if (!matches) {
|
|
137
|
+
res.statusCode = 403;
|
|
138
|
+
res.end(`Route ${pathname} was not matched`);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const match = matches == null ? void 0 : matches.find((match2) => match2.route.id === routeId);
|
|
142
|
+
if (!match) {
|
|
143
|
+
res.statusCode = 403;
|
|
144
|
+
res.end(`Route ${routeId} does not match URL ${context.path}`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const request = createLoaderRequest(context);
|
|
148
|
+
let response;
|
|
149
|
+
try {
|
|
150
|
+
response = await callRouteLoader({
|
|
151
|
+
loader: match.route.loader,
|
|
152
|
+
routeId: match.route.id,
|
|
153
|
+
params: match.params,
|
|
154
|
+
request,
|
|
155
|
+
loadContext: {}
|
|
156
|
+
});
|
|
157
|
+
if (isRedirectResponse(response)) {
|
|
158
|
+
const headers = new Headers(response.headers);
|
|
159
|
+
headers.set("X-Modernjs-Redirect", headers.get("Location"));
|
|
160
|
+
headers.delete("Location");
|
|
161
|
+
response = new NodeResponse(null, {
|
|
162
|
+
status: 204,
|
|
163
|
+
headers
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
} catch (error) {
|
|
167
|
+
const message = String(error);
|
|
168
|
+
response = new NodeResponse(message, {
|
|
169
|
+
status: 500,
|
|
170
|
+
headers: {
|
|
171
|
+
"Content-Type": "text/plain"
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
sendLoaderResponse(res, response);
|
|
176
|
+
};
|
|
7
177
|
var server_default = () => ({
|
|
8
178
|
name: "@modern-js/plugin-data-loader",
|
|
9
179
|
setup: () => ({
|
|
@@ -12,29 +182,19 @@ var server_default = () => ({
|
|
|
12
182
|
distDir
|
|
13
183
|
}) {
|
|
14
184
|
return async (context) => {
|
|
15
|
-
const entry = matchEntry(context.path, serverRoutes);
|
|
16
|
-
if (!entry) {
|
|
17
|
-
throw new Error("Route is not matched");
|
|
18
|
-
}
|
|
19
|
-
const routesPath = path.join(
|
|
20
|
-
distDir,
|
|
21
|
-
SERVER_BUNDLE_DIRECTORY,
|
|
22
|
-
`${entry.entryName || MAIN_ENTRY_NAME}-server-loaders`
|
|
23
|
-
);
|
|
24
|
-
const { routes, handleRequest } = await import(routesPath);
|
|
25
|
-
if (!routes) {
|
|
26
|
-
throw new Error("Missing route info");
|
|
27
|
-
;
|
|
28
|
-
}
|
|
29
185
|
return handleRequest({
|
|
30
186
|
serverRoutes,
|
|
31
|
-
|
|
32
|
-
|
|
187
|
+
distDir,
|
|
188
|
+
context
|
|
33
189
|
});
|
|
34
190
|
};
|
|
35
191
|
}
|
|
36
192
|
})
|
|
37
193
|
});
|
|
38
194
|
export {
|
|
39
|
-
server_default as default
|
|
195
|
+
server_default as default,
|
|
196
|
+
getPathWithoutEntry,
|
|
197
|
+
handleRequest,
|
|
198
|
+
isRedirectResponse,
|
|
199
|
+
isResponse
|
|
40
200
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type UNSAFE_DeferredData as DeferredData } from '@modern-js/utils/remix-router';
|
|
2
1
|
export declare const getRequestUrl: ({
|
|
3
2
|
params,
|
|
4
3
|
request,
|
|
@@ -14,4 +13,4 @@ export declare const createRequest: (routeId: string, method?: string) => ({
|
|
|
14
13
|
}: {
|
|
15
14
|
params: Record<string, string>;
|
|
16
15
|
request: Request;
|
|
17
|
-
}) => Promise<
|
|
16
|
+
}) => Promise<Response>;
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
import type { ServerPlugin } from '@modern-js/server-core';
|
|
2
|
+
import type { ModernServerContext, ServerRoute } from '@modern-js/types';
|
|
3
|
+
import { Response as NodeResponse } from '@remix-run/node';
|
|
4
|
+
export type ServerContext = Pick<ModernServerContext, 'req' | 'res' | 'params' | 'headers' | 'method' | 'url' | 'host' | 'protocol' | 'origin' | 'href' | 'path' | 'query'>;
|
|
5
|
+
export declare function isRedirectResponse(response: NodeResponse): boolean;
|
|
6
|
+
export declare function isResponse(value: any): value is NodeResponse;
|
|
7
|
+
export declare const getPathWithoutEntry: (pathname: string, entryPath: string) => string;
|
|
8
|
+
export declare const handleRequest: ({
|
|
9
|
+
context,
|
|
10
|
+
serverRoutes,
|
|
11
|
+
distDir
|
|
12
|
+
}: {
|
|
13
|
+
context: ServerContext;
|
|
14
|
+
serverRoutes: ServerRoute[];
|
|
15
|
+
distDir: string;
|
|
16
|
+
}) => Promise<void>;
|
|
2
17
|
|
|
3
18
|
declare const _default: () => ServerPlugin;
|
|
4
19
|
|
package/package.json
CHANGED
|
@@ -11,10 +11,7 @@
|
|
|
11
11
|
"modern",
|
|
12
12
|
"modern.js"
|
|
13
13
|
],
|
|
14
|
-
"version": "2.
|
|
15
|
-
"engines": {
|
|
16
|
-
"node": ">=14.17.6"
|
|
17
|
-
},
|
|
14
|
+
"version": "2.6.0",
|
|
18
15
|
"jsnext:source": "./src/index.ts",
|
|
19
16
|
"types": "./dist/types/index.d.ts",
|
|
20
17
|
"main": "./dist/cjs/index.js",
|
|
@@ -27,10 +24,6 @@
|
|
|
27
24
|
"./server": {
|
|
28
25
|
"jsnext:source": "./src/server/index.ts",
|
|
29
26
|
"default": "./dist/cjs/server/index.js"
|
|
30
|
-
},
|
|
31
|
-
"./runtime": {
|
|
32
|
-
"jsnext:source": "./src/runtime/index.ts",
|
|
33
|
-
"default": "./dist/esm/runtime/index.js"
|
|
34
27
|
}
|
|
35
28
|
},
|
|
36
29
|
"typesVersions": {
|
|
@@ -40,19 +33,16 @@
|
|
|
40
33
|
],
|
|
41
34
|
"server": [
|
|
42
35
|
"./dist/types/server/index.d.ts"
|
|
43
|
-
],
|
|
44
|
-
"runtime": [
|
|
45
|
-
"./dist/types/runtime/index.d.ts"
|
|
46
36
|
]
|
|
47
37
|
}
|
|
48
38
|
},
|
|
49
39
|
"dependencies": {
|
|
50
40
|
"@babel/core": "^7.18.0",
|
|
51
41
|
"@babel/runtime": "^7.18.0",
|
|
52
|
-
"@remix-run/node": "^1.
|
|
42
|
+
"@remix-run/node": "^1.9.0",
|
|
53
43
|
"path-to-regexp": "^6.2.0",
|
|
54
|
-
"react-router-dom": "^6.
|
|
55
|
-
"@modern-js/utils": "2.
|
|
44
|
+
"react-router-dom": "^6.6.0",
|
|
45
|
+
"@modern-js/utils": "2.6.0"
|
|
56
46
|
},
|
|
57
47
|
"devDependencies": {
|
|
58
48
|
"@types/babel__core": "^7.1.15",
|
|
@@ -67,12 +57,11 @@
|
|
|
67
57
|
"typescript": "^4",
|
|
68
58
|
"webpack": "^5.75.0",
|
|
69
59
|
"webpack-chain": "^6.5.1",
|
|
70
|
-
"@modern-js/core": "2.
|
|
71
|
-
"@modern-js/
|
|
72
|
-
"@
|
|
73
|
-
"@
|
|
74
|
-
"@
|
|
75
|
-
"@scripts/jest-config": "2.5.0"
|
|
60
|
+
"@modern-js/core": "2.6.0",
|
|
61
|
+
"@modern-js/server-core": "2.6.0",
|
|
62
|
+
"@modern-js/types": "2.6.0",
|
|
63
|
+
"@scripts/build": "2.6.0",
|
|
64
|
+
"@scripts/jest-config": "2.6.0"
|
|
76
65
|
},
|
|
77
66
|
"sideEffects": false,
|
|
78
67
|
"publishConfig": {
|
package/dist/cjs/cli/data.js
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
var __export = (target, all) => {
|
|
6
|
-
for (var name in all)
|
|
7
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
-
};
|
|
9
|
-
var __copyProps = (to, from, except, desc) => {
|
|
10
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
-
for (let key of __getOwnPropNames(from))
|
|
12
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
-
}
|
|
15
|
-
return to;
|
|
16
|
-
};
|
|
17
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
-
var data_exports = {};
|
|
19
|
-
__export(data_exports, {
|
|
20
|
-
parseDeferredReadableStream: () => parseDeferredReadableStream
|
|
21
|
-
});
|
|
22
|
-
module.exports = __toCommonJS(data_exports);
|
|
23
|
-
var import_remix_router = require("@modern-js/utils/remix-router");
|
|
24
|
-
const DEFERRED_VALUE_PLACEHOLDER_PREFIX = "__deferred_promise:";
|
|
25
|
-
async function parseDeferredReadableStream(stream) {
|
|
26
|
-
if (!stream) {
|
|
27
|
-
throw new Error("parseDeferredReadableStream requires stream argument");
|
|
28
|
-
}
|
|
29
|
-
let deferredData;
|
|
30
|
-
const deferredResolvers = {};
|
|
31
|
-
try {
|
|
32
|
-
const sectionReader = readStreamSections(stream);
|
|
33
|
-
const initialSectionResult = await sectionReader.next();
|
|
34
|
-
const initialSection = initialSectionResult.value;
|
|
35
|
-
if (!initialSection) {
|
|
36
|
-
throw new Error("no critical data");
|
|
37
|
-
}
|
|
38
|
-
const criticalData = JSON.parse(initialSection);
|
|
39
|
-
if (typeof criticalData === "object" && criticalData !== null) {
|
|
40
|
-
for (const [eventKey, value] of Object.entries(criticalData)) {
|
|
41
|
-
if (typeof value !== "string" || !value.startsWith(DEFERRED_VALUE_PLACEHOLDER_PREFIX)) {
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
deferredData = deferredData || {};
|
|
45
|
-
deferredData[eventKey] = new Promise((resolve, reject) => {
|
|
46
|
-
deferredResolvers[eventKey] = {
|
|
47
|
-
resolve: (value2) => {
|
|
48
|
-
resolve(value2);
|
|
49
|
-
delete deferredResolvers[eventKey];
|
|
50
|
-
},
|
|
51
|
-
reject: (error) => {
|
|
52
|
-
reject(error);
|
|
53
|
-
delete deferredResolvers[eventKey];
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
(async () => {
|
|
60
|
-
try {
|
|
61
|
-
for await (const section of sectionReader) {
|
|
62
|
-
const [event, ...sectionDataStrings] = section.split(":");
|
|
63
|
-
const sectionDataString = sectionDataStrings.join(":");
|
|
64
|
-
const data = JSON.parse(sectionDataString);
|
|
65
|
-
if (event === "data") {
|
|
66
|
-
for (const [key, value] of Object.entries(data)) {
|
|
67
|
-
if (deferredResolvers[key]) {
|
|
68
|
-
deferredResolvers[key].resolve(value);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
} else if (event === "error") {
|
|
72
|
-
for (const [key, value] of Object.entries(data)) {
|
|
73
|
-
const err = new Error(value.message);
|
|
74
|
-
err.stack = value.stack;
|
|
75
|
-
if (deferredResolvers[key]) {
|
|
76
|
-
deferredResolvers[key].reject(err);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
for (const [key, resolver] of Object.entries(deferredResolvers)) {
|
|
82
|
-
resolver.reject(
|
|
83
|
-
new import_remix_router.AbortedDeferredError(`Deferred ${key} will never resolved`)
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
} catch (error) {
|
|
87
|
-
for (const resolver of Object.values(deferredResolvers)) {
|
|
88
|
-
resolver.reject(error);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
})();
|
|
92
|
-
return new import_remix_router.UNSAFE_DeferredData({ ...criticalData, ...deferredData });
|
|
93
|
-
} catch (error) {
|
|
94
|
-
for (const resolver of Object.values(deferredResolvers)) {
|
|
95
|
-
resolver.reject(error);
|
|
96
|
-
}
|
|
97
|
-
throw error;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
async function* readStreamSections(stream) {
|
|
101
|
-
const reader = stream.getReader();
|
|
102
|
-
let buffer = [];
|
|
103
|
-
let sections = [];
|
|
104
|
-
let closed = false;
|
|
105
|
-
const encoder = new TextEncoder();
|
|
106
|
-
const decoder = new TextDecoder();
|
|
107
|
-
const readStreamSection = async () => {
|
|
108
|
-
if (sections.length > 0) {
|
|
109
|
-
return sections.shift();
|
|
110
|
-
}
|
|
111
|
-
while (!closed && sections.length === 0) {
|
|
112
|
-
const chunk = await reader.read();
|
|
113
|
-
if (chunk.done) {
|
|
114
|
-
closed = true;
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
117
|
-
buffer.push(chunk.value);
|
|
118
|
-
try {
|
|
119
|
-
const bufferedString = decoder.decode(mergeArrays(...buffer));
|
|
120
|
-
const splitSections = bufferedString.split("\n\n");
|
|
121
|
-
if (splitSections.length >= 2) {
|
|
122
|
-
sections.push(...splitSections.slice(0, -1));
|
|
123
|
-
buffer = [encoder.encode(splitSections.slice(-1).join("\n\n"))];
|
|
124
|
-
}
|
|
125
|
-
if (sections.length > 0) {
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
} catch {
|
|
129
|
-
continue;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
if (sections.length > 0) {
|
|
133
|
-
return sections.shift();
|
|
134
|
-
}
|
|
135
|
-
if (buffer.length > 0) {
|
|
136
|
-
const bufferedString = decoder.decode(mergeArrays(...buffer));
|
|
137
|
-
sections = bufferedString.split("\n\n").filter((s) => s);
|
|
138
|
-
buffer = [];
|
|
139
|
-
}
|
|
140
|
-
return sections.shift();
|
|
141
|
-
};
|
|
142
|
-
let section = await readStreamSection();
|
|
143
|
-
while (section) {
|
|
144
|
-
yield section;
|
|
145
|
-
section = await readStreamSection();
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
function mergeArrays(...arrays) {
|
|
149
|
-
const out = new Uint8Array(
|
|
150
|
-
arrays.reduce((total, arr) => total + arr.length, 0)
|
|
151
|
-
);
|
|
152
|
-
let offset = 0;
|
|
153
|
-
for (const arr of arrays) {
|
|
154
|
-
out.set(arr, offset);
|
|
155
|
-
offset += arr.length;
|
|
156
|
-
}
|
|
157
|
-
return out;
|
|
158
|
-
}
|
|
159
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
160
|
-
0 && (module.exports = {
|
|
161
|
-
parseDeferredReadableStream
|
|
162
|
-
});
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
var __export = (target, all) => {
|
|
6
|
-
for (var name in all)
|
|
7
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
-
};
|
|
9
|
-
var __copyProps = (to, from, except, desc) => {
|
|
10
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
-
for (let key of __getOwnPropNames(from))
|
|
12
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
-
}
|
|
15
|
-
return to;
|
|
16
|
-
};
|
|
17
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
-
var runtime_exports = {};
|
|
19
|
-
__export(runtime_exports, {
|
|
20
|
-
handleRequest: () => handleRequest,
|
|
21
|
-
isRedirectResponse: () => isRedirectResponse,
|
|
22
|
-
isResponse: () => isResponse,
|
|
23
|
-
matchEntry: () => matchEntry
|
|
24
|
-
});
|
|
25
|
-
module.exports = __toCommonJS(runtime_exports);
|
|
26
|
-
var import_node = require("@remix-run/node");
|
|
27
|
-
var import_utils = require("@modern-js/utils");
|
|
28
|
-
var import_remix_router = require("@modern-js/utils/remix-router");
|
|
29
|
-
var import_constants = require("../common/constants");
|
|
30
|
-
var import_response = require("./response");
|
|
31
|
-
(0, import_node.installGlobals)();
|
|
32
|
-
const redirectStatusCodes = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
33
|
-
function isRedirectResponse(status) {
|
|
34
|
-
return redirectStatusCodes.has(status);
|
|
35
|
-
}
|
|
36
|
-
function isResponse(value) {
|
|
37
|
-
return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
|
|
38
|
-
}
|
|
39
|
-
function convertModernRedirectResponse(headers) {
|
|
40
|
-
const newHeaders = new Headers(headers);
|
|
41
|
-
newHeaders.set("X-Modernjs-Redirect", headers.get("Location"));
|
|
42
|
-
newHeaders.delete("Location");
|
|
43
|
-
return new import_node.Response(null, {
|
|
44
|
-
status: 204,
|
|
45
|
-
headers: newHeaders
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
const createLoaderHeaders = (requestHeaders) => {
|
|
49
|
-
const headers = new Headers();
|
|
50
|
-
for (const [key, values] of Object.entries(requestHeaders)) {
|
|
51
|
-
if (values) {
|
|
52
|
-
if (Array.isArray(values)) {
|
|
53
|
-
for (const value of values) {
|
|
54
|
-
headers.append(key, value);
|
|
55
|
-
}
|
|
56
|
-
} else {
|
|
57
|
-
headers.set(key, values);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return headers;
|
|
62
|
-
};
|
|
63
|
-
const createLoaderRequest = (context) => {
|
|
64
|
-
const origin = `${context.protocol}://${context.host}`;
|
|
65
|
-
const url = new URL(context.url, origin);
|
|
66
|
-
const controller = new AbortController();
|
|
67
|
-
const init = {
|
|
68
|
-
method: context.method,
|
|
69
|
-
headers: createLoaderHeaders(context.headers),
|
|
70
|
-
signal: controller.signal
|
|
71
|
-
};
|
|
72
|
-
return new Request(url.href, init);
|
|
73
|
-
};
|
|
74
|
-
const sendLoaderResponse = async (res, nodeResponse) => {
|
|
75
|
-
res.statusMessage = nodeResponse.statusText;
|
|
76
|
-
res.statusCode = nodeResponse.status;
|
|
77
|
-
for (const [key, value] of nodeResponse.headers.entries()) {
|
|
78
|
-
res.setHeader(key, value);
|
|
79
|
-
}
|
|
80
|
-
if (nodeResponse.body) {
|
|
81
|
-
await (0, import_node.writeReadableStreamToWritable)(nodeResponse.body, res);
|
|
82
|
-
} else {
|
|
83
|
-
res.end();
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
const matchEntry = (pathname, entries) => {
|
|
87
|
-
return entries.find((entry) => pathname.startsWith(entry.urlPath));
|
|
88
|
-
};
|
|
89
|
-
const handleRequest = async ({
|
|
90
|
-
context,
|
|
91
|
-
serverRoutes,
|
|
92
|
-
routes
|
|
93
|
-
}) => {
|
|
94
|
-
const { method, query } = context;
|
|
95
|
-
const routeId = query[import_constants.LOADER_ID_PARAM];
|
|
96
|
-
if (!routeId) {
|
|
97
|
-
throw new Error(`Missing parameter: ${import_constants.LOADER_ID_PARAM}`);
|
|
98
|
-
}
|
|
99
|
-
if (method.toLowerCase() !== "get") {
|
|
100
|
-
throw new Error("Only support httpp GET method");
|
|
101
|
-
}
|
|
102
|
-
const entry = matchEntry(context.path, serverRoutes);
|
|
103
|
-
if (!entry) {
|
|
104
|
-
throw new Error("Route is not matched");
|
|
105
|
-
}
|
|
106
|
-
const dataRoutes = (0, import_utils.transformNestedRoutes)(routes);
|
|
107
|
-
const staticHandler = (0, import_remix_router.createStaticHandler)(dataRoutes, {
|
|
108
|
-
basename: entry.urlPath
|
|
109
|
-
});
|
|
110
|
-
const { res } = context;
|
|
111
|
-
const request = createLoaderRequest(context);
|
|
112
|
-
let response;
|
|
113
|
-
try {
|
|
114
|
-
response = await staticHandler.queryRoute(request, {
|
|
115
|
-
routeId,
|
|
116
|
-
requestContext: context
|
|
117
|
-
});
|
|
118
|
-
if (isResponse(response) && isRedirectResponse(response.status)) {
|
|
119
|
-
response = convertModernRedirectResponse(response.headers);
|
|
120
|
-
} else if (import_remix_router.UNSAFE_DEFERRED_SYMBOL in response) {
|
|
121
|
-
const deferredData = response[import_remix_router.UNSAFE_DEFERRED_SYMBOL];
|
|
122
|
-
const body = (0, import_response.createDeferredReadableStream)(deferredData, request.signal);
|
|
123
|
-
const init = deferredData.init || {};
|
|
124
|
-
if (init.status && isRedirectResponse(init.status)) {
|
|
125
|
-
if (!init.headers) {
|
|
126
|
-
throw new Error("redirect response includes no headers");
|
|
127
|
-
}
|
|
128
|
-
response = convertModernRedirectResponse(new Headers(init.headers));
|
|
129
|
-
} else {
|
|
130
|
-
const headers = new Headers(init.headers);
|
|
131
|
-
headers.set("Content-Type", "text/modernjs-deferred");
|
|
132
|
-
init.headers = headers;
|
|
133
|
-
response = new import_node.Response(body, init);
|
|
134
|
-
}
|
|
135
|
-
} else {
|
|
136
|
-
response = isResponse(response) ? response : new import_node.Response(JSON.stringify(response), {
|
|
137
|
-
headers: {
|
|
138
|
-
"Content-Type": "application/json; charset=utf-8"
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
} catch (error) {
|
|
143
|
-
const message = error instanceof import_remix_router.ErrorResponse ? error.data : String(error);
|
|
144
|
-
response = new import_node.Response(message, {
|
|
145
|
-
status: 500,
|
|
146
|
-
headers: {
|
|
147
|
-
"Content-Type": "text/plain"
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
sendLoaderResponse(res, response);
|
|
152
|
-
};
|
|
153
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
154
|
-
0 && (module.exports = {
|
|
155
|
-
handleRequest,
|
|
156
|
-
isRedirectResponse,
|
|
157
|
-
isResponse,
|
|
158
|
-
matchEntry
|
|
159
|
-
});
|