@lolyjs/core 0.2.0-alpha.30 → 0.2.0-alpha.31
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 +6 -7
- package/dist/cli.cjs +359 -171
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +359 -171
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +363 -171
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +361 -171
- package/dist/index.js.map +1 -1
- package/dist/{index.types-B9j4OQft.d.mts → index.types-JJ0KjvFU.d.mts} +58 -14
- package/dist/{index.types-B9j4OQft.d.ts → index.types-JJ0KjvFU.d.ts} +58 -14
- package/dist/react/cache.d.mts +1 -1
- package/dist/react/cache.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -9870,6 +9870,8 @@ var src_exports = {};
|
|
|
9870
9870
|
__export(src_exports, {
|
|
9871
9871
|
DEFAULT_CONFIG: () => DEFAULT_CONFIG,
|
|
9872
9872
|
Logger: () => Logger,
|
|
9873
|
+
NotFoundResponse: () => NotFoundResponse,
|
|
9874
|
+
RedirectResponse: () => RedirectResponse,
|
|
9873
9875
|
ValidationError: () => ValidationError,
|
|
9874
9876
|
bootstrapClient: () => bootstrapClient,
|
|
9875
9877
|
buildApp: () => buildApp,
|
|
@@ -10815,6 +10817,18 @@ function writeRoutesManifest({
|
|
|
10815
10817
|
import_fs7.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
10816
10818
|
}
|
|
10817
10819
|
|
|
10820
|
+
// modules/router/index.types.ts
|
|
10821
|
+
var RedirectResponse = class {
|
|
10822
|
+
constructor(destination, permanent = false) {
|
|
10823
|
+
this.destination = destination;
|
|
10824
|
+
this.permanent = permanent;
|
|
10825
|
+
}
|
|
10826
|
+
};
|
|
10827
|
+
var NotFoundResponse = class {
|
|
10828
|
+
constructor() {
|
|
10829
|
+
}
|
|
10830
|
+
};
|
|
10831
|
+
|
|
10818
10832
|
// modules/router/loader-routes.ts
|
|
10819
10833
|
var import_fs8 = __toESM(require("fs"));
|
|
10820
10834
|
var import_path10 = __toESM(require("path"));
|
|
@@ -15638,16 +15652,6 @@ async function runRouteServerHook(route, ctx) {
|
|
|
15638
15652
|
// modules/server/handlers/response.ts
|
|
15639
15653
|
function handleDataResponse(res, loaderResult, theme, layoutProps, pageProps, error, message) {
|
|
15640
15654
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
15641
|
-
if (loaderResult.redirect) {
|
|
15642
|
-
res.statusCode = 200;
|
|
15643
|
-
res.end(JSON.stringify({ redirect: loaderResult.redirect }));
|
|
15644
|
-
return;
|
|
15645
|
-
}
|
|
15646
|
-
if (loaderResult.notFound) {
|
|
15647
|
-
res.statusCode = 404;
|
|
15648
|
-
res.end(JSON.stringify({ notFound: true }));
|
|
15649
|
-
return;
|
|
15650
|
-
}
|
|
15651
15655
|
const response = {
|
|
15652
15656
|
// Combined props for backward compatibility
|
|
15653
15657
|
props: loaderResult.props ?? {},
|
|
@@ -15768,6 +15772,145 @@ function mergeMetadata(base, override) {
|
|
|
15768
15772
|
function isDataRequest(req) {
|
|
15769
15773
|
return req.query && req.query.__fw_data === "1" || req.headers["x-fw-data"] === "1";
|
|
15770
15774
|
}
|
|
15775
|
+
async function renderNotFoundPage(notFoundPage, req, res, urlPath, finalUrlPath, routerData, assetManifest, theme, clientJsPath, clientCssPath, faviconInfo, projectRoot, skipLayoutHooks, errorPage, routeChunks, env, config) {
|
|
15776
|
+
const ctx = {
|
|
15777
|
+
req,
|
|
15778
|
+
res,
|
|
15779
|
+
params: {},
|
|
15780
|
+
pathname: urlPath,
|
|
15781
|
+
locals: {},
|
|
15782
|
+
Redirect: (destination, permanent = false) => new RedirectResponse(destination, permanent),
|
|
15783
|
+
NotFound: () => new NotFoundResponse()
|
|
15784
|
+
};
|
|
15785
|
+
const layoutProps = {};
|
|
15786
|
+
if (!skipLayoutHooks && notFoundPage.layoutServerHooks && notFoundPage.layoutServerHooks.length > 0) {
|
|
15787
|
+
for (let i = 0; i < notFoundPage.layoutServerHooks.length; i++) {
|
|
15788
|
+
const layoutServerHook = notFoundPage.layoutServerHooks[i];
|
|
15789
|
+
const layoutMiddlewares = notFoundPage.layoutMiddlewares?.[i] || [];
|
|
15790
|
+
if (layoutMiddlewares.length > 0) {
|
|
15791
|
+
for (const mw of layoutMiddlewares) {
|
|
15792
|
+
try {
|
|
15793
|
+
await Promise.resolve(
|
|
15794
|
+
mw(ctx, async () => {
|
|
15795
|
+
})
|
|
15796
|
+
);
|
|
15797
|
+
} catch (error) {
|
|
15798
|
+
const reqLogger = getRequestLogger(req);
|
|
15799
|
+
const layoutFile = notFoundPage.layoutFiles[i];
|
|
15800
|
+
const relativeLayoutPath = layoutFile ? import_path25.default.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
|
|
15801
|
+
reqLogger.error("Layout middleware failed for not-found page", error instanceof Error ? error : new Error(String(error)), {
|
|
15802
|
+
layoutIndex: i,
|
|
15803
|
+
layoutFile: relativeLayoutPath
|
|
15804
|
+
});
|
|
15805
|
+
throw error;
|
|
15806
|
+
}
|
|
15807
|
+
if (ctx.res.headersSent) {
|
|
15808
|
+
return;
|
|
15809
|
+
}
|
|
15810
|
+
}
|
|
15811
|
+
}
|
|
15812
|
+
if (layoutServerHook) {
|
|
15813
|
+
try {
|
|
15814
|
+
const layoutResult = await layoutServerHook(ctx);
|
|
15815
|
+
if (layoutResult instanceof RedirectResponse) {
|
|
15816
|
+
handleRedirect(res, { destination: layoutResult.destination, permanent: layoutResult.permanent });
|
|
15817
|
+
return;
|
|
15818
|
+
}
|
|
15819
|
+
if (layoutResult instanceof NotFoundResponse) {
|
|
15820
|
+
handleNotFound(res, urlPath);
|
|
15821
|
+
return;
|
|
15822
|
+
}
|
|
15823
|
+
if (layoutResult.props) {
|
|
15824
|
+
Object.assign(layoutProps, layoutResult.props);
|
|
15825
|
+
}
|
|
15826
|
+
} catch (error) {
|
|
15827
|
+
const reqLogger = getRequestLogger(req);
|
|
15828
|
+
const layoutFile = notFoundPage.layoutFiles[i];
|
|
15829
|
+
const relativeLayoutPath = layoutFile ? import_path25.default.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
|
|
15830
|
+
reqLogger.warn("Layout server hook failed for not-found page", {
|
|
15831
|
+
error: error instanceof Error ? error.message : String(error),
|
|
15832
|
+
stack: error instanceof Error ? error.stack : void 0,
|
|
15833
|
+
layoutFile: relativeLayoutPath,
|
|
15834
|
+
layoutIndex: i
|
|
15835
|
+
});
|
|
15836
|
+
}
|
|
15837
|
+
}
|
|
15838
|
+
}
|
|
15839
|
+
}
|
|
15840
|
+
let loaderResult = await runRouteServerHook(notFoundPage, ctx);
|
|
15841
|
+
if (loaderResult instanceof RedirectResponse) {
|
|
15842
|
+
handleRedirect(res, { destination: loaderResult.destination, permanent: loaderResult.permanent });
|
|
15843
|
+
return;
|
|
15844
|
+
}
|
|
15845
|
+
if (loaderResult instanceof NotFoundResponse) {
|
|
15846
|
+
handleNotFound(res, urlPath);
|
|
15847
|
+
return;
|
|
15848
|
+
}
|
|
15849
|
+
const notFoundLoaderResult = loaderResult;
|
|
15850
|
+
if (!notFoundLoaderResult.theme) {
|
|
15851
|
+
notFoundLoaderResult.theme = theme;
|
|
15852
|
+
}
|
|
15853
|
+
const combinedProps = {
|
|
15854
|
+
...layoutProps,
|
|
15855
|
+
...notFoundLoaderResult.props || {}
|
|
15856
|
+
};
|
|
15857
|
+
const combinedLoaderResult = {
|
|
15858
|
+
...notFoundLoaderResult,
|
|
15859
|
+
props: combinedProps
|
|
15860
|
+
};
|
|
15861
|
+
const initialData = buildInitialData(finalUrlPath, {}, combinedLoaderResult);
|
|
15862
|
+
const appTree = buildAppTree(notFoundPage, {}, initialData.props);
|
|
15863
|
+
initialData.notFound = true;
|
|
15864
|
+
const nonce = res.locals.nonce || void 0;
|
|
15865
|
+
const entrypointFiles = [];
|
|
15866
|
+
if (assetManifest?.entrypoints?.client) {
|
|
15867
|
+
entrypointFiles.push(...assetManifest.entrypoints.client.map((file) => `${STATIC_PATH}/${file}`));
|
|
15868
|
+
}
|
|
15869
|
+
const documentTree = createDocumentTree({
|
|
15870
|
+
appTree,
|
|
15871
|
+
initialData,
|
|
15872
|
+
routerData,
|
|
15873
|
+
meta: combinedLoaderResult.metadata ?? null,
|
|
15874
|
+
titleFallback: "Not found",
|
|
15875
|
+
descriptionFallback: "Loly demo",
|
|
15876
|
+
chunkHref: null,
|
|
15877
|
+
entrypointFiles,
|
|
15878
|
+
theme,
|
|
15879
|
+
clientJsPath,
|
|
15880
|
+
clientCssPath,
|
|
15881
|
+
nonce,
|
|
15882
|
+
faviconPath: faviconInfo?.path || null,
|
|
15883
|
+
faviconType: faviconInfo?.type || null
|
|
15884
|
+
});
|
|
15885
|
+
let didError = false;
|
|
15886
|
+
const { pipe, abort } = (0, import_server.renderToPipeableStream)(documentTree, {
|
|
15887
|
+
onShellReady() {
|
|
15888
|
+
if (didError || res.headersSent) return;
|
|
15889
|
+
res.statusCode = 404;
|
|
15890
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
15891
|
+
pipe(res);
|
|
15892
|
+
},
|
|
15893
|
+
onShellError(err) {
|
|
15894
|
+
didError = true;
|
|
15895
|
+
const reqLogger = getRequestLogger(req);
|
|
15896
|
+
reqLogger.error("SSR shell error", err, { route: "not-found" });
|
|
15897
|
+
if (!res.headersSent && errorPage) {
|
|
15898
|
+
renderErrorPageWithStream(errorPage, req, res, err, routeChunks || {}, theme, projectRoot, env, config, notFoundPage);
|
|
15899
|
+
} else if (!res.headersSent) {
|
|
15900
|
+
res.statusCode = 500;
|
|
15901
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
15902
|
+
res.end("<!doctype html><h1>Internal Server Error</h1>");
|
|
15903
|
+
}
|
|
15904
|
+
abort();
|
|
15905
|
+
},
|
|
15906
|
+
onError(err) {
|
|
15907
|
+
didError = true;
|
|
15908
|
+
const reqLogger = getRequestLogger(req);
|
|
15909
|
+
reqLogger.error("SSR error", err, { route: "not-found" });
|
|
15910
|
+
}
|
|
15911
|
+
});
|
|
15912
|
+
req.on("close", () => abort());
|
|
15913
|
+
}
|
|
15771
15914
|
async function handlePageRequest(options) {
|
|
15772
15915
|
try {
|
|
15773
15916
|
await handlePageRequestInternal(options);
|
|
@@ -15775,7 +15918,7 @@ async function handlePageRequest(options) {
|
|
|
15775
15918
|
const { errorPage, req, res, routeChunks, theme, projectRoot } = options;
|
|
15776
15919
|
const reqLogger = getRequestLogger(req);
|
|
15777
15920
|
if (errorPage) {
|
|
15778
|
-
await renderErrorPageWithStream(errorPage, req, res, error, routeChunks || {}, theme, projectRoot, options.env, options.config);
|
|
15921
|
+
await renderErrorPageWithStream(errorPage, req, res, error, routeChunks || {}, theme, projectRoot, options.env, options.config, options.notFoundPage);
|
|
15779
15922
|
} else {
|
|
15780
15923
|
reqLogger.error("Unhandled error in page request", error, {
|
|
15781
15924
|
urlPath: options.urlPath,
|
|
@@ -15885,135 +16028,25 @@ async function handlePageRequestInternal(options) {
|
|
|
15885
16028
|
return;
|
|
15886
16029
|
}
|
|
15887
16030
|
if (notFoundPage) {
|
|
15888
|
-
|
|
16031
|
+
await renderNotFoundPage(
|
|
16032
|
+
notFoundPage,
|
|
15889
16033
|
req,
|
|
15890
16034
|
res,
|
|
15891
|
-
|
|
15892
|
-
|
|
15893
|
-
locals: {}
|
|
15894
|
-
};
|
|
15895
|
-
const layoutProps2 = {};
|
|
15896
|
-
if (!skipLayoutHooks && notFoundPage.layoutServerHooks && notFoundPage.layoutServerHooks.length > 0) {
|
|
15897
|
-
for (let i = 0; i < notFoundPage.layoutServerHooks.length; i++) {
|
|
15898
|
-
const layoutServerHook = notFoundPage.layoutServerHooks[i];
|
|
15899
|
-
const layoutMiddlewares = notFoundPage.layoutMiddlewares?.[i] || [];
|
|
15900
|
-
if (layoutMiddlewares.length > 0) {
|
|
15901
|
-
for (const mw of layoutMiddlewares) {
|
|
15902
|
-
try {
|
|
15903
|
-
await Promise.resolve(
|
|
15904
|
-
mw(ctx2, async () => {
|
|
15905
|
-
})
|
|
15906
|
-
);
|
|
15907
|
-
} catch (error) {
|
|
15908
|
-
const reqLogger2 = getRequestLogger(req);
|
|
15909
|
-
const layoutFile = notFoundPage.layoutFiles[i];
|
|
15910
|
-
const relativeLayoutPath = layoutFile ? import_path25.default.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
|
|
15911
|
-
reqLogger2.error("Layout middleware failed for not-found page", error instanceof Error ? error : new Error(String(error)), {
|
|
15912
|
-
layoutIndex: i,
|
|
15913
|
-
layoutFile: relativeLayoutPath
|
|
15914
|
-
});
|
|
15915
|
-
throw error;
|
|
15916
|
-
}
|
|
15917
|
-
if (ctx2.res.headersSent) {
|
|
15918
|
-
return;
|
|
15919
|
-
}
|
|
15920
|
-
}
|
|
15921
|
-
}
|
|
15922
|
-
if (layoutServerHook) {
|
|
15923
|
-
try {
|
|
15924
|
-
const layoutResult = await layoutServerHook(ctx2);
|
|
15925
|
-
if (layoutResult.props) {
|
|
15926
|
-
Object.assign(layoutProps2, layoutResult.props);
|
|
15927
|
-
}
|
|
15928
|
-
} catch (error) {
|
|
15929
|
-
const reqLogger2 = getRequestLogger(req);
|
|
15930
|
-
const layoutFile = notFoundPage.layoutFiles[i];
|
|
15931
|
-
const relativeLayoutPath = layoutFile ? import_path25.default.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
|
|
15932
|
-
reqLogger2.warn("Layout server hook failed for not-found page", {
|
|
15933
|
-
error: error instanceof Error ? error.message : String(error),
|
|
15934
|
-
stack: error instanceof Error ? error.stack : void 0,
|
|
15935
|
-
layoutFile: relativeLayoutPath,
|
|
15936
|
-
layoutIndex: i
|
|
15937
|
-
});
|
|
15938
|
-
}
|
|
15939
|
-
}
|
|
15940
|
-
}
|
|
15941
|
-
}
|
|
15942
|
-
let loaderResult2 = await runRouteServerHook(notFoundPage, ctx2);
|
|
15943
|
-
if (!loaderResult2.theme) {
|
|
15944
|
-
loaderResult2.theme = theme;
|
|
15945
|
-
}
|
|
15946
|
-
const combinedProps2 = {
|
|
15947
|
-
...layoutProps2,
|
|
15948
|
-
...loaderResult2.props || {}
|
|
15949
|
-
};
|
|
15950
|
-
const combinedLoaderResult2 = {
|
|
15951
|
-
...loaderResult2,
|
|
15952
|
-
props: combinedProps2
|
|
15953
|
-
};
|
|
15954
|
-
if (isDataReq) {
|
|
15955
|
-
const pagePropsOnly = loaderResult2.props || {};
|
|
15956
|
-
handleDataResponse(
|
|
15957
|
-
res,
|
|
15958
|
-
combinedLoaderResult2,
|
|
15959
|
-
theme,
|
|
15960
|
-
skipLayoutHooks ? null : Object.keys(layoutProps2).length > 0 ? layoutProps2 : null,
|
|
15961
|
-
pagePropsOnly
|
|
15962
|
-
);
|
|
15963
|
-
return;
|
|
15964
|
-
}
|
|
15965
|
-
const initialData2 = buildInitialData(finalUrlPath, {}, combinedLoaderResult2);
|
|
15966
|
-
const appTree2 = buildAppTree(notFoundPage, {}, initialData2.props);
|
|
15967
|
-
initialData2.notFound = true;
|
|
15968
|
-
const nonce2 = res.locals.nonce || void 0;
|
|
15969
|
-
const entrypointFiles2 = [];
|
|
15970
|
-
if (assetManifest?.entrypoints?.client) {
|
|
15971
|
-
entrypointFiles2.push(...assetManifest.entrypoints.client.map((file) => `${STATIC_PATH}/${file}`));
|
|
15972
|
-
}
|
|
15973
|
-
const documentTree2 = createDocumentTree({
|
|
15974
|
-
appTree: appTree2,
|
|
15975
|
-
initialData: initialData2,
|
|
16035
|
+
urlPath,
|
|
16036
|
+
finalUrlPath,
|
|
15976
16037
|
routerData,
|
|
15977
|
-
|
|
15978
|
-
titleFallback: "Not found",
|
|
15979
|
-
descriptionFallback: "Loly demo",
|
|
15980
|
-
chunkHref: null,
|
|
15981
|
-
entrypointFiles: entrypointFiles2,
|
|
16038
|
+
assetManifest,
|
|
15982
16039
|
theme,
|
|
15983
16040
|
clientJsPath,
|
|
15984
16041
|
clientCssPath,
|
|
15985
|
-
|
|
15986
|
-
|
|
15987
|
-
|
|
15988
|
-
|
|
15989
|
-
|
|
15990
|
-
|
|
15991
|
-
|
|
15992
|
-
|
|
15993
|
-
res.statusCode = 404;
|
|
15994
|
-
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
15995
|
-
pipe2(res);
|
|
15996
|
-
},
|
|
15997
|
-
onShellError(err) {
|
|
15998
|
-
didError2 = true;
|
|
15999
|
-
const reqLogger2 = getRequestLogger(req);
|
|
16000
|
-
reqLogger2.error("SSR shell error", err, { route: "not-found" });
|
|
16001
|
-
if (!res.headersSent && errorPage) {
|
|
16002
|
-
renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot, env, config);
|
|
16003
|
-
} else if (!res.headersSent) {
|
|
16004
|
-
res.statusCode = 500;
|
|
16005
|
-
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
16006
|
-
res.end("<!doctype html><h1>Internal Server Error</h1>");
|
|
16007
|
-
}
|
|
16008
|
-
abort2();
|
|
16009
|
-
},
|
|
16010
|
-
onError(err) {
|
|
16011
|
-
didError2 = true;
|
|
16012
|
-
const reqLogger2 = getRequestLogger(req);
|
|
16013
|
-
reqLogger2.error("SSR error", err, { route: "not-found" });
|
|
16014
|
-
}
|
|
16015
|
-
});
|
|
16016
|
-
req.on("close", () => abort2());
|
|
16042
|
+
faviconInfo,
|
|
16043
|
+
projectRoot,
|
|
16044
|
+
skipLayoutHooks,
|
|
16045
|
+
errorPage,
|
|
16046
|
+
routeChunks,
|
|
16047
|
+
env,
|
|
16048
|
+
config
|
|
16049
|
+
);
|
|
16017
16050
|
return;
|
|
16018
16051
|
}
|
|
16019
16052
|
handleNotFound(res, urlPath);
|
|
@@ -16026,7 +16059,9 @@ async function handlePageRequestInternal(options) {
|
|
|
16026
16059
|
res,
|
|
16027
16060
|
params: sanitizedParams,
|
|
16028
16061
|
pathname: urlPath,
|
|
16029
|
-
locals: {}
|
|
16062
|
+
locals: {},
|
|
16063
|
+
Redirect: (destination, permanent = false) => new RedirectResponse(destination, permanent),
|
|
16064
|
+
NotFound: () => new NotFoundResponse()
|
|
16030
16065
|
};
|
|
16031
16066
|
await runRouteMiddlewares(route, ctx);
|
|
16032
16067
|
if (res.headersSent) {
|
|
@@ -16064,6 +16099,48 @@ async function handlePageRequestInternal(options) {
|
|
|
16064
16099
|
if (layoutServerHook) {
|
|
16065
16100
|
try {
|
|
16066
16101
|
const layoutResult = await layoutServerHook(ctx);
|
|
16102
|
+
if (layoutResult instanceof RedirectResponse) {
|
|
16103
|
+
if (isDataReq) {
|
|
16104
|
+
res.statusCode = 200;
|
|
16105
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
16106
|
+
res.end(JSON.stringify({ redirect: { destination: layoutResult.destination, permanent: layoutResult.permanent } }));
|
|
16107
|
+
} else {
|
|
16108
|
+
handleRedirect(res, { destination: layoutResult.destination, permanent: layoutResult.permanent });
|
|
16109
|
+
}
|
|
16110
|
+
return;
|
|
16111
|
+
}
|
|
16112
|
+
if (layoutResult instanceof NotFoundResponse) {
|
|
16113
|
+
if (isDataReq) {
|
|
16114
|
+
res.statusCode = 200;
|
|
16115
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
16116
|
+
res.end(JSON.stringify({ notFound: true }));
|
|
16117
|
+
} else {
|
|
16118
|
+
if (notFoundPage) {
|
|
16119
|
+
await renderNotFoundPage(
|
|
16120
|
+
notFoundPage,
|
|
16121
|
+
req,
|
|
16122
|
+
res,
|
|
16123
|
+
urlPath,
|
|
16124
|
+
finalUrlPath,
|
|
16125
|
+
routerData,
|
|
16126
|
+
assetManifest,
|
|
16127
|
+
theme,
|
|
16128
|
+
clientJsPath,
|
|
16129
|
+
clientCssPath,
|
|
16130
|
+
faviconInfo,
|
|
16131
|
+
projectRoot,
|
|
16132
|
+
skipLayoutHooks,
|
|
16133
|
+
errorPage,
|
|
16134
|
+
routeChunks,
|
|
16135
|
+
env,
|
|
16136
|
+
config
|
|
16137
|
+
);
|
|
16138
|
+
} else {
|
|
16139
|
+
handleNotFound(res, urlPath);
|
|
16140
|
+
}
|
|
16141
|
+
}
|
|
16142
|
+
return;
|
|
16143
|
+
}
|
|
16067
16144
|
if (layoutResult.props) {
|
|
16068
16145
|
Object.assign(layoutProps, layoutResult.props);
|
|
16069
16146
|
}
|
|
@@ -16088,8 +16165,51 @@ async function handlePageRequestInternal(options) {
|
|
|
16088
16165
|
let loaderResult;
|
|
16089
16166
|
try {
|
|
16090
16167
|
loaderResult = await runRouteServerHook(route, ctx);
|
|
16091
|
-
if (
|
|
16092
|
-
|
|
16168
|
+
if (loaderResult instanceof RedirectResponse) {
|
|
16169
|
+
if (isDataReq) {
|
|
16170
|
+
res.statusCode = 200;
|
|
16171
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
16172
|
+
res.end(JSON.stringify({ redirect: { destination: loaderResult.destination, permanent: loaderResult.permanent } }));
|
|
16173
|
+
} else {
|
|
16174
|
+
handleRedirect(res, { destination: loaderResult.destination, permanent: loaderResult.permanent });
|
|
16175
|
+
}
|
|
16176
|
+
return;
|
|
16177
|
+
}
|
|
16178
|
+
if (loaderResult instanceof NotFoundResponse) {
|
|
16179
|
+
if (isDataReq) {
|
|
16180
|
+
res.statusCode = 200;
|
|
16181
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
16182
|
+
res.end(JSON.stringify({ notFound: true }));
|
|
16183
|
+
} else {
|
|
16184
|
+
if (notFoundPage) {
|
|
16185
|
+
await renderNotFoundPage(
|
|
16186
|
+
notFoundPage,
|
|
16187
|
+
req,
|
|
16188
|
+
res,
|
|
16189
|
+
urlPath,
|
|
16190
|
+
finalUrlPath,
|
|
16191
|
+
routerData,
|
|
16192
|
+
assetManifest,
|
|
16193
|
+
theme,
|
|
16194
|
+
clientJsPath,
|
|
16195
|
+
clientCssPath,
|
|
16196
|
+
faviconInfo,
|
|
16197
|
+
projectRoot,
|
|
16198
|
+
skipLayoutHooks,
|
|
16199
|
+
errorPage,
|
|
16200
|
+
routeChunks,
|
|
16201
|
+
env,
|
|
16202
|
+
config
|
|
16203
|
+
);
|
|
16204
|
+
} else {
|
|
16205
|
+
handleNotFound(res, urlPath);
|
|
16206
|
+
}
|
|
16207
|
+
}
|
|
16208
|
+
return;
|
|
16209
|
+
}
|
|
16210
|
+
const pageLoaderResult2 = loaderResult;
|
|
16211
|
+
if (!pageLoaderResult2.theme) {
|
|
16212
|
+
pageLoaderResult2.theme = theme;
|
|
16093
16213
|
}
|
|
16094
16214
|
} catch (error) {
|
|
16095
16215
|
const relativePagePath = route.pageFile ? import_path25.default.relative(projectRoot || process.cwd(), route.pageFile) : "unknown";
|
|
@@ -16114,17 +16234,18 @@ async function handlePageRequestInternal(options) {
|
|
|
16114
16234
|
return;
|
|
16115
16235
|
} else {
|
|
16116
16236
|
if (errorPage) {
|
|
16117
|
-
await renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env, config);
|
|
16237
|
+
await renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env, config, notFoundPage);
|
|
16118
16238
|
return;
|
|
16119
16239
|
} else {
|
|
16120
16240
|
throw error;
|
|
16121
16241
|
}
|
|
16122
16242
|
}
|
|
16123
16243
|
}
|
|
16244
|
+
const pageLoaderResult = loaderResult;
|
|
16124
16245
|
const combinedProps = {
|
|
16125
16246
|
...layoutProps,
|
|
16126
16247
|
// Props from layouts (stable)
|
|
16127
|
-
...
|
|
16248
|
+
...pageLoaderResult.props || {}
|
|
16128
16249
|
// Props from page (overrides layout)
|
|
16129
16250
|
};
|
|
16130
16251
|
let combinedMetadata = null;
|
|
@@ -16133,18 +16254,18 @@ async function handlePageRequestInternal(options) {
|
|
|
16133
16254
|
combinedMetadata = mergeMetadata(combinedMetadata, layoutMeta);
|
|
16134
16255
|
}
|
|
16135
16256
|
}
|
|
16136
|
-
if (
|
|
16137
|
-
combinedMetadata = mergeMetadata(combinedMetadata,
|
|
16257
|
+
if (pageLoaderResult.metadata) {
|
|
16258
|
+
combinedMetadata = mergeMetadata(combinedMetadata, pageLoaderResult.metadata);
|
|
16138
16259
|
}
|
|
16139
16260
|
const combinedLoaderResult = {
|
|
16140
|
-
...
|
|
16261
|
+
...pageLoaderResult,
|
|
16141
16262
|
props: combinedProps,
|
|
16142
16263
|
metadata: combinedMetadata,
|
|
16143
16264
|
pathname: finalUrlPath
|
|
16144
16265
|
// Include rewritten pathname for client-side matching
|
|
16145
16266
|
};
|
|
16146
16267
|
if (isDataReq) {
|
|
16147
|
-
const pagePropsOnly =
|
|
16268
|
+
const pagePropsOnly = pageLoaderResult.props || {};
|
|
16148
16269
|
handleDataResponse(
|
|
16149
16270
|
res,
|
|
16150
16271
|
combinedLoaderResult,
|
|
@@ -16154,18 +16275,6 @@ async function handlePageRequestInternal(options) {
|
|
|
16154
16275
|
);
|
|
16155
16276
|
return;
|
|
16156
16277
|
}
|
|
16157
|
-
if (loaderResult.redirect) {
|
|
16158
|
-
handleRedirect(res, loaderResult.redirect);
|
|
16159
|
-
return;
|
|
16160
|
-
}
|
|
16161
|
-
if (loaderResult.notFound) {
|
|
16162
|
-
if (isDataReq) {
|
|
16163
|
-
res.status(200).json({ notFound: true });
|
|
16164
|
-
} else {
|
|
16165
|
-
handleNotFound(res, urlPath);
|
|
16166
|
-
}
|
|
16167
|
-
return;
|
|
16168
|
-
}
|
|
16169
16278
|
const initialData = buildInitialData(finalUrlPath, params, combinedLoaderResult);
|
|
16170
16279
|
const appTree = buildAppTree(route, params, initialData.props);
|
|
16171
16280
|
const chunkName = routeChunks[route.pattern];
|
|
@@ -16222,7 +16331,7 @@ async function handlePageRequestInternal(options) {
|
|
|
16222
16331
|
}
|
|
16223
16332
|
console.error("\u{1F4A1} This usually indicates a React rendering error\n");
|
|
16224
16333
|
if (!res.headersSent && errorPage) {
|
|
16225
|
-
renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot, env);
|
|
16334
|
+
renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot, env, config, notFoundPage);
|
|
16226
16335
|
} else if (!res.headersSent) {
|
|
16227
16336
|
res.statusCode = 500;
|
|
16228
16337
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
@@ -16244,7 +16353,7 @@ async function handlePageRequestInternal(options) {
|
|
|
16244
16353
|
abort();
|
|
16245
16354
|
});
|
|
16246
16355
|
}
|
|
16247
|
-
async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env = "dev", config) {
|
|
16356
|
+
async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env = "dev", config, notFoundPage) {
|
|
16248
16357
|
try {
|
|
16249
16358
|
const isDataReq = isDataRequest(req);
|
|
16250
16359
|
const skipLayoutHooks = isDataReq && req.headers["x-skip-layout-hooks"] === "true";
|
|
@@ -16253,7 +16362,9 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
|
|
|
16253
16362
|
res,
|
|
16254
16363
|
params: { error: String(error) },
|
|
16255
16364
|
pathname: req.path,
|
|
16256
|
-
locals: { error }
|
|
16365
|
+
locals: { error },
|
|
16366
|
+
Redirect: (destination, permanent = false) => new RedirectResponse(destination, permanent),
|
|
16367
|
+
NotFound: () => new NotFoundResponse()
|
|
16257
16368
|
};
|
|
16258
16369
|
const faviconInfo = projectRoot && config ? getFaviconInfo(projectRoot, config.directories.static, env === "dev") : null;
|
|
16259
16370
|
const layoutProps = {};
|
|
@@ -16286,6 +16397,26 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
|
|
|
16286
16397
|
if (layoutServerHook) {
|
|
16287
16398
|
try {
|
|
16288
16399
|
const layoutResult = await layoutServerHook(ctx);
|
|
16400
|
+
if (layoutResult instanceof RedirectResponse) {
|
|
16401
|
+
if (isDataReq) {
|
|
16402
|
+
res.statusCode = 200;
|
|
16403
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
16404
|
+
res.end(JSON.stringify({ redirect: { destination: layoutResult.destination, permanent: layoutResult.permanent } }));
|
|
16405
|
+
} else {
|
|
16406
|
+
handleRedirect(res, { destination: layoutResult.destination, permanent: layoutResult.permanent });
|
|
16407
|
+
}
|
|
16408
|
+
return;
|
|
16409
|
+
}
|
|
16410
|
+
if (layoutResult instanceof NotFoundResponse) {
|
|
16411
|
+
if (isDataReq) {
|
|
16412
|
+
res.statusCode = 200;
|
|
16413
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
16414
|
+
res.end(JSON.stringify({ notFound: true }));
|
|
16415
|
+
} else {
|
|
16416
|
+
handleNotFound(res, req.path);
|
|
16417
|
+
}
|
|
16418
|
+
return;
|
|
16419
|
+
}
|
|
16289
16420
|
if (layoutResult.props) {
|
|
16290
16421
|
Object.assign(layoutProps, layoutResult.props);
|
|
16291
16422
|
}
|
|
@@ -16303,22 +16434,69 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
|
|
|
16303
16434
|
}
|
|
16304
16435
|
}
|
|
16305
16436
|
let loaderResult = await runRouteServerHook(errorPage, ctx);
|
|
16306
|
-
if (
|
|
16307
|
-
|
|
16437
|
+
if (loaderResult instanceof RedirectResponse) {
|
|
16438
|
+
if (isDataReq) {
|
|
16439
|
+
res.statusCode = 200;
|
|
16440
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
16441
|
+
res.end(JSON.stringify({ redirect: { destination: loaderResult.destination, permanent: loaderResult.permanent } }));
|
|
16442
|
+
} else {
|
|
16443
|
+
handleRedirect(res, { destination: loaderResult.destination, permanent: loaderResult.permanent });
|
|
16444
|
+
}
|
|
16445
|
+
return;
|
|
16446
|
+
}
|
|
16447
|
+
if (loaderResult instanceof NotFoundResponse) {
|
|
16448
|
+
if (isDataReq) {
|
|
16449
|
+
res.statusCode = 200;
|
|
16450
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
16451
|
+
res.end(JSON.stringify({ notFound: true }));
|
|
16452
|
+
} else {
|
|
16453
|
+
if (notFoundPage) {
|
|
16454
|
+
const notFoundAssetManifest = env === "prod" && projectRoot ? loadAssetManifest(projectRoot) : null;
|
|
16455
|
+
const notFoundClientJsPath = env === "dev" ? "/static/client.js" : projectRoot ? getClientJsPath(projectRoot) : "/static/client.js";
|
|
16456
|
+
const notFoundClientCssPath = env === "dev" ? "/static/client.css" : projectRoot ? getClientCssPath(projectRoot) : "/static/client.css";
|
|
16457
|
+
const notFoundFaviconInfo = projectRoot && config ? getFaviconInfo(projectRoot, config.directories.static, env === "dev") : null;
|
|
16458
|
+
await renderNotFoundPage(
|
|
16459
|
+
notFoundPage,
|
|
16460
|
+
req,
|
|
16461
|
+
res,
|
|
16462
|
+
req.path,
|
|
16463
|
+
req.path,
|
|
16464
|
+
buildRouterData(req),
|
|
16465
|
+
notFoundAssetManifest,
|
|
16466
|
+
theme,
|
|
16467
|
+
notFoundClientJsPath,
|
|
16468
|
+
notFoundClientCssPath,
|
|
16469
|
+
notFoundFaviconInfo,
|
|
16470
|
+
projectRoot,
|
|
16471
|
+
false,
|
|
16472
|
+
errorPage,
|
|
16473
|
+
routeChunks,
|
|
16474
|
+
env,
|
|
16475
|
+
config
|
|
16476
|
+
);
|
|
16477
|
+
} else {
|
|
16478
|
+
handleNotFound(res, req.path);
|
|
16479
|
+
}
|
|
16480
|
+
}
|
|
16481
|
+
return;
|
|
16482
|
+
}
|
|
16483
|
+
const errorLoaderResult = loaderResult;
|
|
16484
|
+
if (!errorLoaderResult.theme && theme) {
|
|
16485
|
+
errorLoaderResult.theme = theme;
|
|
16308
16486
|
}
|
|
16309
16487
|
const combinedProps = {
|
|
16310
16488
|
...layoutProps,
|
|
16311
|
-
...
|
|
16489
|
+
...errorLoaderResult.props || {}
|
|
16312
16490
|
};
|
|
16313
16491
|
const combinedLoaderResult = {
|
|
16314
|
-
...
|
|
16492
|
+
...errorLoaderResult,
|
|
16315
16493
|
props: combinedProps
|
|
16316
16494
|
};
|
|
16317
16495
|
const initialData = buildInitialData(req.path, { error: String(error) }, combinedLoaderResult);
|
|
16318
16496
|
const routerData = buildRouterData(req);
|
|
16319
16497
|
initialData.error = true;
|
|
16320
16498
|
if (isDataReq) {
|
|
16321
|
-
const pagePropsOnly =
|
|
16499
|
+
const pagePropsOnly = errorLoaderResult.props || {};
|
|
16322
16500
|
handleDataResponse(
|
|
16323
16501
|
res,
|
|
16324
16502
|
combinedLoaderResult,
|
|
@@ -17999,7 +18177,9 @@ async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params,
|
|
|
17999
18177
|
res,
|
|
18000
18178
|
params,
|
|
18001
18179
|
pathname: urlPath,
|
|
18002
|
-
locals: {}
|
|
18180
|
+
locals: {},
|
|
18181
|
+
Redirect: (destination, permanent = false) => new RedirectResponse(destination, permanent),
|
|
18182
|
+
NotFound: () => new NotFoundResponse()
|
|
18003
18183
|
};
|
|
18004
18184
|
for (const mw of route.middlewares) {
|
|
18005
18185
|
await Promise.resolve(
|
|
@@ -18015,6 +18195,12 @@ async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params,
|
|
|
18015
18195
|
if (layoutServerHook) {
|
|
18016
18196
|
try {
|
|
18017
18197
|
const layoutResult = await layoutServerHook(ctx);
|
|
18198
|
+
if (layoutResult instanceof RedirectResponse || layoutResult instanceof NotFoundResponse) {
|
|
18199
|
+
console.warn(
|
|
18200
|
+
`\u26A0\uFE0F [framework][ssg] Layout server hook ${i} returned redirect/notFound for route ${route.pattern}. Redirect/NotFound is not supported in SSG (Static Site Generation). Skipping this route.`
|
|
18201
|
+
);
|
|
18202
|
+
return;
|
|
18203
|
+
}
|
|
18018
18204
|
if (layoutResult.props) {
|
|
18019
18205
|
Object.assign(layoutProps, layoutResult.props);
|
|
18020
18206
|
}
|
|
@@ -18036,10 +18222,17 @@ async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params,
|
|
|
18036
18222
|
let loaderResult = { props: {} };
|
|
18037
18223
|
if (route.loader) {
|
|
18038
18224
|
loaderResult = await route.loader(ctx);
|
|
18225
|
+
if (loaderResult instanceof RedirectResponse || loaderResult instanceof NotFoundResponse) {
|
|
18226
|
+
console.warn(
|
|
18227
|
+
`\u26A0\uFE0F [framework][ssg] Page server hook returned redirect/notFound for route ${route.pattern} (${urlPath}). Redirect/NotFound is not supported in SSG (Static Site Generation). Skipping this route.`
|
|
18228
|
+
);
|
|
18229
|
+
return;
|
|
18230
|
+
}
|
|
18039
18231
|
}
|
|
18232
|
+
const pageLoaderResult = loaderResult;
|
|
18040
18233
|
const combinedProps = {
|
|
18041
18234
|
...layoutProps,
|
|
18042
|
-
...
|
|
18235
|
+
...pageLoaderResult.props || {}
|
|
18043
18236
|
};
|
|
18044
18237
|
let combinedMetadata = null;
|
|
18045
18238
|
for (const layoutMeta of layoutMetadata) {
|
|
@@ -18047,17 +18240,14 @@ async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params,
|
|
|
18047
18240
|
combinedMetadata = mergeMetadata(combinedMetadata, layoutMeta);
|
|
18048
18241
|
}
|
|
18049
18242
|
}
|
|
18050
|
-
if (
|
|
18051
|
-
combinedMetadata = mergeMetadata(combinedMetadata,
|
|
18243
|
+
if (pageLoaderResult.metadata) {
|
|
18244
|
+
combinedMetadata = mergeMetadata(combinedMetadata, pageLoaderResult.metadata);
|
|
18052
18245
|
}
|
|
18053
18246
|
const combinedLoaderResult = {
|
|
18054
|
-
...
|
|
18247
|
+
...pageLoaderResult,
|
|
18055
18248
|
props: combinedProps,
|
|
18056
18249
|
metadata: combinedMetadata
|
|
18057
18250
|
};
|
|
18058
|
-
if (combinedLoaderResult.redirect || combinedLoaderResult.notFound) {
|
|
18059
|
-
return;
|
|
18060
|
-
}
|
|
18061
18251
|
const initialData = buildInitialData(urlPath, params, combinedLoaderResult);
|
|
18062
18252
|
const routerData = buildRouterData(req);
|
|
18063
18253
|
const appTree = buildAppTree(route, params, initialData.props);
|
|
@@ -19659,6 +19849,8 @@ var commonSchemas = {
|
|
|
19659
19849
|
0 && (module.exports = {
|
|
19660
19850
|
DEFAULT_CONFIG,
|
|
19661
19851
|
Logger,
|
|
19852
|
+
NotFoundResponse,
|
|
19853
|
+
RedirectResponse,
|
|
19662
19854
|
ValidationError,
|
|
19663
19855
|
bootstrapClient,
|
|
19664
19856
|
buildApp,
|