@modern-js/plugin-data-loader 2.51.0 → 2.53.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/runtime/errors.js +103 -0
- package/dist/cjs/runtime/index.js +14 -11
- package/dist/esm/runtime/errors.js +90 -0
- package/dist/esm/runtime/index.js +16 -13
- package/dist/esm-node/runtime/errors.js +75 -0
- package/dist/esm-node/runtime/index.js +15 -12
- package/dist/types/runtime/errors.d.ts +60 -0
- package/package.json +8 -8
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var errors_exports = {};
|
|
20
|
+
__export(errors_exports, {
|
|
21
|
+
errorResponseToJson: () => errorResponseToJson,
|
|
22
|
+
sanitizeError: () => sanitizeError,
|
|
23
|
+
sanitizeErrors: () => sanitizeErrors,
|
|
24
|
+
serializeError: () => serializeError,
|
|
25
|
+
serializeErrors: () => serializeErrors
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(errors_exports);
|
|
28
|
+
var import_remix_router = require("@modern-js/runtime-utils/remix-router");
|
|
29
|
+
function sanitizeError(error) {
|
|
30
|
+
if (error instanceof Error && process.env.NODE_ENV !== "development" && process.env.NODE_ENV !== "test") {
|
|
31
|
+
const sanitized = new Error("Unexpected Server Error");
|
|
32
|
+
sanitized.stack = void 0;
|
|
33
|
+
return sanitized;
|
|
34
|
+
}
|
|
35
|
+
return error;
|
|
36
|
+
}
|
|
37
|
+
function sanitizeErrors(errors) {
|
|
38
|
+
return Object.entries(errors).reduce((acc, [routeId, error]) => {
|
|
39
|
+
return Object.assign(acc, {
|
|
40
|
+
[routeId]: sanitizeError(error)
|
|
41
|
+
});
|
|
42
|
+
}, {});
|
|
43
|
+
}
|
|
44
|
+
function serializeError(error) {
|
|
45
|
+
const sanitized = sanitizeError(error);
|
|
46
|
+
return {
|
|
47
|
+
message: sanitized.message,
|
|
48
|
+
stack: sanitized.stack
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function serializeErrors(errors) {
|
|
52
|
+
if (!errors) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const entries = Object.entries(errors);
|
|
56
|
+
const serialized = {};
|
|
57
|
+
for (const [key, val] of entries) {
|
|
58
|
+
if ((0, import_remix_router.isRouteErrorResponse)(val)) {
|
|
59
|
+
serialized[key] = {
|
|
60
|
+
...val,
|
|
61
|
+
__type: "RouteErrorResponse"
|
|
62
|
+
};
|
|
63
|
+
} else if (val instanceof Error) {
|
|
64
|
+
const sanitized = sanitizeError(val);
|
|
65
|
+
serialized[key] = {
|
|
66
|
+
message: sanitized.message,
|
|
67
|
+
stack: sanitized.stack,
|
|
68
|
+
__type: "Error",
|
|
69
|
+
// If this is a subclass (i.e., ReferenceError), send up the type so we
|
|
70
|
+
// can re-create the same type during hydration. This will only apply
|
|
71
|
+
// in dev mode since all production errors are sanitized to normal
|
|
72
|
+
// Error instances
|
|
73
|
+
...sanitized.name !== "Error" ? {
|
|
74
|
+
__subType: sanitized.name
|
|
75
|
+
} : {}
|
|
76
|
+
};
|
|
77
|
+
} else {
|
|
78
|
+
serialized[key] = val;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return serialized;
|
|
82
|
+
}
|
|
83
|
+
function errorResponseToJson(errorResponse) {
|
|
84
|
+
return (0, import_remix_router.json)(
|
|
85
|
+
// @ts-expect-error This is "private" from users but intended for internal use
|
|
86
|
+
serializeError(errorResponse.error || new Error("Unexpected Server Error")),
|
|
87
|
+
{
|
|
88
|
+
status: errorResponse.status,
|
|
89
|
+
statusText: errorResponse.statusText,
|
|
90
|
+
headers: {
|
|
91
|
+
"X-Modernjs-Error": "yes"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
97
|
+
0 && (module.exports = {
|
|
98
|
+
errorResponseToJson,
|
|
99
|
+
sanitizeError,
|
|
100
|
+
sanitizeErrors,
|
|
101
|
+
serializeError,
|
|
102
|
+
serializeErrors
|
|
103
|
+
});
|
|
@@ -31,6 +31,7 @@ var import_time = require("@modern-js/runtime-utils/time");
|
|
|
31
31
|
var import_constants = require("@modern-js/utils/universal/constants");
|
|
32
32
|
var import_constants2 = require("../common/constants");
|
|
33
33
|
var import_response = require("./response");
|
|
34
|
+
var import_errors = require("./errors");
|
|
34
35
|
const redirectStatusCodes = /* @__PURE__ */ new Set([
|
|
35
36
|
301,
|
|
36
37
|
302,
|
|
@@ -66,7 +67,7 @@ const handleRequest = async ({ request, serverRoutes, routes: routesConfig, cont
|
|
|
66
67
|
}
|
|
67
68
|
const basename = entry.urlPath;
|
|
68
69
|
const end = (0, import_time.time)();
|
|
69
|
-
const {
|
|
70
|
+
const { reporter } = context;
|
|
70
71
|
const routes = (0, import_browser.transformNestedRoutes)(routesConfig, reporter);
|
|
71
72
|
const { queryRoute } = (0, import_remix_router.createStaticHandler)(routes, {
|
|
72
73
|
basename
|
|
@@ -106,18 +107,20 @@ const handleRequest = async ({ request, serverRoutes, routes: routesConfig, cont
|
|
|
106
107
|
const cost = end();
|
|
107
108
|
reporter === null || reporter === void 0 ? void 0 : reporter.reportTiming(`${import_constants.LOADER_REPORTER_NAME}-navigation`, cost);
|
|
108
109
|
} catch (error) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
if (isResponse(error)) {
|
|
111
|
+
error.headers.set("X-Modernjs-Catch", "yes");
|
|
112
|
+
response = error;
|
|
113
|
+
} else if ((0, import_remix_router.isRouteErrorResponse)(error)) {
|
|
114
|
+
response = (0, import_errors.errorResponseToJson)(error);
|
|
112
115
|
} else {
|
|
113
|
-
|
|
116
|
+
const errorInstance = error instanceof Error || error instanceof DOMException ? error : new Error("Unexpected Server Error");
|
|
117
|
+
response = (0, import_remix_router.json)((0, import_errors.serializeError)(errorInstance), {
|
|
118
|
+
status: 500,
|
|
119
|
+
headers: {
|
|
120
|
+
"X-Modernjs-Error": "yes"
|
|
121
|
+
}
|
|
122
|
+
});
|
|
114
123
|
}
|
|
115
|
-
response = new Response(message, {
|
|
116
|
-
status: 500,
|
|
117
|
-
headers: {
|
|
118
|
-
"Content-Type": "text/plain"
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
124
|
}
|
|
122
125
|
return response;
|
|
123
126
|
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { _ as _define_property } from "@swc/helpers/_/_define_property";
|
|
2
|
+
import { _ as _instanceof } from "@swc/helpers/_/_instanceof";
|
|
3
|
+
import { _ as _object_spread } from "@swc/helpers/_/_object_spread";
|
|
4
|
+
import { _ as _object_spread_props } from "@swc/helpers/_/_object_spread_props";
|
|
5
|
+
import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array";
|
|
6
|
+
import { isRouteErrorResponse, json } from "@modern-js/runtime-utils/remix-router";
|
|
7
|
+
function sanitizeError(error) {
|
|
8
|
+
if (_instanceof(error, Error) && process.env.NODE_ENV !== "development" && process.env.NODE_ENV !== "test") {
|
|
9
|
+
var sanitized = new Error("Unexpected Server Error");
|
|
10
|
+
sanitized.stack = void 0;
|
|
11
|
+
return sanitized;
|
|
12
|
+
}
|
|
13
|
+
return error;
|
|
14
|
+
}
|
|
15
|
+
function sanitizeErrors(errors) {
|
|
16
|
+
return Object.entries(errors).reduce(function(acc, param) {
|
|
17
|
+
var _param = _sliced_to_array(param, 2), routeId = _param[0], error = _param[1];
|
|
18
|
+
return Object.assign(acc, _define_property({}, routeId, sanitizeError(error)));
|
|
19
|
+
}, {});
|
|
20
|
+
}
|
|
21
|
+
function serializeError(error) {
|
|
22
|
+
var sanitized = sanitizeError(error);
|
|
23
|
+
return {
|
|
24
|
+
message: sanitized.message,
|
|
25
|
+
stack: sanitized.stack
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function serializeErrors(errors) {
|
|
29
|
+
if (!errors) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
var entries = Object.entries(errors);
|
|
33
|
+
var serialized = {};
|
|
34
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
|
|
35
|
+
try {
|
|
36
|
+
for (var _iterator = entries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
37
|
+
var _step_value = _sliced_to_array(_step.value, 2), key = _step_value[0], val = _step_value[1];
|
|
38
|
+
if (isRouteErrorResponse(val)) {
|
|
39
|
+
serialized[key] = _object_spread_props(_object_spread({}, val), {
|
|
40
|
+
__type: "RouteErrorResponse"
|
|
41
|
+
});
|
|
42
|
+
} else if (_instanceof(val, Error)) {
|
|
43
|
+
var sanitized = sanitizeError(val);
|
|
44
|
+
serialized[key] = _object_spread({
|
|
45
|
+
message: sanitized.message,
|
|
46
|
+
stack: sanitized.stack,
|
|
47
|
+
__type: "Error"
|
|
48
|
+
}, sanitized.name !== "Error" ? {
|
|
49
|
+
__subType: sanitized.name
|
|
50
|
+
} : {});
|
|
51
|
+
} else {
|
|
52
|
+
serialized[key] = val;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
} catch (err) {
|
|
56
|
+
_didIteratorError = true;
|
|
57
|
+
_iteratorError = err;
|
|
58
|
+
} finally {
|
|
59
|
+
try {
|
|
60
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
61
|
+
_iterator.return();
|
|
62
|
+
}
|
|
63
|
+
} finally {
|
|
64
|
+
if (_didIteratorError) {
|
|
65
|
+
throw _iteratorError;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return serialized;
|
|
70
|
+
}
|
|
71
|
+
function errorResponseToJson(errorResponse) {
|
|
72
|
+
return json(
|
|
73
|
+
// @ts-expect-error This is "private" from users but intended for internal use
|
|
74
|
+
serializeError(errorResponse.error || new Error("Unexpected Server Error")),
|
|
75
|
+
{
|
|
76
|
+
status: errorResponse.status,
|
|
77
|
+
statusText: errorResponse.statusText,
|
|
78
|
+
headers: {
|
|
79
|
+
"X-Modernjs-Error": "yes"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
export {
|
|
85
|
+
errorResponseToJson,
|
|
86
|
+
sanitizeError,
|
|
87
|
+
sanitizeErrors,
|
|
88
|
+
serializeError,
|
|
89
|
+
serializeErrors
|
|
90
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { _ as _async_to_generator } from "@swc/helpers/_/_async_to_generator";
|
|
2
2
|
import { _ as _instanceof } from "@swc/helpers/_/_instanceof";
|
|
3
3
|
import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
|
|
4
|
-
import { createStaticHandler, UNSAFE_DEFERRED_SYMBOL as DEFERRED_SYMBOL, isRouteErrorResponse } from "@modern-js/runtime-utils/remix-router";
|
|
4
|
+
import { createStaticHandler, UNSAFE_DEFERRED_SYMBOL as DEFERRED_SYMBOL, isRouteErrorResponse, json } from "@modern-js/runtime-utils/remix-router";
|
|
5
5
|
import { transformNestedRoutes } from "@modern-js/runtime-utils/browser";
|
|
6
6
|
import { isPlainObject } from "@modern-js/utils/lodash";
|
|
7
7
|
import { matchEntry, createRequestContext, reporterCtx } from "@modern-js/runtime-utils/node";
|
|
@@ -9,6 +9,7 @@ import { time } from "@modern-js/runtime-utils/time";
|
|
|
9
9
|
import { LOADER_REPORTER_NAME } from "@modern-js/utils/universal/constants";
|
|
10
10
|
import { CONTENT_TYPE_DEFERRED, LOADER_ID_PARAM } from "../common/constants";
|
|
11
11
|
import { createDeferredReadableStream } from "./response";
|
|
12
|
+
import { errorResponseToJson, serializeError } from "./errors";
|
|
12
13
|
var redirectStatusCodes = /* @__PURE__ */ new Set([
|
|
13
14
|
301,
|
|
14
15
|
302,
|
|
@@ -37,7 +38,7 @@ function convertModernRedirectResponse(headers, basename) {
|
|
|
37
38
|
}
|
|
38
39
|
var handleRequest = function() {
|
|
39
40
|
var _ref = _async_to_generator(function(param) {
|
|
40
|
-
var request, serverRoutes, routesConfig, context, url, routeId, entry, basename, end,
|
|
41
|
+
var request, serverRoutes, routesConfig, context, url, routeId, entry, basename, end, reporter, routes, queryRoute, requestContext, response, deferredData, body, init, headers, cost, error, errorInstance;
|
|
41
42
|
return _ts_generator(this, function(_state) {
|
|
42
43
|
switch (_state.label) {
|
|
43
44
|
case 0:
|
|
@@ -52,7 +53,7 @@ var handleRequest = function() {
|
|
|
52
53
|
}
|
|
53
54
|
basename = entry.urlPath;
|
|
54
55
|
end = time();
|
|
55
|
-
|
|
56
|
+
reporter = context.reporter;
|
|
56
57
|
routes = transformNestedRoutes(routesConfig, reporter);
|
|
57
58
|
queryRoute = createStaticHandler(routes, {
|
|
58
59
|
basename
|
|
@@ -108,18 +109,20 @@ var handleRequest = function() {
|
|
|
108
109
|
];
|
|
109
110
|
case 3:
|
|
110
111
|
error = _state.sent();
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
if (isResponse(error)) {
|
|
113
|
+
error.headers.set("X-Modernjs-Catch", "yes");
|
|
114
|
+
response = error;
|
|
115
|
+
} else if (isRouteErrorResponse(error)) {
|
|
116
|
+
response = errorResponseToJson(error);
|
|
114
117
|
} else {
|
|
115
|
-
|
|
118
|
+
errorInstance = _instanceof(error, Error) || _instanceof(error, DOMException) ? error : new Error("Unexpected Server Error");
|
|
119
|
+
response = json(serializeError(errorInstance), {
|
|
120
|
+
status: 500,
|
|
121
|
+
headers: {
|
|
122
|
+
"X-Modernjs-Error": "yes"
|
|
123
|
+
}
|
|
124
|
+
});
|
|
116
125
|
}
|
|
117
|
-
response = new Response(message, {
|
|
118
|
-
status: 500,
|
|
119
|
-
headers: {
|
|
120
|
-
"Content-Type": "text/plain"
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
126
|
return [
|
|
124
127
|
3,
|
|
125
128
|
4
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { isRouteErrorResponse, json } from "@modern-js/runtime-utils/remix-router";
|
|
2
|
+
function sanitizeError(error) {
|
|
3
|
+
if (error instanceof Error && process.env.NODE_ENV !== "development" && process.env.NODE_ENV !== "test") {
|
|
4
|
+
const sanitized = new Error("Unexpected Server Error");
|
|
5
|
+
sanitized.stack = void 0;
|
|
6
|
+
return sanitized;
|
|
7
|
+
}
|
|
8
|
+
return error;
|
|
9
|
+
}
|
|
10
|
+
function sanitizeErrors(errors) {
|
|
11
|
+
return Object.entries(errors).reduce((acc, [routeId, error]) => {
|
|
12
|
+
return Object.assign(acc, {
|
|
13
|
+
[routeId]: sanitizeError(error)
|
|
14
|
+
});
|
|
15
|
+
}, {});
|
|
16
|
+
}
|
|
17
|
+
function serializeError(error) {
|
|
18
|
+
const sanitized = sanitizeError(error);
|
|
19
|
+
return {
|
|
20
|
+
message: sanitized.message,
|
|
21
|
+
stack: sanitized.stack
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function serializeErrors(errors) {
|
|
25
|
+
if (!errors) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const entries = Object.entries(errors);
|
|
29
|
+
const serialized = {};
|
|
30
|
+
for (const [key, val] of entries) {
|
|
31
|
+
if (isRouteErrorResponse(val)) {
|
|
32
|
+
serialized[key] = {
|
|
33
|
+
...val,
|
|
34
|
+
__type: "RouteErrorResponse"
|
|
35
|
+
};
|
|
36
|
+
} else if (val instanceof Error) {
|
|
37
|
+
const sanitized = sanitizeError(val);
|
|
38
|
+
serialized[key] = {
|
|
39
|
+
message: sanitized.message,
|
|
40
|
+
stack: sanitized.stack,
|
|
41
|
+
__type: "Error",
|
|
42
|
+
// If this is a subclass (i.e., ReferenceError), send up the type so we
|
|
43
|
+
// can re-create the same type during hydration. This will only apply
|
|
44
|
+
// in dev mode since all production errors are sanitized to normal
|
|
45
|
+
// Error instances
|
|
46
|
+
...sanitized.name !== "Error" ? {
|
|
47
|
+
__subType: sanitized.name
|
|
48
|
+
} : {}
|
|
49
|
+
};
|
|
50
|
+
} else {
|
|
51
|
+
serialized[key] = val;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return serialized;
|
|
55
|
+
}
|
|
56
|
+
function errorResponseToJson(errorResponse) {
|
|
57
|
+
return json(
|
|
58
|
+
// @ts-expect-error This is "private" from users but intended for internal use
|
|
59
|
+
serializeError(errorResponse.error || new Error("Unexpected Server Error")),
|
|
60
|
+
{
|
|
61
|
+
status: errorResponse.status,
|
|
62
|
+
statusText: errorResponse.statusText,
|
|
63
|
+
headers: {
|
|
64
|
+
"X-Modernjs-Error": "yes"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
errorResponseToJson,
|
|
71
|
+
sanitizeError,
|
|
72
|
+
sanitizeErrors,
|
|
73
|
+
serializeError,
|
|
74
|
+
serializeErrors
|
|
75
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createStaticHandler, UNSAFE_DEFERRED_SYMBOL as DEFERRED_SYMBOL, isRouteErrorResponse } from "@modern-js/runtime-utils/remix-router";
|
|
1
|
+
import { createStaticHandler, UNSAFE_DEFERRED_SYMBOL as DEFERRED_SYMBOL, isRouteErrorResponse, json } from "@modern-js/runtime-utils/remix-router";
|
|
2
2
|
import { transformNestedRoutes } from "@modern-js/runtime-utils/browser";
|
|
3
3
|
import { isPlainObject } from "@modern-js/utils/lodash";
|
|
4
4
|
import { matchEntry, createRequestContext, reporterCtx } from "@modern-js/runtime-utils/node";
|
|
@@ -6,6 +6,7 @@ import { time } from "@modern-js/runtime-utils/time";
|
|
|
6
6
|
import { LOADER_REPORTER_NAME } from "@modern-js/utils/universal/constants";
|
|
7
7
|
import { CONTENT_TYPE_DEFERRED, LOADER_ID_PARAM } from "../common/constants";
|
|
8
8
|
import { createDeferredReadableStream } from "./response";
|
|
9
|
+
import { errorResponseToJson, serializeError } from "./errors";
|
|
9
10
|
const redirectStatusCodes = /* @__PURE__ */ new Set([
|
|
10
11
|
301,
|
|
11
12
|
302,
|
|
@@ -41,7 +42,7 @@ const handleRequest = async ({ request, serverRoutes, routes: routesConfig, cont
|
|
|
41
42
|
}
|
|
42
43
|
const basename = entry.urlPath;
|
|
43
44
|
const end = time();
|
|
44
|
-
const {
|
|
45
|
+
const { reporter } = context;
|
|
45
46
|
const routes = transformNestedRoutes(routesConfig, reporter);
|
|
46
47
|
const { queryRoute } = createStaticHandler(routes, {
|
|
47
48
|
basename
|
|
@@ -81,18 +82,20 @@ const handleRequest = async ({ request, serverRoutes, routes: routesConfig, cont
|
|
|
81
82
|
const cost = end();
|
|
82
83
|
reporter === null || reporter === void 0 ? void 0 : reporter.reportTiming(`${LOADER_REPORTER_NAME}-navigation`, cost);
|
|
83
84
|
} catch (error) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
if (isResponse(error)) {
|
|
86
|
+
error.headers.set("X-Modernjs-Catch", "yes");
|
|
87
|
+
response = error;
|
|
88
|
+
} else if (isRouteErrorResponse(error)) {
|
|
89
|
+
response = errorResponseToJson(error);
|
|
87
90
|
} else {
|
|
88
|
-
|
|
91
|
+
const errorInstance = error instanceof Error || error instanceof DOMException ? error : new Error("Unexpected Server Error");
|
|
92
|
+
response = json(serializeError(errorInstance), {
|
|
93
|
+
status: 500,
|
|
94
|
+
headers: {
|
|
95
|
+
"X-Modernjs-Error": "yes"
|
|
96
|
+
}
|
|
97
|
+
});
|
|
89
98
|
}
|
|
90
|
-
response = new Response(message, {
|
|
91
|
-
status: 500,
|
|
92
|
-
headers: {
|
|
93
|
-
"Content-Type": "text/plain"
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
99
|
}
|
|
97
100
|
return response;
|
|
98
101
|
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The following code is modified based on
|
|
3
|
+
* https://github.com/remix-run/remix/blob/main/packages/remix-server-runtime/errors.ts
|
|
4
|
+
*
|
|
5
|
+
* MIT Licensed
|
|
6
|
+
* Author Michael Jackson
|
|
7
|
+
* Copyright 2021 Remix Software Inc.
|
|
8
|
+
* https://github.com/remix-run/remix/blob/main/LICENSE.md
|
|
9
|
+
*/
|
|
10
|
+
import type { ErrorResponse, StaticHandlerContext } from '@modern-js/runtime-utils/remix-router';
|
|
11
|
+
/**
|
|
12
|
+
* This thing probably warrants some explanation.
|
|
13
|
+
*
|
|
14
|
+
* The whole point here is to emulate componentDidCatch for server rendering and
|
|
15
|
+
* data loading. It can get tricky. React can do this on component boundaries
|
|
16
|
+
* but doesn't support it for server rendering or data loading. We know enough
|
|
17
|
+
* with nested routes to be able to emulate the behavior (because we know them
|
|
18
|
+
* statically before rendering.)
|
|
19
|
+
*
|
|
20
|
+
* Each route can export an `ErrorBoundary`.
|
|
21
|
+
*
|
|
22
|
+
* - When rendering throws an error, the nearest error boundary will render
|
|
23
|
+
* (normal react componentDidCatch). This will be the route's own boundary, but
|
|
24
|
+
* if none is provided, it will bubble up to the parents.
|
|
25
|
+
* - When data loading throws an error, the nearest error boundary will render
|
|
26
|
+
* - When performing an action, the nearest error boundary for the action's
|
|
27
|
+
* route tree will render (no redirect happens)
|
|
28
|
+
*
|
|
29
|
+
* During normal react rendering, we do nothing special, just normal
|
|
30
|
+
* componentDidCatch.
|
|
31
|
+
*
|
|
32
|
+
* For server rendering, we mutate `renderBoundaryRouteId` to know the last
|
|
33
|
+
* layout that has an error boundary that tried to render. This emulates which
|
|
34
|
+
* layout would catch a thrown error. If the rendering fails, we catch the error
|
|
35
|
+
* on the server, and go again a second time with the emulator holding on to the
|
|
36
|
+
* information it needs to render the same error boundary as a dynamically
|
|
37
|
+
* thrown render error.
|
|
38
|
+
*
|
|
39
|
+
* When data loading, server or client side, we use the emulator to likewise
|
|
40
|
+
* hang on to the error and re-render at the appropriate layout (where a thrown
|
|
41
|
+
* error would have been caught by cDC).
|
|
42
|
+
*
|
|
43
|
+
* When actions throw, it all works the same. There's an edge case to be aware
|
|
44
|
+
* of though. Actions normally are required to redirect, but in the case of
|
|
45
|
+
* errors, we render the action's route with the emulator holding on to the
|
|
46
|
+
* error. If during this render a parent route/loader throws we ignore that new
|
|
47
|
+
* error and render the action's original error as deeply as possible. In other
|
|
48
|
+
* words, we simply ignore the new error and use the action's error in place
|
|
49
|
+
* because it came first, and that just wouldn't be fair to let errors cut in
|
|
50
|
+
* line.
|
|
51
|
+
*/
|
|
52
|
+
export declare function sanitizeError<T = unknown>(error: T): Error | T;
|
|
53
|
+
export declare function sanitizeErrors(errors: NonNullable<StaticHandlerContext['errors']>): {};
|
|
54
|
+
export type SerializedError = {
|
|
55
|
+
message: string;
|
|
56
|
+
stack?: string;
|
|
57
|
+
};
|
|
58
|
+
export declare function serializeError(error: Error): SerializedError;
|
|
59
|
+
export declare function serializeErrors(errors: StaticHandlerContext['errors']): StaticHandlerContext['errors'];
|
|
60
|
+
export declare function errorResponseToJson(errorResponse: ErrorResponse): Response;
|
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"modern",
|
|
16
16
|
"modern.js"
|
|
17
17
|
],
|
|
18
|
-
"version": "2.
|
|
18
|
+
"version": "2.53.0",
|
|
19
19
|
"engines": {
|
|
20
20
|
"node": ">=16.2.0"
|
|
21
21
|
},
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"@babel/core": "^7.23.2",
|
|
50
50
|
"path-to-regexp": "^6.2.0",
|
|
51
51
|
"@swc/helpers": "0.5.3",
|
|
52
|
-
"@modern-js/utils": "2.
|
|
53
|
-
"@modern-js/runtime-utils": "2.
|
|
52
|
+
"@modern-js/utils": "2.53.0",
|
|
53
|
+
"@modern-js/runtime-utils": "2.53.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/babel__core": "^7.20.1",
|
|
@@ -66,11 +66,11 @@
|
|
|
66
66
|
"webpack": "^5.91.0",
|
|
67
67
|
"react": "^18",
|
|
68
68
|
"react-dom": "^18",
|
|
69
|
-
"@modern-js/core": "2.
|
|
70
|
-
"@modern-js/server-core": "2.
|
|
71
|
-
"@modern-js/types": "2.
|
|
72
|
-
"@scripts/
|
|
73
|
-
"@scripts/
|
|
69
|
+
"@modern-js/core": "2.53.0",
|
|
70
|
+
"@modern-js/server-core": "2.53.0",
|
|
71
|
+
"@modern-js/types": "2.53.0",
|
|
72
|
+
"@scripts/build": "2.53.0",
|
|
73
|
+
"@scripts/jest-config": "2.53.0"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"react": ">=17.0.0"
|