@modern-js/server-core 2.67.1 → 2.67.3

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 (34) hide show
  1. package/dist/cjs/adapters/node/node.js +29 -5
  2. package/dist/cjs/adapters/node/plugins/resource.js +5 -0
  3. package/dist/cjs/adapters/node/plugins/static.js +6 -2
  4. package/dist/cjs/context.js +31 -0
  5. package/dist/cjs/index.js +7 -1
  6. package/dist/cjs/plugins/render/index.js +9 -6
  7. package/dist/cjs/plugins/render/render.js +28 -8
  8. package/dist/cjs/serverBase.js +2 -0
  9. package/dist/cjs/utils/storage.js +74 -0
  10. package/dist/esm/adapters/node/node.js +29 -5
  11. package/dist/esm/adapters/node/plugins/resource.js +7 -1
  12. package/dist/esm/adapters/node/plugins/static.js +10 -3
  13. package/dist/esm/context.js +6 -0
  14. package/dist/esm/index.js +5 -1
  15. package/dist/esm/plugins/render/index.js +9 -7
  16. package/dist/esm/plugins/render/render.js +30 -10
  17. package/dist/esm/serverBase.js +2 -0
  18. package/dist/esm/utils/storage.js +38 -0
  19. package/dist/esm-node/adapters/node/node.js +29 -5
  20. package/dist/esm-node/adapters/node/plugins/resource.js +5 -0
  21. package/dist/esm-node/adapters/node/plugins/static.js +6 -2
  22. package/dist/esm-node/context.js +6 -0
  23. package/dist/esm-node/index.js +5 -1
  24. package/dist/esm-node/plugins/render/index.js +9 -6
  25. package/dist/esm-node/plugins/render/render.js +28 -8
  26. package/dist/esm-node/serverBase.js +2 -0
  27. package/dist/esm-node/utils/storage.js +40 -0
  28. package/dist/types/context.d.ts +3 -0
  29. package/dist/types/index.d.ts +2 -0
  30. package/dist/types/types/config/server.d.ts +5 -0
  31. package/dist/types/types/plugins/base.d.ts +2 -1
  32. package/dist/types/types/plugins/index.d.ts +1 -1
  33. package/dist/types/utils/storage.d.ts +5 -0
  34. package/package.json +10 -8
@@ -35,6 +35,7 @@ __export(node_exports, {
35
35
  });
36
36
  module.exports = __toCommonJS(node_exports);
37
37
  var import_node_http = require("node:http");
38
+ var import_cloneable_readable = __toESM(require("cloneable-readable"));
38
39
  var import_helper = require("./helper");
39
40
  var import_install = require("./polyfills/install");
40
41
  var import_stream = require("./polyfills/stream");
@@ -61,13 +62,36 @@ const createWebRequest = (req, res, body) => {
61
62
  };
62
63
  res.on("close", () => controller.abort("res closed"));
63
64
  const url = `http://${req.headers.host}${req.url}`;
64
- const fullUrl = new URL(url);
65
- if (body || !(method === "GET" || method === "HEAD") && fullUrl.searchParams.has("__loader") || fullUrl.searchParams.has("__pass_body") || req.headers["x-mf-micro"] || req.headers["x-rsc-action"] || req.headers["x-parse-through-body"]) {
66
- init.body = body !== null && body !== void 0 ? body : (0, import_stream.createReadableStreamFromReadable)(req);
65
+ const needsRequestBody = body || !(method === "GET" || method === "HEAD");
66
+ const cloneableReq = needsRequestBody ? (0, import_cloneable_readable.default)(req) : null;
67
+ if (needsRequestBody) {
68
+ if (body) {
69
+ init.body = body;
70
+ } else {
71
+ const stream = cloneableReq.clone();
72
+ init.body = (0, import_stream.createReadableStreamFromReadable)(stream);
73
+ }
67
74
  init.duplex = "half";
68
75
  }
69
- const request = new Request(url, init);
70
- return request;
76
+ const originalRequest = new Request(url, init);
77
+ if (needsRequestBody) {
78
+ return new Proxy(originalRequest, {
79
+ get(target, prop) {
80
+ if ([
81
+ "json",
82
+ "text",
83
+ "blob",
84
+ "arrayBuffer",
85
+ "formData",
86
+ "body"
87
+ ].includes(prop)) {
88
+ cloneableReq.resume();
89
+ }
90
+ return target[prop];
91
+ }
92
+ });
93
+ }
94
+ return originalRequest;
71
95
  };
72
96
  const sendResponse = async (response, res) => {
73
97
  var _response_headers_get;
@@ -134,7 +134,12 @@ const injectRscManifestPlugin = () => ({
134
134
  setup(api) {
135
135
  return {
136
136
  async prepare() {
137
+ var _config_server;
137
138
  const { middlewares, distDirectory: pwd } = api.useAppContext();
139
+ const config = api.useConfigContext();
140
+ if (!((_config_server = config.server) === null || _config_server === void 0 ? void 0 : _config_server.rsc)) {
141
+ return;
142
+ }
138
143
  middlewares.push({
139
144
  name: "inject-rsc-manifest",
140
145
  handler: async (c, next) => {
@@ -61,7 +61,7 @@ const serverStaticPlugin = () => ({
61
61
  });
62
62
  function createPublicMiddleware({ pwd, routes }) {
63
63
  return async (c, next) => {
64
- const route = matchRoute(c.req, routes);
64
+ const route = matchPublicRoute(c.req, routes);
65
65
  if (route) {
66
66
  const { entryPath } = route;
67
67
  const filename = import_path.default.join(pwd, entryPath);
@@ -80,7 +80,7 @@ function createPublicMiddleware({ pwd, routes }) {
80
80
  return await next();
81
81
  };
82
82
  }
83
- function matchRoute(req, routes) {
83
+ function matchPublicRoute(req, routes) {
84
84
  for (const route of routes.sort(import_utils2.sortRoutes)) {
85
85
  if (!route.isSSR && route.entryPath.startsWith("public") && req.path.startsWith(route.urlPath)) {
86
86
  return route;
@@ -115,7 +115,11 @@ function createStaticMiddleware(options) {
115
115
  ...iconReg
116
116
  ].join("|")})`);
117
117
  return async (c, next) => {
118
+ const pageRoute = c.get("route");
118
119
  const pathname = c.req.path;
120
+ if (pageRoute && import_path.default.extname(pathname) === "") {
121
+ return next();
122
+ }
119
123
  const hit = staticPathRegExp.test(pathname);
120
124
  if (hit) {
121
125
  const filepath = import_path.default.join(pwd, pathname.replace(prefix, () => ""));
@@ -0,0 +1,31 @@
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 context_exports = {};
20
+ __export(context_exports, {
21
+ run: () => run,
22
+ useHonoContext: () => useHonoContext
23
+ });
24
+ module.exports = __toCommonJS(context_exports);
25
+ var import_storage = require("./utils/storage");
26
+ const { run, useHonoContext } = (0, import_storage.createStorage)();
27
+ // Annotate the CommonJS export names for ESM import in node:
28
+ 0 && (module.exports = {
29
+ run,
30
+ useHonoContext
31
+ });
package/dist/cjs/index.js CHANGED
@@ -21,15 +21,19 @@ var src_exports = {};
21
21
  __export(src_exports, {
22
22
  AGGRED_DIR: () => import_constants.AGGRED_DIR,
23
23
  ErrorDigest: () => import_utils.ErrorDigest,
24
+ Hono: () => import_hono.Hono,
24
25
  createErrorHtml: () => import_utils.createErrorHtml,
25
26
  createServerBase: () => import_serverBase.createServerBase,
26
27
  getLoaderCtx: () => import_helper.getLoaderCtx,
27
- onError: () => import_utils.onError
28
+ onError: () => import_utils.onError,
29
+ useHonoContext: () => import_context.useHonoContext
28
30
  });
29
31
  module.exports = __toCommonJS(src_exports);
30
32
  var import_utils = require("./utils");
31
33
  var import_constants = require("./constants");
32
34
  var import_serverBase = require("./serverBase");
35
+ var import_context = require("./context");
36
+ var import_hono = require("hono");
33
37
  var import_helper = require("./helper");
34
38
  __reExport(src_exports, require("./plugins"), module.exports);
35
39
  __reExport(src_exports, require("./types/plugins"), module.exports);
@@ -41,10 +45,12 @@ __reExport(src_exports, require("./types/requestHandler"), module.exports);
41
45
  0 && (module.exports = {
42
46
  AGGRED_DIR,
43
47
  ErrorDigest,
48
+ Hono,
44
49
  createErrorHtml,
45
50
  createServerBase,
46
51
  getLoaderCtx,
47
52
  onError,
53
+ useHonoContext,
48
54
  ...require("./plugins"),
49
55
  ...require("./types/plugins"),
50
56
  ...require("./types/render"),
@@ -48,14 +48,17 @@ const renderPlugin = () => ({
48
48
  handler: (0, import_monitors.requestLatencyMiddleware)()
49
49
  });
50
50
  for (const route of pageRoutes) {
51
+ var _config_server;
51
52
  const { urlPath: originUrlPath, entryName = import_constants.MAIN_ENTRY_NAME } = route;
52
53
  const urlPath = originUrlPath.endsWith("/") ? `${originUrlPath}*` : `${originUrlPath}/*`;
53
- const customServerHookMiddleware = customServer.getHookMiddleware(entryName, routes);
54
- middlewares.push({
55
- name: "custom-server-hook",
56
- path: urlPath,
57
- handler: customServerHookMiddleware
58
- });
54
+ if (((_config_server = config.server) === null || _config_server === void 0 ? void 0 : _config_server.disableHook) !== true) {
55
+ const customServerHookMiddleware = customServer.getHookMiddleware(entryName, routes);
56
+ middlewares.push({
57
+ name: "custom-server-hook",
58
+ path: urlPath,
59
+ handler: customServerHookMiddleware
60
+ });
61
+ }
59
62
  const customServerMiddleware = await customServer.getServerMiddleware(serverMiddleware);
60
63
  customServerMiddleware && middlewares.push({
61
64
  name: "custom-server-middleware",
@@ -87,8 +87,8 @@ async function createRender({ routes, pwd, metaName, staticGenerate, cacheConfig
87
87
  return async (req, { logger, reporter, metrics, monitors, nodeReq, templates, serverManifest, rscClientManifest, rscSSRManifest, rscServerManifest, locals, matchEntryName, matchPathname, loaderContext }) => {
88
88
  const forMatchpathname = matchPathname !== null && matchPathname !== void 0 ? matchPathname : (0, import_utils2.getPathname)(req);
89
89
  const [routeInfo, params] = matchRoute(router, forMatchpathname, matchEntryName);
90
- const framework = metaName || "modern-js";
91
- const fallbackHeader = `x-${(0, import_universal.cutNameByHyphen)(framework)}-ssr-fallback`;
90
+ const framework = (0, import_universal.cutNameByHyphen)(metaName || "modern-js");
91
+ const fallbackHeader = `x-${framework}-ssr-fallback`;
92
92
  let fallbackReason = null;
93
93
  const fallbackWrapper = async (reason, error) => {
94
94
  fallbackReason = reason;
@@ -146,10 +146,17 @@ async function createRender({ routes, pwd, metaName, staticGenerate, cacheConfig
146
146
  onError,
147
147
  onTiming
148
148
  };
149
+ if (fallbackReason) {
150
+ renderOptions.html = injectFallbackReasonToHtml({
151
+ html: renderOptions.html,
152
+ reason: fallbackReason,
153
+ framework
154
+ });
155
+ }
149
156
  let response;
150
157
  switch (renderMode) {
151
158
  case "data":
152
- response = await (0, import_dataHandler.dataHandler)(req, renderOptions) || await renderHandler(req, renderOptions, "ssr", fallbackWrapper);
159
+ response = await (0, import_dataHandler.dataHandler)(req, renderOptions) || await renderHandler(req, renderOptions, "ssr", fallbackWrapper, framework);
153
160
  break;
154
161
  case "rsc-tree":
155
162
  response = await (0, import_renderRscHandler.renderRscHandler)(req, renderOptions);
@@ -159,7 +166,7 @@ async function createRender({ routes, pwd, metaName, staticGenerate, cacheConfig
159
166
  break;
160
167
  case "ssr":
161
168
  case "csr":
162
- response = await renderHandler(req, renderOptions, renderMode, fallbackWrapper);
169
+ response = await renderHandler(req, renderOptions, renderMode, fallbackWrapper, framework);
163
170
  break;
164
171
  default:
165
172
  throw new Error(`Unknown render mode: ${renderMode}`);
@@ -170,7 +177,7 @@ async function createRender({ routes, pwd, metaName, staticGenerate, cacheConfig
170
177
  return response;
171
178
  };
172
179
  }
173
- async function renderHandler(request, options, mode, fallbackWrapper) {
180
+ async function renderHandler(request, options, mode, fallbackWrapper, framework) {
174
181
  var _options_config_server;
175
182
  let response = null;
176
183
  const { serverManifest } = options;
@@ -202,7 +209,11 @@ async function renderHandler(request, options, mode, fallbackWrapper) {
202
209
  } catch (e) {
203
210
  options.onError(e, import_utils2.ErrorDigest.ERENDER);
204
211
  await fallbackWrapper("error", e);
205
- response = csrRender(options.html);
212
+ response = csrRender(injectFallbackReasonToHtml({
213
+ html: options.html,
214
+ reason: "error",
215
+ framework
216
+ }));
206
217
  }
207
218
  } else {
208
219
  response = csrRender(options.html);
@@ -228,11 +239,14 @@ async function getRenderMode(req, fallbackHeader, isSSR, forceCSR, nodeReq, onFa
228
239
  if (query.__loader) {
229
240
  return "data";
230
241
  }
231
- if (forceCSR && (query.csr || req.headers.get(fallbackHeader) || (nodeReq === null || nodeReq === void 0 ? void 0 : nodeReq.headers[fallbackHeader]))) {
242
+ const fallbackHeaderValue = req.headers.get(fallbackHeader) || (nodeReq === null || nodeReq === void 0 ? void 0 : nodeReq.headers[fallbackHeader]);
243
+ if (forceCSR && (query.csr || fallbackHeaderValue)) {
232
244
  if (query.csr) {
233
245
  await (onFallback === null || onFallback === void 0 ? void 0 : onFallback("query"));
234
246
  } else {
235
- await (onFallback === null || onFallback === void 0 ? void 0 : onFallback("header"));
247
+ var _fallbackHeaderValue_split_;
248
+ const reason = fallbackHeaderValue === null || fallbackHeaderValue === void 0 ? void 0 : (_fallbackHeaderValue_split_ = fallbackHeaderValue.split(";")[1]) === null || _fallbackHeaderValue_split_ === void 0 ? void 0 : _fallbackHeaderValue_split_.split("=")[1];
249
+ await (onFallback === null || onFallback === void 0 ? void 0 : onFallback(reason ? `header,${reason}` : "header"));
236
250
  }
237
251
  return "csr";
238
252
  }
@@ -241,6 +255,12 @@ async function getRenderMode(req, fallbackHeader, isSSR, forceCSR, nodeReq, onFa
241
255
  return "csr";
242
256
  }
243
257
  }
258
+ function injectFallbackReasonToHtml({ html, reason, framework }) {
259
+ const tag = `<script id="__${framework}_ssr_fallback_reason__" type="application/json">${JSON.stringify({
260
+ reason
261
+ })}</script>`;
262
+ return html.replace(/<\/head>/, `${tag}</head>`);
263
+ }
244
264
  function csrRender(html) {
245
265
  return new Response(html, {
246
266
  status: 200,
@@ -26,6 +26,7 @@ var import_class_private_method_get = require("@swc/helpers/_/_class_private_met
26
26
  var import_class_private_method_init = require("@swc/helpers/_/_class_private_method_init");
27
27
  var import_server = require("@modern-js/plugin-v2/server");
28
28
  var import_hono = require("hono");
29
+ var import_context = require("./context");
29
30
  var import_hooks = require("./plugins/compat/hooks");
30
31
  var import_utils = require("./utils");
31
32
  var _applyMiddlewares = /* @__PURE__ */ new WeakSet();
@@ -99,6 +100,7 @@ class ServerBase {
99
100
  this.serverContext = null;
100
101
  this.options = options;
101
102
  this.app = new import_hono.Hono();
103
+ this.app.use("*", import_context.run);
102
104
  }
103
105
  }
104
106
  function applyMiddlewares() {
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var storage_exports = {};
30
+ __export(storage_exports, {
31
+ createStorage: () => createStorage
32
+ });
33
+ module.exports = __toCommonJS(storage_exports);
34
+ var ah = __toESM(require("async_hooks"));
35
+ const createStorage = () => {
36
+ let storage;
37
+ if (typeof ah.AsyncLocalStorage !== "undefined") {
38
+ storage = new ah.AsyncLocalStorage();
39
+ }
40
+ const run = (context, cb) => {
41
+ if (!storage) {
42
+ throw new Error(`Unable to use async_hook, please confirm the node version >= 12.17
43
+ `);
44
+ }
45
+ return new Promise((resolve, reject) => {
46
+ storage.run(context, () => {
47
+ try {
48
+ return resolve(cb());
49
+ } catch (error) {
50
+ return reject(error);
51
+ }
52
+ });
53
+ });
54
+ };
55
+ const useHonoContext = () => {
56
+ if (!storage) {
57
+ throw new Error(`Unable to use async_hook, please confirm the node version >= 12.17
58
+ `);
59
+ }
60
+ const context = storage.getStore();
61
+ if (!context) {
62
+ throw new Error(`Can't call useContext out of server scope`);
63
+ }
64
+ return context;
65
+ };
66
+ return {
67
+ run,
68
+ useHonoContext
69
+ };
70
+ };
71
+ // Annotate the CommonJS export names for ESM import in node:
72
+ 0 && (module.exports = {
73
+ createStorage
74
+ });
@@ -4,6 +4,7 @@ import { _ as _object_spread } from "@swc/helpers/_/_object_spread";
4
4
  import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array";
5
5
  import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
6
6
  import { ServerResponse } from "node:http";
7
+ import cloneable from "cloneable-readable";
7
8
  import { isResFinalized } from "./helper";
8
9
  import { installGlobals } from "./polyfills/install";
9
10
  import { createReadableStreamFromReadable, writeReadableStreamToWritable } from "./polyfills/stream";
@@ -32,13 +33,36 @@ var createWebRequest = function(req, res, body) {
32
33
  return controller.abort("res closed");
33
34
  });
34
35
  var url = "http://".concat(req.headers.host).concat(req.url);
35
- var fullUrl = new URL(url);
36
- if (body || !(method === "GET" || method === "HEAD") && fullUrl.searchParams.has("__loader") || fullUrl.searchParams.has("__pass_body") || req.headers["x-mf-micro"] || req.headers["x-rsc-action"] || req.headers["x-parse-through-body"]) {
37
- init.body = body !== null && body !== void 0 ? body : createReadableStreamFromReadable(req);
36
+ var needsRequestBody = body || !(method === "GET" || method === "HEAD");
37
+ var cloneableReq = needsRequestBody ? cloneable(req) : null;
38
+ if (needsRequestBody) {
39
+ if (body) {
40
+ init.body = body;
41
+ } else {
42
+ var stream = cloneableReq.clone();
43
+ init.body = createReadableStreamFromReadable(stream);
44
+ }
38
45
  init.duplex = "half";
39
46
  }
40
- var request = new Request(url, init);
41
- return request;
47
+ var originalRequest = new Request(url, init);
48
+ if (needsRequestBody) {
49
+ return new Proxy(originalRequest, {
50
+ get: function get(target, prop) {
51
+ if ([
52
+ "json",
53
+ "text",
54
+ "blob",
55
+ "arrayBuffer",
56
+ "formData",
57
+ "body"
58
+ ].includes(prop)) {
59
+ cloneableReq.resume();
60
+ }
61
+ return target[prop];
62
+ }
63
+ });
64
+ }
65
+ return originalRequest;
42
66
  };
43
67
  var sendResponse = function() {
44
68
  var _ref = _async_to_generator(function(response, res) {
@@ -409,9 +409,15 @@ var injectRscManifestPlugin = function() {
409
409
  return {
410
410
  prepare: function prepare() {
411
411
  return _async_to_generator(function() {
412
- var _api_useAppContext, middlewares, pwd;
412
+ var _config_server, _api_useAppContext, middlewares, pwd, config;
413
413
  return _ts_generator(this, function(_state) {
414
414
  _api_useAppContext = api.useAppContext(), middlewares = _api_useAppContext.middlewares, pwd = _api_useAppContext.distDirectory;
415
+ config = api.useConfigContext();
416
+ if (!((_config_server = config.server) === null || _config_server === void 0 ? void 0 : _config_server.rsc)) {
417
+ return [
418
+ 2
419
+ ];
420
+ }
415
421
  middlewares.push({
416
422
  name: "inject-rsc-manifest",
417
423
  handler: function() {
@@ -38,7 +38,7 @@ function createPublicMiddleware(param) {
38
38
  return _ts_generator(this, function(_state) {
39
39
  switch (_state.label) {
40
40
  case 0:
41
- route = matchRoute(c.req, routes);
41
+ route = matchPublicRoute(c.req, routes);
42
42
  if (!route)
43
43
  return [
44
44
  3,
@@ -85,7 +85,7 @@ function createPublicMiddleware(param) {
85
85
  };
86
86
  }();
87
87
  }
88
- function matchRoute(req, routes) {
88
+ function matchPublicRoute(req, routes) {
89
89
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
90
90
  try {
91
91
  for (var _iterator = routes.sort(sortRoutes)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
@@ -135,11 +135,18 @@ function createStaticMiddleware(options) {
135
135
  var staticPathRegExp = new RegExp("^".concat(regPrefix, "(").concat(_to_consumable_array(staticReg).concat(_to_consumable_array(iconReg)).join("|"), ")"));
136
136
  return function() {
137
137
  var _ref2 = _async_to_generator(function(c, next) {
138
- var pathname, hit, filepath, mimeType, stat, size, chunk;
138
+ var pageRoute, pathname, hit, filepath, mimeType, stat, size, chunk;
139
139
  return _ts_generator(this, function(_state) {
140
140
  switch (_state.label) {
141
141
  case 0:
142
+ pageRoute = c.get("route");
142
143
  pathname = c.req.path;
144
+ if (pageRoute && path.extname(pathname) === "") {
145
+ return [
146
+ 2,
147
+ next()
148
+ ];
149
+ }
143
150
  hit = staticPathRegExp.test(pathname);
144
151
  if (!hit)
145
152
  return [
@@ -0,0 +1,6 @@
1
+ import { createStorage } from "./utils/storage";
2
+ var _createStorage = createStorage(), run = _createStorage.run, useHonoContext = _createStorage.useHonoContext;
3
+ export {
4
+ run,
5
+ useHonoContext
6
+ };
package/dist/esm/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { createErrorHtml, onError, ErrorDigest } from "./utils";
2
2
  import { AGGRED_DIR } from "./constants";
3
3
  import { createServerBase } from "./serverBase";
4
+ import { useHonoContext } from "./context";
5
+ import { Hono } from "hono";
4
6
  import { getLoaderCtx } from "./helper";
5
7
  export * from "./plugins";
6
8
  export * from "./types/plugins";
@@ -11,8 +13,10 @@ export * from "./types/requestHandler";
11
13
  export {
12
14
  AGGRED_DIR,
13
15
  ErrorDigest,
16
+ Hono,
14
17
  createErrorHtml,
15
18
  createServerBase,
16
19
  getLoaderCtx,
17
- onError
20
+ onError,
21
+ useHonoContext
18
22
  };
@@ -13,7 +13,7 @@ var renderPlugin = function() {
13
13
  return {
14
14
  prepare: function prepare() {
15
15
  return _async_to_generator(function() {
16
- var _config_render, _api_useAppContext, middlewares, routes, render, pwd, serverBase, hooks, config, customServer, serverMiddleware, pageRoutes, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, route, originUrlPath, _route_entryName, entryName, urlPath, customServerHookMiddleware, customServerMiddleware, err;
16
+ var _config_render, _api_useAppContext, middlewares, routes, render, pwd, serverBase, hooks, config, customServer, serverMiddleware, pageRoutes, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, route, _config_server, originUrlPath, _route_entryName, entryName, urlPath, customServerHookMiddleware, customServerMiddleware, err;
17
17
  return _ts_generator(this, function(_state) {
18
18
  switch (_state.label) {
19
19
  case 0:
@@ -52,12 +52,14 @@ var renderPlugin = function() {
52
52
  route = _step.value;
53
53
  originUrlPath = route.urlPath, _route_entryName = route.entryName, entryName = _route_entryName === void 0 ? MAIN_ENTRY_NAME : _route_entryName;
54
54
  urlPath = originUrlPath.endsWith("/") ? "".concat(originUrlPath, "*") : "".concat(originUrlPath, "/*");
55
- customServerHookMiddleware = customServer.getHookMiddleware(entryName, routes);
56
- middlewares.push({
57
- name: "custom-server-hook",
58
- path: urlPath,
59
- handler: customServerHookMiddleware
60
- });
55
+ if (((_config_server = config.server) === null || _config_server === void 0 ? void 0 : _config_server.disableHook) !== true) {
56
+ customServerHookMiddleware = customServer.getHookMiddleware(entryName, routes);
57
+ middlewares.push({
58
+ name: "custom-server-hook",
59
+ path: urlPath,
60
+ handler: customServerHookMiddleware
61
+ });
62
+ }
61
63
  return [
62
64
  4,
63
65
  customServer.getServerMiddleware(serverMiddleware)
@@ -93,8 +93,8 @@ function _createRender() {
93
93
  logger = param2.logger, reporter = param2.reporter, metrics = param2.metrics, monitors = param2.monitors, nodeReq = param2.nodeReq, templates = param2.templates, serverManifest = param2.serverManifest, rscClientManifest = param2.rscClientManifest, rscSSRManifest = param2.rscSSRManifest, rscServerManifest = param2.rscServerManifest, locals = param2.locals, matchEntryName = param2.matchEntryName, matchPathname = param2.matchPathname, loaderContext = param2.loaderContext;
94
94
  forMatchpathname = matchPathname !== null && matchPathname !== void 0 ? matchPathname : getPathname(req);
95
95
  _matchRoute = _sliced_to_array(matchRoute(router, forMatchpathname, matchEntryName), 2), routeInfo = _matchRoute[0], params = _matchRoute[1];
96
- framework = metaName || "modern-js";
97
- fallbackHeader = "x-".concat(cutNameByHyphen(framework), "-ssr-fallback");
96
+ framework = cutNameByHyphen(metaName || "modern-js");
97
+ fallbackHeader = "x-".concat(framework, "-ssr-fallback");
98
98
  fallbackReason = null;
99
99
  fallbackWrapper = function() {
100
100
  var _ref2 = _async_to_generator(function(reason, error) {
@@ -173,6 +173,13 @@ function _createRender() {
173
173
  onError,
174
174
  onTiming
175
175
  };
176
+ if (fallbackReason) {
177
+ renderOptions.html = injectFallbackReasonToHtml({
178
+ html: renderOptions.html,
179
+ reason: fallbackReason,
180
+ framework
181
+ });
182
+ }
176
183
  switch (renderMode) {
177
184
  case "data":
178
185
  return [
@@ -218,7 +225,7 @@ function _createRender() {
218
225
  ];
219
226
  return [
220
227
  4,
221
- renderHandler(req, renderOptions, "ssr", fallbackWrapper)
228
+ renderHandler(req, renderOptions, "ssr", fallbackWrapper, framework)
222
229
  ];
223
230
  case 4:
224
231
  _tmp = _state2.sent();
@@ -254,7 +261,7 @@ function _createRender() {
254
261
  case 10:
255
262
  return [
256
263
  4,
257
- renderHandler(req, renderOptions, renderMode, fallbackWrapper)
264
+ renderHandler(req, renderOptions, renderMode, fallbackWrapper, framework)
258
265
  ];
259
266
  case 11:
260
267
  response = _state2.sent();
@@ -284,11 +291,11 @@ function _createRender() {
284
291
  });
285
292
  return _createRender.apply(this, arguments);
286
293
  }
287
- function renderHandler(request, options, mode, fallbackWrapper) {
294
+ function renderHandler(request, options, mode, fallbackWrapper, framework) {
288
295
  return _renderHandler.apply(this, arguments);
289
296
  }
290
297
  function _renderHandler() {
291
- _renderHandler = _async_to_generator(function(request, options, mode, fallbackWrapper) {
298
+ _renderHandler = _async_to_generator(function(request, options, mode, fallbackWrapper, framework) {
292
299
  var _options_config_server, response, serverManifest, ssrByRouteIds, runtimeEnv, nestedRoutesJson, routes, urlPath, pathToFileURL, matchRoutes, url, matchedRoutes, _lastMatch_route, lastMatch, e, routeInfo;
293
300
  function applyExtendHeaders(r, route) {
294
301
  Object.entries(route.responseHeaders || {}).forEach(function(param) {
@@ -373,7 +380,11 @@ function _renderHandler() {
373
380
  ];
374
381
  case 7:
375
382
  _state.sent();
376
- response = csrRender(options.html);
383
+ response = csrRender(injectFallbackReasonToHtml({
384
+ html: options.html,
385
+ reason: "error",
386
+ framework
387
+ }));
377
388
  return [
378
389
  3,
379
390
  8
@@ -403,7 +414,7 @@ function getRenderMode(req, fallbackHeader, isSSR, forceCSR, nodeReq, onFallback
403
414
  }
404
415
  function _getRenderMode() {
405
416
  _getRenderMode = _async_to_generator(function(req, fallbackHeader, isSSR, forceCSR, nodeReq, onFallback) {
406
- var query;
417
+ var query, fallbackHeaderValue, _fallbackHeaderValue_split_, reason;
407
418
  return _ts_generator(this, function(_state) {
408
419
  switch (_state.label) {
409
420
  case 0:
@@ -431,7 +442,8 @@ function _getRenderMode() {
431
442
  "data"
432
443
  ];
433
444
  }
434
- if (!(forceCSR && (query.csr || req.headers.get(fallbackHeader) || (nodeReq === null || nodeReq === void 0 ? void 0 : nodeReq.headers[fallbackHeader]))))
445
+ fallbackHeaderValue = req.headers.get(fallbackHeader) || (nodeReq === null || nodeReq === void 0 ? void 0 : nodeReq.headers[fallbackHeader]);
446
+ if (!(forceCSR && (query.csr || fallbackHeaderValue)))
435
447
  return [
436
448
  3,
437
449
  5
@@ -452,9 +464,10 @@ function _getRenderMode() {
452
464
  4
453
465
  ];
454
466
  case 2:
467
+ reason = fallbackHeaderValue === null || fallbackHeaderValue === void 0 ? void 0 : (_fallbackHeaderValue_split_ = fallbackHeaderValue.split(";")[1]) === null || _fallbackHeaderValue_split_ === void 0 ? void 0 : _fallbackHeaderValue_split_.split("=")[1];
455
468
  return [
456
469
  4,
457
- onFallback === null || onFallback === void 0 ? void 0 : onFallback("header")
470
+ onFallback === null || onFallback === void 0 ? void 0 : onFallback(reason ? "header,".concat(reason) : "header")
458
471
  ];
459
472
  case 3:
460
473
  _state.sent();
@@ -483,6 +496,13 @@ function _getRenderMode() {
483
496
  });
484
497
  return _getRenderMode.apply(this, arguments);
485
498
  }
499
+ function injectFallbackReasonToHtml(param) {
500
+ var html = param.html, reason = param.reason, framework = param.framework;
501
+ var tag = '<script id="__'.concat(framework, '_ssr_fallback_reason__" type="application/json">').concat(JSON.stringify({
502
+ reason
503
+ }), "</script>");
504
+ return html.replace(/<\/head>/, "".concat(tag, "</head>"));
505
+ }
486
506
  function csrRender(html) {
487
507
  return new Response(html, {
488
508
  status: 200,
@@ -7,6 +7,7 @@ import { _ as _to_consumable_array } from "@swc/helpers/_/_to_consumable_array";
7
7
  import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
8
8
  import { server } from "@modern-js/plugin-v2/server";
9
9
  import { Hono } from "hono";
10
+ import { run } from "./context";
10
11
  import { handleSetupResult } from "./plugins/compat/hooks";
11
12
  import { loadConfig } from "./utils";
12
13
  var _applyMiddlewares = /* @__PURE__ */ new WeakSet();
@@ -19,6 +20,7 @@ var ServerBase = /* @__PURE__ */ function() {
19
20
  this.serverContext = null;
20
21
  this.options = options;
21
22
  this.app = new Hono();
23
+ this.app.use("*", run);
22
24
  }
23
25
  var _proto = ServerBase2.prototype;
24
26
  _proto.init = function init() {
@@ -0,0 +1,38 @@
1
+ import * as ah from "async_hooks";
2
+ var createStorage = function() {
3
+ var storage;
4
+ if (typeof ah.AsyncLocalStorage !== "undefined") {
5
+ storage = new ah.AsyncLocalStorage();
6
+ }
7
+ var run = function(context, cb) {
8
+ if (!storage) {
9
+ throw new Error("Unable to use async_hook, please confirm the node version >= 12.17\n ");
10
+ }
11
+ return new Promise(function(resolve, reject) {
12
+ storage.run(context, function() {
13
+ try {
14
+ return resolve(cb());
15
+ } catch (error) {
16
+ return reject(error);
17
+ }
18
+ });
19
+ });
20
+ };
21
+ var useHonoContext = function() {
22
+ if (!storage) {
23
+ throw new Error("Unable to use async_hook, please confirm the node version >= 12.17\n ");
24
+ }
25
+ var context = storage.getStore();
26
+ if (!context) {
27
+ throw new Error("Can't call useContext out of server scope");
28
+ }
29
+ return context;
30
+ };
31
+ return {
32
+ run,
33
+ useHonoContext
34
+ };
35
+ };
36
+ export {
37
+ createStorage
38
+ };
@@ -1,4 +1,5 @@
1
1
  import { ServerResponse } from "node:http";
2
+ import cloneable from "cloneable-readable";
2
3
  import { isResFinalized } from "./helper";
3
4
  import { installGlobals } from "./polyfills/install";
4
5
  import { createReadableStreamFromReadable, writeReadableStreamToWritable } from "./polyfills/stream";
@@ -25,13 +26,36 @@ const createWebRequest = (req, res, body) => {
25
26
  };
26
27
  res.on("close", () => controller.abort("res closed"));
27
28
  const url = `http://${req.headers.host}${req.url}`;
28
- const fullUrl = new URL(url);
29
- if (body || !(method === "GET" || method === "HEAD") && fullUrl.searchParams.has("__loader") || fullUrl.searchParams.has("__pass_body") || req.headers["x-mf-micro"] || req.headers["x-rsc-action"] || req.headers["x-parse-through-body"]) {
30
- init.body = body !== null && body !== void 0 ? body : createReadableStreamFromReadable(req);
29
+ const needsRequestBody = body || !(method === "GET" || method === "HEAD");
30
+ const cloneableReq = needsRequestBody ? cloneable(req) : null;
31
+ if (needsRequestBody) {
32
+ if (body) {
33
+ init.body = body;
34
+ } else {
35
+ const stream = cloneableReq.clone();
36
+ init.body = createReadableStreamFromReadable(stream);
37
+ }
31
38
  init.duplex = "half";
32
39
  }
33
- const request = new Request(url, init);
34
- return request;
40
+ const originalRequest = new Request(url, init);
41
+ if (needsRequestBody) {
42
+ return new Proxy(originalRequest, {
43
+ get(target, prop) {
44
+ if ([
45
+ "json",
46
+ "text",
47
+ "blob",
48
+ "arrayBuffer",
49
+ "formData",
50
+ "body"
51
+ ].includes(prop)) {
52
+ cloneableReq.resume();
53
+ }
54
+ return target[prop];
55
+ }
56
+ });
57
+ }
58
+ return originalRequest;
35
59
  };
36
60
  const sendResponse = async (response, res) => {
37
61
  var _response_headers_get;
@@ -93,7 +93,12 @@ const injectRscManifestPlugin = () => ({
93
93
  setup(api) {
94
94
  return {
95
95
  async prepare() {
96
+ var _config_server;
96
97
  const { middlewares, distDirectory: pwd } = api.useAppContext();
98
+ const config = api.useConfigContext();
99
+ if (!((_config_server = config.server) === null || _config_server === void 0 ? void 0 : _config_server.rsc)) {
100
+ return;
101
+ }
97
102
  middlewares.push({
98
103
  name: "inject-rsc-manifest",
99
104
  handler: async (c, next) => {
@@ -26,7 +26,7 @@ const serverStaticPlugin = () => ({
26
26
  });
27
27
  function createPublicMiddleware({ pwd, routes }) {
28
28
  return async (c, next) => {
29
- const route = matchRoute(c.req, routes);
29
+ const route = matchPublicRoute(c.req, routes);
30
30
  if (route) {
31
31
  const { entryPath } = route;
32
32
  const filename = path.join(pwd, entryPath);
@@ -45,7 +45,7 @@ function createPublicMiddleware({ pwd, routes }) {
45
45
  return await next();
46
46
  };
47
47
  }
48
- function matchRoute(req, routes) {
48
+ function matchPublicRoute(req, routes) {
49
49
  for (const route of routes.sort(sortRoutes)) {
50
50
  if (!route.isSSR && route.entryPath.startsWith("public") && req.path.startsWith(route.urlPath)) {
51
51
  return route;
@@ -80,7 +80,11 @@ function createStaticMiddleware(options) {
80
80
  ...iconReg
81
81
  ].join("|")})`);
82
82
  return async (c, next) => {
83
+ const pageRoute = c.get("route");
83
84
  const pathname = c.req.path;
85
+ if (pageRoute && path.extname(pathname) === "") {
86
+ return next();
87
+ }
84
88
  const hit = staticPathRegExp.test(pathname);
85
89
  if (hit) {
86
90
  const filepath = path.join(pwd, pathname.replace(prefix, () => ""));
@@ -0,0 +1,6 @@
1
+ import { createStorage } from "./utils/storage";
2
+ const { run, useHonoContext } = createStorage();
3
+ export {
4
+ run,
5
+ useHonoContext
6
+ };
@@ -1,6 +1,8 @@
1
1
  import { createErrorHtml, onError, ErrorDigest } from "./utils";
2
2
  import { AGGRED_DIR } from "./constants";
3
3
  import { createServerBase } from "./serverBase";
4
+ import { useHonoContext } from "./context";
5
+ import { Hono } from "hono";
4
6
  import { getLoaderCtx } from "./helper";
5
7
  export * from "./plugins";
6
8
  export * from "./types/plugins";
@@ -11,8 +13,10 @@ export * from "./types/requestHandler";
11
13
  export {
12
14
  AGGRED_DIR,
13
15
  ErrorDigest,
16
+ Hono,
14
17
  createErrorHtml,
15
18
  createServerBase,
16
19
  getLoaderCtx,
17
- onError
20
+ onError,
21
+ useHonoContext
18
22
  };
@@ -24,14 +24,17 @@ const renderPlugin = () => ({
24
24
  handler: requestLatencyMiddleware()
25
25
  });
26
26
  for (const route of pageRoutes) {
27
+ var _config_server;
27
28
  const { urlPath: originUrlPath, entryName = MAIN_ENTRY_NAME } = route;
28
29
  const urlPath = originUrlPath.endsWith("/") ? `${originUrlPath}*` : `${originUrlPath}/*`;
29
- const customServerHookMiddleware = customServer.getHookMiddleware(entryName, routes);
30
- middlewares.push({
31
- name: "custom-server-hook",
32
- path: urlPath,
33
- handler: customServerHookMiddleware
34
- });
30
+ if (((_config_server = config.server) === null || _config_server === void 0 ? void 0 : _config_server.disableHook) !== true) {
31
+ const customServerHookMiddleware = customServer.getHookMiddleware(entryName, routes);
32
+ middlewares.push({
33
+ name: "custom-server-hook",
34
+ path: urlPath,
35
+ handler: customServerHookMiddleware
36
+ });
37
+ }
35
38
  const customServerMiddleware = await customServer.getServerMiddleware(serverMiddleware);
36
39
  customServerMiddleware && middlewares.push({
37
40
  name: "custom-server-middleware",
@@ -54,8 +54,8 @@ async function createRender({ routes, pwd, metaName, staticGenerate, cacheConfig
54
54
  return async (req, { logger, reporter, metrics, monitors, nodeReq, templates, serverManifest, rscClientManifest, rscSSRManifest, rscServerManifest, locals, matchEntryName, matchPathname, loaderContext }) => {
55
55
  const forMatchpathname = matchPathname !== null && matchPathname !== void 0 ? matchPathname : getPathname(req);
56
56
  const [routeInfo, params] = matchRoute(router, forMatchpathname, matchEntryName);
57
- const framework = metaName || "modern-js";
58
- const fallbackHeader = `x-${cutNameByHyphen(framework)}-ssr-fallback`;
57
+ const framework = cutNameByHyphen(metaName || "modern-js");
58
+ const fallbackHeader = `x-${framework}-ssr-fallback`;
59
59
  let fallbackReason = null;
60
60
  const fallbackWrapper = async (reason, error) => {
61
61
  fallbackReason = reason;
@@ -113,10 +113,17 @@ async function createRender({ routes, pwd, metaName, staticGenerate, cacheConfig
113
113
  onError,
114
114
  onTiming
115
115
  };
116
+ if (fallbackReason) {
117
+ renderOptions.html = injectFallbackReasonToHtml({
118
+ html: renderOptions.html,
119
+ reason: fallbackReason,
120
+ framework
121
+ });
122
+ }
116
123
  let response;
117
124
  switch (renderMode) {
118
125
  case "data":
119
- response = await dataHandler(req, renderOptions) || await renderHandler(req, renderOptions, "ssr", fallbackWrapper);
126
+ response = await dataHandler(req, renderOptions) || await renderHandler(req, renderOptions, "ssr", fallbackWrapper, framework);
120
127
  break;
121
128
  case "rsc-tree":
122
129
  response = await renderRscHandler(req, renderOptions);
@@ -126,7 +133,7 @@ async function createRender({ routes, pwd, metaName, staticGenerate, cacheConfig
126
133
  break;
127
134
  case "ssr":
128
135
  case "csr":
129
- response = await renderHandler(req, renderOptions, renderMode, fallbackWrapper);
136
+ response = await renderHandler(req, renderOptions, renderMode, fallbackWrapper, framework);
130
137
  break;
131
138
  default:
132
139
  throw new Error(`Unknown render mode: ${renderMode}`);
@@ -137,7 +144,7 @@ async function createRender({ routes, pwd, metaName, staticGenerate, cacheConfig
137
144
  return response;
138
145
  };
139
146
  }
140
- async function renderHandler(request, options, mode, fallbackWrapper) {
147
+ async function renderHandler(request, options, mode, fallbackWrapper, framework) {
141
148
  var _options_config_server;
142
149
  let response = null;
143
150
  const { serverManifest } = options;
@@ -169,7 +176,11 @@ async function renderHandler(request, options, mode, fallbackWrapper) {
169
176
  } catch (e) {
170
177
  options.onError(e, ErrorDigest.ERENDER);
171
178
  await fallbackWrapper("error", e);
172
- response = csrRender(options.html);
179
+ response = csrRender(injectFallbackReasonToHtml({
180
+ html: options.html,
181
+ reason: "error",
182
+ framework
183
+ }));
173
184
  }
174
185
  } else {
175
186
  response = csrRender(options.html);
@@ -195,11 +206,14 @@ async function getRenderMode(req, fallbackHeader, isSSR, forceCSR, nodeReq, onFa
195
206
  if (query.__loader) {
196
207
  return "data";
197
208
  }
198
- if (forceCSR && (query.csr || req.headers.get(fallbackHeader) || (nodeReq === null || nodeReq === void 0 ? void 0 : nodeReq.headers[fallbackHeader]))) {
209
+ const fallbackHeaderValue = req.headers.get(fallbackHeader) || (nodeReq === null || nodeReq === void 0 ? void 0 : nodeReq.headers[fallbackHeader]);
210
+ if (forceCSR && (query.csr || fallbackHeaderValue)) {
199
211
  if (query.csr) {
200
212
  await (onFallback === null || onFallback === void 0 ? void 0 : onFallback("query"));
201
213
  } else {
202
- await (onFallback === null || onFallback === void 0 ? void 0 : onFallback("header"));
214
+ var _fallbackHeaderValue_split_;
215
+ const reason = fallbackHeaderValue === null || fallbackHeaderValue === void 0 ? void 0 : (_fallbackHeaderValue_split_ = fallbackHeaderValue.split(";")[1]) === null || _fallbackHeaderValue_split_ === void 0 ? void 0 : _fallbackHeaderValue_split_.split("=")[1];
216
+ await (onFallback === null || onFallback === void 0 ? void 0 : onFallback(reason ? `header,${reason}` : "header"));
203
217
  }
204
218
  return "csr";
205
219
  }
@@ -208,6 +222,12 @@ async function getRenderMode(req, fallbackHeader, isSSR, forceCSR, nodeReq, onFa
208
222
  return "csr";
209
223
  }
210
224
  }
225
+ function injectFallbackReasonToHtml({ html, reason, framework }) {
226
+ const tag = `<script id="__${framework}_ssr_fallback_reason__" type="application/json">${JSON.stringify({
227
+ reason
228
+ })}</script>`;
229
+ return html.replace(/<\/head>/, `${tag}</head>`);
230
+ }
211
231
  function csrRender(html) {
212
232
  return new Response(html, {
213
233
  status: 200,
@@ -2,6 +2,7 @@ import { _ as _class_private_method_get } from "@swc/helpers/_/_class_private_me
2
2
  import { _ as _class_private_method_init } from "@swc/helpers/_/_class_private_method_init";
3
3
  import { server } from "@modern-js/plugin-v2/server";
4
4
  import { Hono } from "hono";
5
+ import { run } from "./context";
5
6
  import { handleSetupResult } from "./plugins/compat/hooks";
6
7
  import { loadConfig } from "./utils";
7
8
  var _applyMiddlewares = /* @__PURE__ */ new WeakSet();
@@ -75,6 +76,7 @@ class ServerBase {
75
76
  this.serverContext = null;
76
77
  this.options = options;
77
78
  this.app = new Hono();
79
+ this.app.use("*", run);
78
80
  }
79
81
  }
80
82
  function applyMiddlewares() {
@@ -0,0 +1,40 @@
1
+ import * as ah from "async_hooks";
2
+ const createStorage = () => {
3
+ let storage;
4
+ if (typeof ah.AsyncLocalStorage !== "undefined") {
5
+ storage = new ah.AsyncLocalStorage();
6
+ }
7
+ const run = (context, cb) => {
8
+ if (!storage) {
9
+ throw new Error(`Unable to use async_hook, please confirm the node version >= 12.17
10
+ `);
11
+ }
12
+ return new Promise((resolve, reject) => {
13
+ storage.run(context, () => {
14
+ try {
15
+ return resolve(cb());
16
+ } catch (error) {
17
+ return reject(error);
18
+ }
19
+ });
20
+ });
21
+ };
22
+ const useHonoContext = () => {
23
+ if (!storage) {
24
+ throw new Error(`Unable to use async_hook, please confirm the node version >= 12.17
25
+ `);
26
+ }
27
+ const context = storage.getStore();
28
+ if (!context) {
29
+ throw new Error(`Can't call useContext out of server scope`);
30
+ }
31
+ return context;
32
+ };
33
+ return {
34
+ run,
35
+ useHonoContext
36
+ };
37
+ };
38
+ export {
39
+ createStorage
40
+ };
@@ -0,0 +1,3 @@
1
+ import type { Context } from 'hono';
2
+ declare const run: <O>(context: Context<any, any, {}>, cb: () => O | Promise<O>) => Promise<O>, useHonoContext: () => Context<any, any, {}>;
3
+ export { run, useHonoContext };
@@ -2,6 +2,8 @@ export { createErrorHtml, onError, ErrorDigest } from './utils';
2
2
  export { AGGRED_DIR } from './constants';
3
3
  export type { ServerBase, ServerBaseOptions } from './serverBase';
4
4
  export { createServerBase } from './serverBase';
5
+ export { useHonoContext } from './context';
6
+ export { Hono, type MiddlewareHandler } from 'hono';
5
7
  export type { Middleware, Context, Next, HonoRequest as InternalRequest, ServerEnv, ServerManifest, ServerLoaderBundle, } from './types';
6
8
  export { getLoaderCtx } from './helper';
7
9
  export * from './plugins';
@@ -36,6 +36,11 @@ export interface ServerUserConfig {
36
36
  */
37
37
  useJsonScript?: boolean;
38
38
  logger?: boolean | Record<string, unknown>;
39
+ /**
40
+ * @description disable hook middleware for performance
41
+ * @default false
42
+ */
43
+ disableHook?: boolean;
39
44
  }
40
45
  export type ServerNormalizedConfig = ServerUserConfig;
41
46
  export {};
@@ -7,7 +7,7 @@ import type { Render } from '../render';
7
7
  import type { ServerPlugin } from './new';
8
8
  import type { ServerPluginLegacy } from './old';
9
9
  export type { FileChangeEvent, ResetEvent } from '@modern-js/plugin-v2';
10
- export type FallbackReason = 'error' | 'header' | 'query';
10
+ export type FallbackReason = 'error' | 'header' | 'query' | `header,${string}`;
11
11
  export type FallbackInput = {
12
12
  reason: FallbackReason;
13
13
  error: unknown;
@@ -44,6 +44,7 @@ export type Middleware = {
44
44
  before?: Array<Middleware['name']>;
45
45
  order?: MiddlewareOrder;
46
46
  };
47
+ export type ServerMiddleware = Middleware;
47
48
  export interface GetRenderHandlerOptions {
48
49
  pwd: string;
49
50
  routes: ServerRoute[];
@@ -1,3 +1,3 @@
1
1
  export * from './new';
2
2
  export * from './old';
3
- export type { ServerConfig, CacheConfig, OnFallback, FallbackReason, GetRenderHandlerOptions, FileChangeEvent, FallbackInput, WebServerStartInput, APIServerStartInput, } from './base';
3
+ export type { ServerConfig, CacheConfig, OnFallback, FallbackReason, GetRenderHandlerOptions, FileChangeEvent, FallbackInput, WebServerStartInput, APIServerStartInput, ServerMiddleware, } from './base';
@@ -0,0 +1,5 @@
1
+ declare const createStorage: <T>() => {
2
+ run: <O>(context: T, cb: () => O | Promise<O>) => Promise<O>;
3
+ useHonoContext: () => T;
4
+ };
5
+ export { createStorage };
package/package.json CHANGED
@@ -15,7 +15,7 @@
15
15
  "modern",
16
16
  "modern.js"
17
17
  ],
18
- "version": "2.67.1",
18
+ "version": "2.67.3",
19
19
  "jsnext:source": "./src/index.ts",
20
20
  "types": "./dist/types/index.d.ts",
21
21
  "main": "./dist/cjs/index.js",
@@ -50,25 +50,27 @@
50
50
  "@web-std/fetch": "^4.2.1",
51
51
  "@web-std/file": "^3.0.3",
52
52
  "@web-std/stream": "^1.0.3",
53
+ "cloneable-readable": "^3.0.0",
53
54
  "flatted": "^3.2.9",
54
55
  "hono": "^3.12.2",
55
56
  "ts-deepmerge": "7.0.2",
56
- "@modern-js/plugin": "2.67.1",
57
- "@modern-js/runtime-utils": "2.67.1",
58
- "@modern-js/utils": "2.67.1",
59
- "@modern-js/plugin-v2": "2.67.1"
57
+ "@modern-js/plugin": "2.67.3",
58
+ "@modern-js/plugin-v2": "2.67.3",
59
+ "@modern-js/runtime-utils": "2.67.3",
60
+ "@modern-js/utils": "2.67.3"
60
61
  },
61
62
  "devDependencies": {
63
+ "@types/cloneable-readable": "^2.0.3",
62
64
  "@types/jest": "^29",
63
65
  "@types/merge-deep": "^3.0.0",
64
66
  "@types/node": "^14",
65
- "http-proxy-middleware": "^2.0.4",
67
+ "http-proxy-middleware": "^2.0.9",
66
68
  "jest": "^29",
67
69
  "ts-jest": "^29.1.0",
68
70
  "typescript": "^5",
69
- "@scripts/build": "2.66.0",
71
+ "@modern-js/types": "2.67.3",
70
72
  "@scripts/jest-config": "2.66.0",
71
- "@modern-js/types": "2.67.1"
73
+ "@scripts/build": "2.66.0"
72
74
  },
73
75
  "sideEffects": false,
74
76
  "publishConfig": {