@bleedingdev/modern-js-server-core 3.9.0-ultramodern.2 → 3.9.0-ultramodern.20

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.
Files changed (65) hide show
  1. package/dist/cjs/adapters/node/hono.js +15 -5
  2. package/dist/cjs/adapters/node/index.js +4 -0
  3. package/dist/cjs/adapters/node/plugins/static.js +107 -29
  4. package/dist/cjs/helper.js +1 -1
  5. package/dist/cjs/index.js +10 -34
  6. package/dist/cjs/plugins/compat/index.js +1 -0
  7. package/dist/cjs/plugins/render/render.js +3 -4
  8. package/dist/cjs/plugins/render/ssrCache.js +63 -42
  9. package/dist/cjs/serverBase.js +60 -19
  10. package/dist/cjs/utils/error.js +0 -10
  11. package/dist/cjs/utils/transformStream.js +1 -1
  12. package/dist/esm/adapters/node/hono.mjs +15 -5
  13. package/dist/esm/adapters/node/index.mjs +1 -0
  14. package/dist/esm/adapters/node/plugins/static.mjs +107 -32
  15. package/dist/esm/helper.mjs +1 -1
  16. package/dist/esm/index.mjs +1 -1
  17. package/dist/esm/plugins/compat/index.mjs +1 -0
  18. package/dist/esm/plugins/render/render.mjs +4 -11
  19. package/dist/esm/plugins/render/ssrCache.mjs +63 -42
  20. package/dist/esm/serverBase.mjs +60 -19
  21. package/dist/esm/utils/error.mjs +0 -1
  22. package/dist/esm/utils/transformStream.mjs +1 -1
  23. package/dist/esm-node/adapters/node/hono.mjs +15 -5
  24. package/dist/esm-node/adapters/node/index.mjs +1 -0
  25. package/dist/esm-node/adapters/node/plugins/static.mjs +107 -32
  26. package/dist/esm-node/helper.mjs +1 -1
  27. package/dist/esm-node/index.mjs +1 -1
  28. package/dist/esm-node/plugins/compat/index.mjs +1 -0
  29. package/dist/esm-node/plugins/render/render.mjs +4 -11
  30. package/dist/esm-node/plugins/render/ssrCache.mjs +63 -42
  31. package/dist/esm-node/serverBase.mjs +60 -19
  32. package/dist/esm-node/utils/error.mjs +0 -1
  33. package/dist/esm-node/utils/transformStream.mjs +1 -1
  34. package/dist/types/adapters/node/index.d.ts +2 -0
  35. package/dist/types/adapters/node/plugins/static.d.ts +42 -4
  36. package/dist/types/index.d.ts +1 -2
  37. package/dist/types/serverBase.d.ts +6 -0
  38. package/dist/types/types/config/bff.d.ts +4 -15
  39. package/dist/types/types/config/server.d.ts +1 -3
  40. package/dist/types/types/plugins/plugin.d.ts +15 -1
  41. package/dist/types/types/requestHandler.d.ts +2 -3
  42. package/dist/types/utils/error.d.ts +0 -2
  43. package/package.json +9 -10
  44. package/dist/cjs/adapters/node/plugins/staticModuleFederation.js +0 -173
  45. package/dist/cjs/adapters/node/plugins/staticPrecompressed.js +0 -152
  46. package/dist/cjs/adapters/node/plugins/staticServing.js +0 -206
  47. package/dist/cjs/types/config/bffRuntime.js +0 -18
  48. package/dist/cjs/types/config/serverTelemetry.js +0 -18
  49. package/dist/esm/adapters/node/plugins/staticModuleFederation.mjs +0 -104
  50. package/dist/esm/adapters/node/plugins/staticPrecompressed.mjs +0 -111
  51. package/dist/esm/adapters/node/plugins/staticServing.mjs +0 -152
  52. package/dist/esm/rslib-runtime~1.mjs +0 -18
  53. package/dist/esm/types/config/bffRuntime.mjs +0 -0
  54. package/dist/esm/types/config/serverTelemetry.mjs +0 -0
  55. package/dist/esm-node/adapters/node/plugins/staticModuleFederation.mjs +0 -105
  56. package/dist/esm-node/adapters/node/plugins/staticPrecompressed.mjs +0 -112
  57. package/dist/esm-node/adapters/node/plugins/staticServing.mjs +0 -153
  58. package/dist/esm-node/rslib-runtime~0.mjs +0 -19
  59. package/dist/esm-node/types/config/bffRuntime.mjs +0 -1
  60. package/dist/esm-node/types/config/serverTelemetry.mjs +0 -1
  61. package/dist/types/adapters/node/plugins/staticModuleFederation.d.ts +0 -13
  62. package/dist/types/adapters/node/plugins/staticPrecompressed.d.ts +0 -13
  63. package/dist/types/adapters/node/plugins/staticServing.d.ts +0 -25
  64. package/dist/types/types/config/bffRuntime.d.ts +0 -116
  65. package/dist/types/types/config/serverTelemetry.d.ts +0 -319
@@ -32,6 +32,7 @@ __webpack_require__.d(__webpack_exports__, {
32
32
  createServerBase: ()=>createServerBase
33
33
  });
34
34
  const server_namespaceObject = require("@modern-js/plugin/server");
35
+ const utils_namespaceObject = require("@modern-js/utils");
35
36
  const external_hono_namespaceObject = require("hono");
36
37
  const external_context_js_namespaceObject = require("./context.js");
37
38
  const hooks_js_namespaceObject = require("./plugins/compat/hooks.js");
@@ -50,22 +51,54 @@ function _class_private_method_init(obj, privateSet) {
50
51
  var _applyMiddlewares = /*#__PURE__*/ new WeakSet();
51
52
  class ServerBase {
52
53
  async init() {
53
- const { serverConfig, config: cliConfig } = this.serverOptions;
54
- const mergedConfig = (0, index_js_namespaceObject.loadConfig)({
55
- cliConfig,
56
- serverConfig: serverConfig || {}
57
- });
58
- const { serverContext } = await server_namespaceObject.server.run({
59
- plugins: this.plugins,
60
- options: this.serverOptions,
61
- config: mergedConfig,
62
- handleSetupResult: hooks_js_namespaceObject.handleSetupResult
63
- });
64
- serverContext.serverBase = this;
65
- this.serverContext = serverContext;
66
- await serverContext.hooks.onPrepare.call();
67
- _class_private_method_get(this, _applyMiddlewares, applyMiddlewares).call(this);
68
- return this;
54
+ try {
55
+ const { serverConfig, config: cliConfig } = this.serverOptions;
56
+ const mergedConfig = (0, index_js_namespaceObject.loadConfig)({
57
+ cliConfig,
58
+ serverConfig: serverConfig || {}
59
+ });
60
+ const { serverContext } = await server_namespaceObject.server.run({
61
+ plugins: this.plugins,
62
+ options: this.serverOptions,
63
+ config: mergedConfig,
64
+ handleSetupResult: hooks_js_namespaceObject.handleSetupResult
65
+ });
66
+ serverContext.serverBase = this;
67
+ this.serverContext = serverContext;
68
+ await serverContext.hooks.onPrepare.call();
69
+ _class_private_method_get(this, _applyMiddlewares, applyMiddlewares).call(this);
70
+ return this;
71
+ } catch (error) {
72
+ await this.dispose().catch((disposeError)=>{
73
+ utils_namespaceObject.logger.error(disposeError);
74
+ });
75
+ throw error;
76
+ }
77
+ }
78
+ onDispose(disposer) {
79
+ if (this.disposePromise) throw new Error('Cannot register a disposer on a retired server.');
80
+ this.disposers.add(disposer);
81
+ return ()=>{
82
+ this.disposers.delete(disposer);
83
+ };
84
+ }
85
+ dispose() {
86
+ if (!this.disposePromise) {
87
+ const disposers = [
88
+ ...this.disposers
89
+ ].reverse();
90
+ this.disposers.clear();
91
+ this.disposePromise = Promise.resolve().then(async ()=>{
92
+ const errors = [];
93
+ for (const disposer of disposers)try {
94
+ await disposer();
95
+ } catch (error) {
96
+ errors.push(error);
97
+ }
98
+ if (errors.length > 0) throw new AggregateError(errors, 'Failed to dispose server.');
99
+ });
100
+ }
101
+ return this.disposePromise;
69
102
  }
70
103
  addPlugins(plugins) {
71
104
  this.plugins.push(...plugins);
@@ -111,7 +144,15 @@ class ServerBase {
111
144
  }
112
145
  constructor(options){
113
146
  _class_private_method_init(this, _applyMiddlewares);
114
- this.plugins = [];
147
+ this.plugins = [
148
+ {
149
+ name: '@modern-js/server-lifecycle',
150
+ _registryApi: ()=>({
151
+ onDispose: (disposer)=>this.onDispose(disposer)
152
+ })
153
+ }
154
+ ];
155
+ this.disposers = new Set();
115
156
  this.serverContext = null;
116
157
  this.serverOptions = options;
117
158
  this.app = new external_hono_namespaceObject.Hono();
@@ -138,7 +179,7 @@ function applyMiddlewares() {
138
179
  if (middleware.before) {
139
180
  const targetIndex = finalMiddlewares.findIndex((item)=>{
140
181
  if (middleware.before?.includes(item.name)) return true;
141
- return false;
182
+ else return false;
142
183
  });
143
184
  if (-1 !== targetIndex) finalMiddlewares.splice(targetIndex, 0, middleware);
144
185
  else finalMiddlewares.push(middleware);
@@ -159,7 +200,7 @@ function applyMiddlewares() {
159
200
  }
160
201
  function handler2Handlers(handler) {
161
202
  if (Array.isArray(handler)) return handler;
162
- return [
203
+ else return [
163
204
  handler
164
205
  ];
165
206
  }
@@ -30,12 +30,8 @@ __webpack_require__.r(__webpack_exports__);
30
30
  __webpack_require__.d(__webpack_exports__, {
31
31
  ErrorDigest: ()=>error_ErrorDigest,
32
32
  createErrorHtml: ()=>createErrorHtml,
33
- createSafeFailureHttpResult: ()=>safe_failure_namespaceObject.createSafeFailureHttpResult,
34
- createSafeJsonFailureResponse: ()=>safe_failure_namespaceObject.createSafeJsonFailureResponse,
35
- getSafeFailureStatus: ()=>safe_failure_namespaceObject.getSafeFailureStatus,
36
33
  onError: ()=>onError
37
34
  });
38
- const safe_failure_namespaceObject = require("@modern-js/runtime-extensions/safe-failure");
39
35
  const external_request_js_namespaceObject = require("./request.js");
40
36
  const ERROR_PAGE_TEXT = {
41
37
  404: 'This page could not be found.',
@@ -90,16 +86,10 @@ function onError(digest, error, monitors, req) {
90
86
  }
91
87
  exports.ErrorDigest = __webpack_exports__.ErrorDigest;
92
88
  exports.createErrorHtml = __webpack_exports__.createErrorHtml;
93
- exports.createSafeFailureHttpResult = __webpack_exports__.createSafeFailureHttpResult;
94
- exports.createSafeJsonFailureResponse = __webpack_exports__.createSafeJsonFailureResponse;
95
- exports.getSafeFailureStatus = __webpack_exports__.getSafeFailureStatus;
96
89
  exports.onError = __webpack_exports__.onError;
97
90
  for(var __rspack_i in __webpack_exports__)if (-1 === [
98
91
  "ErrorDigest",
99
92
  "createErrorHtml",
100
- "createSafeFailureHttpResult",
101
- "createSafeJsonFailureResponse",
102
- "getSafeFailureStatus",
103
93
  "onError"
104
94
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
105
95
  Object.defineProperty(exports, '__esModule', {
@@ -43,7 +43,7 @@ function transformResponse(response, transformCb) {
43
43
  if (response.body) {
44
44
  const stream = createTransformStream(async (before)=>{
45
45
  if (Array.isArray(transformCb)) return transformCb.reduce(async (before, cb)=>cb(await before), Promise.resolve(before));
46
- return transformCb(before);
46
+ else return transformCb(before);
47
47
  });
48
48
  response.body.pipeThrough(stream);
49
49
  readable = stream.readable;
@@ -30,12 +30,22 @@ const httpCallBack2HonoMid = (handler)=>async (context, next)=>{
30
30
  };
31
31
  const noop = ()=>{};
32
32
  const connectMid2HonoMid = (handler)=>async (context, next)=>new Promise((resolve, reject)=>{
33
- const { req, res } = context.env.node;
33
+ const { req, res: rawRes } = context.env.node;
34
+ const res = rawRes;
34
35
  if (handler.length < 3) resolve(handler(req, res, noop));
35
- else handler(req, res, (err)=>{
36
- if (err) reject(err);
37
- else resolve(next());
38
- });
36
+ else {
37
+ const onFinish = ()=>{
38
+ context.res;
39
+ context.finalized = true;
40
+ resolve();
41
+ };
42
+ res.once?.('finish', onFinish);
43
+ handler(req, res, (err)=>{
44
+ res.removeListener?.('finish', onFinish);
45
+ if (err) reject(err);
46
+ else resolve(next());
47
+ });
48
+ }
39
49
  });
40
50
  const connectMockMid2HonoMid = (handler)=>async (context, next)=>new Promise((resolve, reject)=>{
41
51
  const { req, res: rawRes } = context.env.node;
@@ -2,3 +2,4 @@ export { loadCacheConfig, loadServerCliConfig, loadServerEnv, loadServerPlugins,
2
2
  export { connectMid2HonoMid, connectMockMid2HonoMid, httpCallBack2HonoMid } from "./hono.mjs";
3
3
  export { createNodeServer, createWebRequest, sendResponse } from "./node.mjs";
4
4
  export { getHtmlTemplates, getServerManifest, injectNodeSeverPlugin, injectResourcePlugin, injectRscManifestPlugin, serverStaticPlugin } from "./plugins/index.mjs";
5
+ export { serveStaticAsset } from "./plugins/static.mjs";
@@ -1,8 +1,55 @@
1
- import path_0 from "path";
1
+ import { fileReader } from "@modern-js/runtime-utils/fileReader";
2
+ import { fs } from "@modern-js/utils";
3
+ import { getMimeType } from "hono/utils/mime";
4
+ import path from "path";
2
5
  import { sortRoutes } from "../../../utils/index.mjs";
3
6
  import { getPublicDirPatterns } from "../../../utils/publicDir.mjs";
4
- import { createModuleFederationStaticServing, servePreCompressedPublicRouteAsset, servePublicDirectoryAsset } from "./staticServing.mjs";
5
- const serverStaticPlugin = ()=>({
7
+ const isPathInside = (target, root)=>{
8
+ const relative = path.relative(path.resolve(root), path.resolve(target));
9
+ return '' === relative || !relative.startsWith(`..${path.sep}`) && '..' !== relative && !path.isAbsolute(relative);
10
+ };
11
+ async function serveStaticAsset(context, asset, respond) {
12
+ let { filename } = asset;
13
+ const { kind } = asset;
14
+ if (asset.root && !isPathInside(filename, asset.root)) return null;
15
+ if (asset.realpath) try {
16
+ const [realFilename, realRoot, stat] = await Promise.all([
17
+ fs.realpath(filename),
18
+ asset.root ? fs.realpath(asset.root) : Promise.resolve(void 0),
19
+ fs.stat(filename)
20
+ ]);
21
+ if (!stat.isFile() || realRoot && !isPathInside(realFilename, realRoot)) return null;
22
+ filename = realFilename;
23
+ asset = {
24
+ ...asset,
25
+ filename,
26
+ root: realRoot
27
+ };
28
+ } catch {
29
+ return null;
30
+ }
31
+ if ('static' === kind && !await fs.pathExists(filename)) return null;
32
+ if (respond) return respond(asset, (representation)=>serveStaticAsset(context, {
33
+ ...asset,
34
+ ...representation,
35
+ filename: representation?.filename ?? asset.filename,
36
+ mimeFilename: asset.mimeFilename ?? filename
37
+ }));
38
+ const mimeType = getMimeType(asset.mimeFilename ?? filename);
39
+ if ('static' === kind && mimeType) context.header('Content-Type', mimeType);
40
+ const size = 'static' === kind ? (await fs.lstat(filename)).size : void 0;
41
+ const data = 'static' === kind ? await fileReader.readFileFromSystem(filename, 'buffer') : await fileReader.readFile(filename, 'buffer');
42
+ if ('static' === kind && (asset.contentLength ?? true)) context.header('Content-Length', String(true === asset.contentLength && data ? data.byteLength : size));
43
+ if (null === data) return null;
44
+ if ('public' === kind && mimeType) context.header('Content-Type', mimeType);
45
+ Object.entries(asset.responseHeaders || {}).forEach(([key, value])=>{
46
+ context.header(key, value);
47
+ });
48
+ if ('public' === kind && asset.contentLength) context.header('Content-Length', String(data.byteLength));
49
+ const body = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
50
+ return context.body(body, 200);
51
+ }
52
+ const serverStaticPlugin = (options = {})=>({
6
53
  name: '@modern-js/plugin-server-static',
7
54
  setup (api) {
8
55
  api.onPrepare(()=>{
@@ -13,7 +60,9 @@ const serverStaticPlugin = ()=>({
13
60
  routes,
14
61
  output: config.output || {},
15
62
  html: config.html || {},
16
- server: config.server || {}
63
+ server: config.server || {},
64
+ ...api.getServerContext().staticAssetResponders,
65
+ ...options
17
66
  });
18
67
  middlewares.push({
19
68
  name: 'server-static',
@@ -22,16 +71,33 @@ const serverStaticPlugin = ()=>({
22
71
  });
23
72
  }
24
73
  });
25
- function createPublicMiddleware({ pwd, routes }) {
74
+ function createPublicMiddleware({ pwd, routes, pathPrefix = '/', respondAsset, respondPublicFallback }) {
26
75
  return async (c, next)=>{
27
- const route = matchPublicRoute(c.req, routes);
28
- if (route) {
29
- const response = await servePreCompressedPublicRouteAsset(c, pwd, route);
30
- if (null !== response) return response;
31
- }
32
- const generatedPublicAsset = await servePublicDirectoryAsset(c, pwd);
33
- if (null !== generatedPublicAsset) return generatedPublicAsset;
34
- return await next();
76
+ const respondPublic = async ()=>{
77
+ const route = matchPublicRoute(c.req, routes);
78
+ if (!route) return null;
79
+ const asset = {
80
+ filename: path.join(pwd, route.entryPath),
81
+ kind: 'public',
82
+ responseHeaders: route.responseHeaders
83
+ };
84
+ const serve = (representation)=>serveStaticAsset(c, {
85
+ ...asset,
86
+ ...representation,
87
+ filename: representation?.filename ?? asset.filename,
88
+ mimeFilename: asset.filename
89
+ });
90
+ const response = respondAsset ? await respondAsset(c, asset, serve, {
91
+ root: pwd,
92
+ pathPrefix
93
+ }) : void 0;
94
+ return void 0 === response ? serve() : response;
95
+ };
96
+ const response = respondPublicFallback ? await respondPublicFallback(c, respondPublic, {
97
+ root: pwd,
98
+ pathPrefix
99
+ }) : await respondPublic();
100
+ return response ?? next();
35
101
  };
36
102
  }
37
103
  function matchPublicRoute(req, routes) {
@@ -76,29 +142,38 @@ function createStaticMiddleware(options) {
76
142
  ...staticReg,
77
143
  ...iconReg
78
144
  ].join('|')})`);
79
- const publicMiddleware = createPublicMiddleware({
80
- pwd,
81
- routes: routes || []
82
- });
83
- const moduleFederationStaticServing = createModuleFederationStaticServing({
84
- pwd,
85
- pathPrefix
86
- });
87
145
  return async (c, next)=>{
88
146
  const pageRoute = c.get('route');
89
147
  const pathname = c.req.path;
90
- if (pageRoute && '' === path_0.extname(pathname)) return next();
148
+ if (pageRoute && '' === path.extname(pathname)) return next();
91
149
  const hit = staticPathRegExp.test(pathname);
92
- const staticServingRequest = await moduleFederationStaticServing.resolveRequest(pathname);
93
- if (null === staticServingRequest) return next();
94
- if (hit) {
95
- const response = await moduleFederationStaticServing.serveStaticHit(c, staticServingRequest);
96
- if (null !== response) return response;
97
- return next();
150
+ if (!hit) return createPublicMiddleware({
151
+ pwd,
152
+ routes: routes || [],
153
+ pathPrefix,
154
+ respondAsset: options.respondAsset,
155
+ respondPublicFallback: options.respondPublicFallback
156
+ })(c, next);
157
+ else {
158
+ const filepath = path.join(pwd, pathname.replace(pathPrefix, ()=>''));
159
+ if (!isPathInside(filepath, pwd)) return next();
160
+ if (!await fs.pathExists(filepath)) return next();
161
+ const asset = {
162
+ filename: filepath,
163
+ kind: 'static'
164
+ };
165
+ const serve = (representation)=>serveStaticAsset(c, {
166
+ ...asset,
167
+ ...representation,
168
+ filename: representation?.filename ?? asset.filename,
169
+ mimeFilename: filepath
170
+ });
171
+ const response = options.respondAsset ? await options.respondAsset(c, asset, serve, {
172
+ root: pwd,
173
+ pathPrefix
174
+ }) : void 0;
175
+ return (void 0 === response ? await serve() : response) ?? next();
98
176
  }
99
- const moduleFederationResponse = await moduleFederationStaticServing.serveModuleFederationAsset(c, staticServingRequest);
100
- if (null !== moduleFederationResponse) return moduleFederationResponse;
101
- return publicMiddleware(c, next);
102
177
  };
103
178
  }
104
179
  const prepareFavicons = (favicon)=>{
@@ -106,4 +181,4 @@ const prepareFavicons = (favicon)=>{
106
181
  if (favicon && 'string' == typeof favicon) faviconNames.push(favicon.substring(favicon.lastIndexOf('/') + 1));
107
182
  return faviconNames;
108
183
  };
109
- export { createPublicMiddleware, createStaticMiddleware, serverStaticPlugin };
184
+ export { createPublicMiddleware, createStaticMiddleware, serveStaticAsset, serverStaticPlugin };
@@ -2,7 +2,7 @@ const LOADER_CONTEXT = 'loaderContext';
2
2
  function getLoaderCtx(c) {
3
3
  const loaderContext = c.get(LOADER_CONTEXT);
4
4
  if (loaderContext) return loaderContext;
5
- {
5
+ else {
6
6
  const loaderContext = new Map();
7
7
  c.set(LOADER_CONTEXT, loaderContext);
8
8
  return loaderContext;
@@ -8,5 +8,5 @@ export { AGGRED_DIR } from "./constants.mjs";
8
8
  export { run, useHonoContext } from "./context.mjs";
9
9
  export { getLoaderCtx } from "./helper.mjs";
10
10
  export { createServerBase } from "./serverBase.mjs";
11
- export { ErrorDigest, createErrorHtml, createSafeFailureHttpResult, createSafeJsonFailureResponse, getSafeFailureStatus, onError } from "./utils/index.mjs";
11
+ export { ErrorDigest, createErrorHtml, onError } from "./utils/index.mjs";
12
12
  export { getPublicDirConfig, getPublicDirPatterns, getPublicDirRoutePrefixes, normalizePublicDir, normalizePublicDirPath, resolvePublicDirPaths } from "./utils/publicDir.mjs";
@@ -3,6 +3,7 @@ import { getHookRunners, handleSetupResult } from "./hooks.mjs";
3
3
  const compatPlugin = ()=>({
4
4
  name: '@modern-js/server-compat',
5
5
  registryHooks: {
6
+ handleError: createAsyncPipelineHook(),
6
7
  prepareWebServer: createAsyncPipelineHook(),
7
8
  prepareApiServer: createAsyncPipelineHook(),
8
9
  afterMatch: createAsyncPipelineHook(),
@@ -7,12 +7,6 @@ import { dataHandler } from "./dataHandler.mjs";
7
7
  import { renderRscHandler } from "./renderRscHandler.mjs";
8
8
  import { serverActionHandler } from "./serverActionHandler.mjs";
9
9
  import { ssrRender } from "./ssrRender.mjs";
10
- import { __webpack_require__ } from "../../rslib-runtime~1.mjs";
11
- __webpack_require__.add({
12
- 718 (module) {
13
- module.exports = require("@modern-js/runtime-utils/router");
14
- }
15
- });
16
10
  const DYNAMIC_ROUTE_REG = /\/:./;
17
11
  function getRouter(routes) {
18
12
  const dynamicRoutes = [];
@@ -45,8 +39,7 @@ function matchRoute(router, pathname, entryName) {
45
39
  void 0,
46
40
  {}
47
41
  ];
48
- }
49
- {
42
+ } else {
50
43
  const result = matchedRoutes[0];
51
44
  if (!result) return [
52
45
  void 0,
@@ -163,7 +156,7 @@ async function renderHandler(request, options, mode, fallbackWrapper, framework)
163
156
  const { nestedRoutesJson } = serverManifest;
164
157
  const routes = nestedRoutesJson?.[options.routeInfo.entryName];
165
158
  if (routes) {
166
- const { matchRoutes } = __webpack_require__(718);
159
+ const { matchRoutes } = require("@modern-js/runtime-utils/router");
167
160
  const url = new URL(request.url);
168
161
  const matchedRoutes = matchRoutes(routes, url.pathname, options.routeInfo.urlPath);
169
162
  if (matchedRoutes) {
@@ -201,7 +194,7 @@ async function getRenderMode(req, fallbackHeader, isSSR, forceCSR, nodeReq, onFa
201
194
  if (req.headers.get('x-rsc-action')) return 'rsc-action';
202
195
  if (req.headers.get('x-rsc-tree')) return 'rsc-tree';
203
196
  if (!isSSR) return 'csr';
204
- {
197
+ else {
205
198
  if (query.__loader) return 'data';
206
199
  const fallbackHeaderValue = req.headers.get(fallbackHeader) || nodeReq?.headers[fallbackHeader];
207
200
  if (forceCSR && (query.csr || fallbackHeaderValue || contextForceCSR)) {
@@ -230,6 +223,6 @@ async function csrRender(request, options) {
230
223
  [X_MODERNJS_RENDER]: 'client'
231
224
  })
232
225
  });
233
- return csrRscRender(request, options);
226
+ else return csrRscRender(request, options);
234
227
  }
235
228
  export { createRender, matchRoute };
@@ -1,54 +1,67 @@
1
1
  import { createMemoryStorage } from "@modern-js/runtime-utils/storer";
2
2
  import { X_RENDER_CACHE } from "../../constants.mjs";
3
3
  import { createTransformStream, getPathname } from "../../utils/index.mjs";
4
+ const preventsSharedCaching = (headers)=>/(?:^|,)\s*(?:private|no-store|no-cache)\s*(?:[=,]|$)/i.test(headers.get('cache-control') || '');
5
+ const isCacheableResponse = (response)=>200 === response.status && !preventsSharedCaching(response.headers) && !response.headers.has('set-cookie') && !response.headers.get('vary');
4
6
  const removeTailSlash = (s)=>s.replace(/\/+$/, '');
5
7
  const ZERO_RENDER_LEVEL = /"renderLevel":0/;
6
8
  const NO_SSR_CACHE = /<meta\s+[^>]*name=["']no-ssr-cache["'][^>]*>/i;
7
9
  async function processCache({ request, key, requestHandler, requestHandlerOptions, ttl, container, cacheStatus }) {
8
10
  const response = await requestHandler(request, requestHandlerOptions);
9
11
  const { onError } = requestHandlerOptions;
10
- const nonCacheableStatusCodes = [
11
- 204,
12
- 305,
13
- 404,
14
- 405,
15
- 500,
16
- 501,
17
- 502,
18
- 503,
19
- 504
20
- ];
21
- if (nonCacheableStatusCodes.includes(response.status)) return response;
12
+ const deleteCache = async ()=>{
13
+ try {
14
+ await container.delete(key);
15
+ } catch {
16
+ (onError || console.error)('[render-cache] delete cache failed');
17
+ }
18
+ };
19
+ if (!isCacheableResponse(response) || !response.body) {
20
+ await deleteCache();
21
+ return response;
22
+ }
23
+ const headers = Object.fromEntries(response.headers);
22
24
  const decoder = new TextDecoder();
23
25
  if (response.body) {
24
26
  const stream = createTransformStream();
25
27
  const reader = response.body.getReader();
26
28
  const writer = stream.writable.getWriter();
27
29
  let html = '';
28
- const push = ()=>reader.read().then(({ done, value })=>{
30
+ const push = ()=>reader.read().then(async ({ done, value })=>{
29
31
  if (done) {
32
+ html += decoder.decode();
30
33
  const match = ZERO_RENDER_LEVEL.test(html) || NO_SSR_CACHE.test(html);
31
- if (match) return void writer.close();
34
+ if (match) {
35
+ await deleteCache();
36
+ return writer.close();
37
+ }
32
38
  const current = Date.now();
33
39
  const cache = {
34
40
  val: html,
35
- cursor: current
41
+ cursor: current,
42
+ headers
36
43
  };
37
44
  container.set(key, JSON.stringify(cache), {
38
45
  ttl
39
46
  }).catch(()=>{
40
- if (onError) onError(`[render-cache] set cache failed, key: ${key}, value: ${JSON.stringify(cache)}`);
41
- else console.error(`[render-cache] set cache failed, key: ${key}, value: ${JSON.stringify(cache)}`);
47
+ (onError || console.error)('[render-cache] set cache failed');
42
48
  });
43
- writer.close();
44
- return;
49
+ return writer.close();
45
50
  }
46
- const content = decoder.decode(value);
51
+ const content = decoder.decode(value, {
52
+ stream: true
53
+ });
47
54
  html += content;
48
- writer.write(value);
49
- push();
55
+ await writer.write(value);
56
+ return push();
50
57
  });
51
- push();
58
+ push().catch(async (error)=>{
59
+ await Promise.allSettled([
60
+ writer.abort(error),
61
+ reader.cancel(error)
62
+ ]);
63
+ (onError || console.error)('[render-cache] response stream failed');
64
+ });
52
65
  cacheStatus && response.headers.set(X_RENDER_CACHE, cacheStatus);
53
66
  return new Response(stream.readable, {
54
67
  status: response.status,
@@ -63,9 +76,12 @@ function computedKey(req, cacheControl) {
63
76
  const pathname = getPathname(req);
64
77
  const { customKey } = cacheControl;
65
78
  const defaultKey = '/' === pathname ? pathname : removeTailSlash(pathname);
66
- if (!customKey) return defaultKey;
67
- if ('string' == typeof customKey) return customKey;
68
- return customKey(defaultKey);
79
+ if (customKey) if ('string' == typeof customKey) return customKey;
80
+ else return customKey(defaultKey);
81
+ else {
82
+ const url = new URL(req.url);
83
+ return `${url.origin}${defaultKey}${url.search}`;
84
+ }
69
85
  }
70
86
  function shouldUseCache(request) {
71
87
  const url = new URL(request.url);
@@ -76,7 +92,7 @@ function shouldUseCache(request) {
76
92
  }
77
93
  function matchCacheControl(cacheOption, req) {
78
94
  if (!cacheOption || !req) return;
79
- {
95
+ else {
80
96
  if (isCacheControl(cacheOption)) return cacheOption;
81
97
  if (isCacheOptionProvider(cacheOption)) return cacheOption(req);
82
98
  const url = req.url;
@@ -95,13 +111,15 @@ function matchCacheControl(cacheOption, req) {
95
111
  async function getCacheResult(request, options) {
96
112
  const { cacheControl, container = storage, requestHandler, requestHandlerOptions } = options;
97
113
  const { onError } = requestHandlerOptions;
98
- const key = computedKey(request, cacheControl);
114
+ const hasCredentials = request.headers.has('cookie') || request.headers.has('authorization');
115
+ if ('GET' !== request.method || !shouldUseCache(request) || preventsSharedCaching(request.headers) || hasCredentials && !cacheControl.customKey) return requestHandler(request, requestHandlerOptions);
116
+ const key = `${CACHE_NAMESPACE}:v2:${computedKey(request, cacheControl)}`;
99
117
  let value;
100
118
  try {
101
119
  value = await container.get(key);
102
120
  } catch (_) {
103
- if (onError) onError(`[render-cache] get cache failed, key: ${key}`);
104
- else console.error(`[render-cache] get cache failed, key: ${key}`);
121
+ if (onError) onError('[render-cache] get cache failed');
122
+ else console.error('[render-cache] get cache failed');
105
123
  value = void 0;
106
124
  }
107
125
  const { maxAge, staleWhileRevalidate } = cacheControl;
@@ -115,27 +133,27 @@ async function getCacheResult(request, options) {
115
133
  container,
116
134
  cacheStatus: 'miss'
117
135
  });
118
- {
136
+ else {
119
137
  const cache = JSON.parse(value);
120
138
  const interval = Date.now() - cache.cursor;
121
139
  if (interval <= maxAge) {
122
140
  const cacheStatus = 'hit';
123
141
  return new Response(cache.val, {
124
142
  headers: {
143
+ ...cache.headers,
125
144
  [X_RENDER_CACHE]: cacheStatus
126
145
  }
127
146
  });
128
- }
129
- if (!(interval <= staleWhileRevalidate + maxAge)) return processCache({
130
- key,
131
- request,
132
- requestHandler,
133
- requestHandlerOptions,
134
- ttl,
135
- container,
136
- cacheStatus: 'expired'
137
- });
138
- {
147
+ } else {
148
+ if (!(interval <= staleWhileRevalidate + maxAge)) return processCache({
149
+ key,
150
+ request,
151
+ requestHandler,
152
+ requestHandlerOptions,
153
+ ttl,
154
+ container,
155
+ cacheStatus: 'expired'
156
+ });
139
157
  processCache({
140
158
  key,
141
159
  request,
@@ -145,10 +163,13 @@ async function getCacheResult(request, options) {
145
163
  container
146
164
  }).then(async (response)=>{
147
165
  await response.text();
166
+ }).catch(()=>{
167
+ (onError || console.error)('[render-cache] revalidation failed');
148
168
  });
149
169
  const cacheStatus = 'stale';
150
170
  return new Response(cache.val, {
151
171
  headers: {
172
+ ...cache.headers,
152
173
  [X_RENDER_CACHE]: cacheStatus
153
174
  }
154
175
  });