vinext 0.0.24 → 0.0.26

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 (145) hide show
  1. package/README.md +30 -1
  2. package/dist/check.d.ts.map +1 -1
  3. package/dist/check.js +6 -5
  4. package/dist/check.js.map +1 -1
  5. package/dist/cli.js +32 -1
  6. package/dist/cli.js.map +1 -1
  7. package/dist/client/entry.js +1 -1
  8. package/dist/client/entry.js.map +1 -1
  9. package/dist/client/vinext-next-data.d.ts +22 -0
  10. package/dist/client/vinext-next-data.d.ts.map +1 -0
  11. package/dist/client/vinext-next-data.js +2 -0
  12. package/dist/client/vinext-next-data.js.map +1 -0
  13. package/dist/config/config-matchers.d.ts +21 -0
  14. package/dist/config/config-matchers.d.ts.map +1 -1
  15. package/dist/config/config-matchers.js +52 -8
  16. package/dist/config/config-matchers.js.map +1 -1
  17. package/dist/config/next-config.d.ts +39 -6
  18. package/dist/config/next-config.d.ts.map +1 -1
  19. package/dist/config/next-config.js +241 -48
  20. package/dist/config/next-config.js.map +1 -1
  21. package/dist/deploy.d.ts +21 -0
  22. package/dist/deploy.d.ts.map +1 -1
  23. package/dist/deploy.js +94 -41
  24. package/dist/deploy.js.map +1 -1
  25. package/dist/entries/app-browser-entry.d.ts +9 -0
  26. package/dist/entries/app-browser-entry.d.ts.map +1 -0
  27. package/dist/entries/app-browser-entry.js +340 -0
  28. package/dist/entries/app-browser-entry.js.map +1 -0
  29. package/dist/{server/app-dev-server.d.ts → entries/app-rsc-entry.d.ts} +6 -19
  30. package/dist/entries/app-rsc-entry.d.ts.map +1 -0
  31. package/dist/{server/app-dev-server.js → entries/app-rsc-entry.js} +572 -1293
  32. package/dist/entries/app-rsc-entry.js.map +1 -0
  33. package/dist/entries/app-ssr-entry.d.ts +8 -0
  34. package/dist/entries/app-ssr-entry.d.ts.map +1 -0
  35. package/dist/entries/app-ssr-entry.js +449 -0
  36. package/dist/entries/app-ssr-entry.js.map +1 -0
  37. package/dist/entries/pages-client-entry.d.ts +4 -0
  38. package/dist/entries/pages-client-entry.d.ts.map +1 -0
  39. package/dist/entries/pages-client-entry.js +94 -0
  40. package/dist/entries/pages-client-entry.js.map +1 -0
  41. package/dist/entries/pages-entry-helpers.d.ts +7 -0
  42. package/dist/entries/pages-entry-helpers.d.ts.map +1 -0
  43. package/dist/entries/pages-entry-helpers.js +18 -0
  44. package/dist/entries/pages-entry-helpers.js.map +1 -0
  45. package/dist/entries/pages-server-entry.d.ts +8 -0
  46. package/dist/entries/pages-server-entry.d.ts.map +1 -0
  47. package/dist/entries/pages-server-entry.js +993 -0
  48. package/dist/entries/pages-server-entry.js.map +1 -0
  49. package/dist/index.d.ts +4 -25
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +345 -1227
  52. package/dist/index.js.map +1 -1
  53. package/dist/plugins/async-hooks-stub.d.ts +16 -0
  54. package/dist/plugins/async-hooks-stub.d.ts.map +1 -0
  55. package/dist/plugins/async-hooks-stub.js +45 -0
  56. package/dist/plugins/async-hooks-stub.js.map +1 -0
  57. package/dist/routing/app-router.d.ts +12 -6
  58. package/dist/routing/app-router.d.ts.map +1 -1
  59. package/dist/routing/app-router.js +19 -40
  60. package/dist/routing/app-router.js.map +1 -1
  61. package/dist/routing/pages-router.d.ts.map +1 -1
  62. package/dist/routing/pages-router.js +3 -9
  63. package/dist/routing/pages-router.js.map +1 -1
  64. package/dist/routing/utils.d.ts +9 -0
  65. package/dist/routing/utils.d.ts.map +1 -1
  66. package/dist/routing/utils.js +10 -0
  67. package/dist/routing/utils.js.map +1 -1
  68. package/dist/server/api-handler.d.ts.map +1 -1
  69. package/dist/server/api-handler.js +6 -0
  70. package/dist/server/api-handler.js.map +1 -1
  71. package/dist/server/dev-module-runner.d.ts +84 -0
  72. package/dist/server/dev-module-runner.d.ts.map +1 -0
  73. package/dist/server/dev-module-runner.js +105 -0
  74. package/dist/server/dev-module-runner.js.map +1 -0
  75. package/dist/server/dev-server.js.map +1 -1
  76. package/dist/server/instrumentation.d.ts +52 -9
  77. package/dist/server/instrumentation.d.ts.map +1 -1
  78. package/dist/server/instrumentation.js +52 -15
  79. package/dist/server/instrumentation.js.map +1 -1
  80. package/dist/server/middleware-codegen.d.ts +1 -1
  81. package/dist/server/middleware-codegen.js +1 -1
  82. package/dist/server/middleware-codegen.js.map +1 -1
  83. package/dist/server/middleware.d.ts +7 -3
  84. package/dist/server/middleware.d.ts.map +1 -1
  85. package/dist/server/middleware.js +16 -6
  86. package/dist/server/middleware.js.map +1 -1
  87. package/dist/server/prod-server.d.ts.map +1 -1
  88. package/dist/server/prod-server.js +33 -28
  89. package/dist/server/prod-server.js.map +1 -1
  90. package/dist/server/request-pipeline.d.ts +92 -0
  91. package/dist/server/request-pipeline.d.ts.map +1 -0
  92. package/dist/server/request-pipeline.js +202 -0
  93. package/dist/server/request-pipeline.js.map +1 -0
  94. package/dist/shims/cache.d.ts.map +1 -1
  95. package/dist/shims/cache.js +14 -2
  96. package/dist/shims/cache.js.map +1 -1
  97. package/dist/shims/constants.d.ts +120 -3
  98. package/dist/shims/constants.d.ts.map +1 -1
  99. package/dist/shims/constants.js +170 -3
  100. package/dist/shims/constants.js.map +1 -1
  101. package/dist/shims/fetch-cache.d.ts.map +1 -1
  102. package/dist/shims/fetch-cache.js +139 -29
  103. package/dist/shims/fetch-cache.js.map +1 -1
  104. package/dist/shims/form.d.ts.map +1 -1
  105. package/dist/shims/form.js +2 -3
  106. package/dist/shims/form.js.map +1 -1
  107. package/dist/shims/headers.d.ts.map +1 -1
  108. package/dist/shims/headers.js +1 -0
  109. package/dist/shims/headers.js.map +1 -1
  110. package/dist/shims/layout-segment-context.d.ts +5 -4
  111. package/dist/shims/layout-segment-context.d.ts.map +1 -1
  112. package/dist/shims/layout-segment-context.js +6 -5
  113. package/dist/shims/layout-segment-context.js.map +1 -1
  114. package/dist/shims/link.d.ts.map +1 -1
  115. package/dist/shims/link.js +33 -18
  116. package/dist/shims/link.js.map +1 -1
  117. package/dist/shims/metadata.d.ts +7 -1
  118. package/dist/shims/metadata.d.ts.map +1 -1
  119. package/dist/shims/metadata.js +9 -3
  120. package/dist/shims/metadata.js.map +1 -1
  121. package/dist/shims/navigation.d.ts +14 -11
  122. package/dist/shims/navigation.d.ts.map +1 -1
  123. package/dist/shims/navigation.js +122 -102
  124. package/dist/shims/navigation.js.map +1 -1
  125. package/dist/shims/og.d.ts +6 -6
  126. package/dist/shims/og.js +6 -6
  127. package/dist/shims/og.js.map +1 -1
  128. package/dist/shims/router.d.ts.map +1 -1
  129. package/dist/shims/router.js +37 -21
  130. package/dist/shims/router.js.map +1 -1
  131. package/dist/shims/server.d.ts +2 -0
  132. package/dist/shims/server.d.ts.map +1 -1
  133. package/dist/shims/server.js +4 -0
  134. package/dist/shims/server.js.map +1 -1
  135. package/dist/shims/url-utils.d.ts +13 -0
  136. package/dist/shims/url-utils.d.ts.map +1 -0
  137. package/dist/shims/url-utils.js +28 -0
  138. package/dist/shims/url-utils.js.map +1 -0
  139. package/dist/utils/project.d.ts +15 -0
  140. package/dist/utils/project.d.ts.map +1 -1
  141. package/dist/utils/project.js +48 -0
  142. package/dist/utils/project.js.map +1 -1
  143. package/package.json +1 -1
  144. package/dist/server/app-dev-server.d.ts.map +0 -1
  145. package/dist/server/app-dev-server.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"middleware-codegen.js","sourceRoot":"","sources":["../../src/server/middleware-codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,QAA0B,QAAQ;IACvE,MAAM,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/C,MAAM,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7C,OAAO;;IAEL,CAAC;IACD,CAAC;IACD,CAAC;;MAEC,CAAC;;;;;;;;;;;;;;;;;;;QAmBC,CAAC;;QAED,CAAC;;;;;;;;;;;;;;QAcD,CAAC;;;;;;;;QAQD,CAAC;;;;;;;;;;;;;;;;;;EAkBP,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAA0B,QAAQ;IAC1E,MAAM,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/C,MAAM,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7C,OAAO;;;;;;;;;;;;;;IAcL,CAAC;IACD,CAAC;SACI,CAAC;MACJ,CAAC;;;;;;EAML,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,6BAA6B,CAAC,QAA0B,QAAQ;IAC9E,MAAM,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/C,MAAM,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7C,MAAM,EAAE,GAAG,KAAK,KAAK,QAAQ;QAC3B,CAAC,CAAC,CAAC,MAAc,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI,MAAM,UAAU,IAAI,IAAI;QAChE,CAAC,CAAC,CAAC,MAAc,EAAE,IAAY,EAAE,EAAE,CAAC,YAAY,MAAM,OAAO,IAAI,IAAI,CAAC;IAExE,oEAAoE;IACpE,qEAAqE;IACrE,iCAAiC;IACjC,OAAO;;;;;;MAMH,CAAC;;;;;IAKH,CAAC;IACD,CAAC;IACD,CAAC;;;;;;;;IAQD,CAAC;;;;;;;;IAQD,CAAC;;;WAGM,CAAC;;;;;yBAKa,EAAE,CAAC,GAAG,EAAE,6CAA6C,CAAC;EAC7E,CAAC;AACH,CAAC","sourcesContent":["/**\n * Shared middleware matching code generator.\n *\n * Both the App Router RSC entry (app-dev-server.ts) and the Pages Router\n * production entry (index.ts) need middleware matching logic inlined as\n * generated JavaScript strings. This module provides a single source of\n * truth to prevent the implementations from diverging.\n *\n * The regex detection guard (checking for \"(\" or \"\\\\\") is critical.\n * Without it, dot-escaping corrupts regex patterns like\n * /((?!api|_next).*), causing middleware to silently skip paths.\n */\n\n/**\n * Returns the generated JavaScript source for `__isSafeRegex` and `__safeRegExp`.\n *\n * @param style - \"modern\" emits const/let (for RSC entry), \"es5\" emits var (for prod entry)\n */\nexport function generateSafeRegExpCode(style: \"modern\" | \"es5\" = \"modern\"): string {\n const v = style === \"modern\" ? \"const\" : \"var\";\n const l = style === \"modern\" ? \"let\" : \"var\";\n return `\nfunction __isSafeRegex(pattern) {\n ${v} quantifierAtDepth = [];\n ${l} depth = 0;\n ${l} i = 0;\n while (i < pattern.length) {\n ${v} ch = pattern[i];\n if (ch === \"\\\\\\\\\") { i += 2; continue; }\n if (ch === \"[\") {\n i++;\n while (i < pattern.length && pattern[i] !== \"]\") {\n if (pattern[i] === \"\\\\\\\\\") i++;\n i++;\n }\n i++;\n continue;\n }\n if (ch === \"(\") {\n depth++;\n if (quantifierAtDepth.length <= depth) quantifierAtDepth.push(false);\n else quantifierAtDepth[depth] = false;\n i++;\n continue;\n }\n if (ch === \")\") {\n ${v} hadQ = depth > 0 && quantifierAtDepth[depth];\n if (depth > 0) depth--;\n ${v} next = pattern[i + 1];\n if (next === \"+\" || next === \"*\" || next === \"{\") {\n if (hadQ) return false;\n if (depth >= 0 && depth < quantifierAtDepth.length) quantifierAtDepth[depth] = true;\n }\n i++;\n continue;\n }\n if (ch === \"+\" || ch === \"*\") {\n if (depth > 0) quantifierAtDepth[depth] = true;\n i++;\n continue;\n }\n if (ch === \"?\") {\n ${v} prev = i > 0 ? pattern[i - 1] : \"\";\n if (prev !== \"+\" && prev !== \"*\" && prev !== \"?\" && prev !== \"}\") {\n if (depth > 0) quantifierAtDepth[depth] = true;\n }\n i++;\n continue;\n }\n if (ch === \"{\") {\n ${l} j = i + 1;\n while (j < pattern.length && /[\\\\d,]/.test(pattern[j])) j++;\n if (j < pattern.length && pattern[j] === \"}\" && j > i + 1) {\n if (depth > 0) quantifierAtDepth[depth] = true;\n i = j + 1;\n continue;\n }\n }\n i++;\n }\n return true;\n}\nfunction __safeRegExp(pattern, flags) {\n if (!__isSafeRegex(pattern)) {\n console.warn(\"[vinext] Ignoring potentially unsafe regex pattern (ReDoS risk): \" + pattern);\n return null;\n }\n try { return new RegExp(pattern, flags); } catch { return null; }\n}`;\n}\n\n/**\n * Returns the generated JavaScript source for `__normalizePath`.\n *\n * This must be kept in sync with `normalizePath()` in `normalize-path.ts`.\n * The inline version is used by codegen entries that can't import modules.\n *\n * @param style - \"modern\" emits const/let, \"es5\" emits var\n */\nexport function generateNormalizePathCode(style: \"modern\" | \"es5\" = \"modern\"): string {\n const v = style === \"modern\" ? \"const\" : \"var\";\n const l = style === \"modern\" ? \"let\" : \"var\";\n return `\nfunction __normalizePath(pathname) {\n if (\n pathname === \"/\" ||\n (pathname.length > 1 &&\n pathname[0] === \"/\" &&\n !pathname.includes(\"//\") &&\n !pathname.includes(\"/./\") &&\n !pathname.includes(\"/../\") &&\n !pathname.endsWith(\"/.\") &&\n !pathname.endsWith(\"/..\"))\n ) {\n return pathname;\n }\n ${v} segments = pathname.split(\"/\");\n ${v} resolved = [];\n for (${l} i = 0; i < segments.length; i++) {\n ${v} seg = segments[i];\n if (seg === \"\" || seg === \".\") continue;\n if (seg === \"..\") { resolved.pop(); }\n else { resolved.push(seg); }\n }\n return \"/\" + resolved.join(\"/\");\n}`;\n}\n\n/**\n * Returns the generated JavaScript source for middleware pattern matching.\n *\n * This includes:\n * - `matchMiddlewarePattern(pathname, pattern)` — matches a single pattern\n * - `matchesMiddleware(pathname, matcher)` — matches the full matcher config\n *\n * The generated code depends on `__safeRegExp` being defined in the same scope\n * (use `generateSafeRegExpCode` to emit it).\n *\n * @param style - \"modern\" emits const/let/arrow functions, \"es5\" emits var/function\n */\nexport function generateMiddlewareMatcherCode(style: \"modern\" | \"es5\" = \"modern\"): string {\n const v = style === \"modern\" ? \"const\" : \"var\";\n const l = style === \"modern\" ? \"let\" : \"var\";\n const fn = style === \"modern\"\n ? (params: string, body: string) => `(${params}) => { ${body} }`\n : (params: string, body: string) => `function(${params}) { ${body} }`;\n\n // The pattern matching logic must be identical to matchPattern() in\n // packages/vinext/src/server/middleware.ts. Any changes here must be\n // mirrored there and vice versa.\n return `\nfunction matchMiddlewarePattern(pathname, pattern) {\n // Regex patterns: if the pattern contains \"(\" or \"\\\\\" it's a regex —\n // pass it through to RegExp directly WITHOUT dot-escaping.\n // This guard prevents regex pattern corruption from dot-escaping.\n if (pattern.includes(\"(\") || pattern.includes(\"\\\\\\\\\")) {\n ${v} re = __safeRegExp(\"^\" + pattern + \"$\");\n if (re) return re.test(pathname);\n }\n // Single-pass tokenizer (avoids chained .replace() flagged by CodeQL as\n // incomplete sanitization — later passes could re-process earlier outputs).\n ${l} regexStr = \"\";\n ${v} tokenRe = /\\\\/:([\\\\w-]+)\\\\*|\\\\/:([\\\\w-]+)\\\\+|:([\\\\w-]+)|[.]|[^/:.]+|./g;\n ${l} tok;\n while ((tok = tokenRe.exec(pattern)) !== null) {\n if (tok[1] !== undefined) { regexStr += \"(?:/.*)?\"; }\n else if (tok[2] !== undefined) { regexStr += \"(?:/.+)\"; }\n else if (tok[3] !== undefined) { regexStr += \"([^/]+)\"; }\n else if (tok[0] === \".\") { regexStr += \"\\\\\\\\.\"; }\n else { regexStr += tok[0]; }\n }\n ${v} re2 = __safeRegExp(\"^\" + regexStr + \"$\");\n return re2 ? re2.test(pathname) : pathname === pattern;\n}\n\nfunction matchesMiddleware(pathname, matcher) {\n if (!matcher) {\n return true;\n }\n ${v} patterns = [];\n if (typeof matcher === \"string\") { patterns.push(matcher); }\n else if (Array.isArray(matcher)) {\n for (${v} m of matcher) {\n if (typeof m === \"string\") patterns.push(m);\n else if (m && typeof m === \"object\" && \"source\" in m) patterns.push(m.source);\n }\n }\n return patterns.some(${fn(\"p\", \"return matchMiddlewarePattern(pathname, p);\")});\n}`;\n}\n\n\n"]}
1
+ {"version":3,"file":"middleware-codegen.js","sourceRoot":"","sources":["../../src/server/middleware-codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,QAA0B,QAAQ;IACvE,MAAM,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/C,MAAM,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7C,OAAO;;IAEL,CAAC;IACD,CAAC;IACD,CAAC;;MAEC,CAAC;;;;;;;;;;;;;;;;;;;QAmBC,CAAC;;QAED,CAAC;;;;;;;;;;;;;;QAcD,CAAC;;;;;;;;QAQD,CAAC;;;;;;;;;;;;;;;;;;EAkBP,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAA0B,QAAQ;IAC1E,MAAM,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/C,MAAM,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7C,OAAO;;;;;;;;;;;;;;IAcL,CAAC;IACD,CAAC;SACI,CAAC;MACJ,CAAC;;;;;;EAML,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,6BAA6B,CAAC,QAA0B,QAAQ;IAC9E,MAAM,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/C,MAAM,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7C,MAAM,EAAE,GAAG,KAAK,KAAK,QAAQ;QAC3B,CAAC,CAAC,CAAC,MAAc,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI,MAAM,UAAU,IAAI,IAAI;QAChE,CAAC,CAAC,CAAC,MAAc,EAAE,IAAY,EAAE,EAAE,CAAC,YAAY,MAAM,OAAO,IAAI,IAAI,CAAC;IAExE,oEAAoE;IACpE,qEAAqE;IACrE,iCAAiC;IACjC,OAAO;;;;;;MAMH,CAAC;;;;;IAKH,CAAC;IACD,CAAC;IACD,CAAC;;;;;;;;IAQD,CAAC;;;;;;;;IAQD,CAAC;;;WAGM,CAAC;;;;;yBAKa,EAAE,CAAC,GAAG,EAAE,6CAA6C,CAAC;EAC7E,CAAC;AACH,CAAC","sourcesContent":["/**\n * Shared middleware matching code generator.\n *\n * Both the App Router RSC entry (entries/app-rsc-entry.ts) and the Pages Router\n * production entry (index.ts) need middleware matching logic inlined as\n * generated JavaScript strings. This module provides a single source of\n * truth to prevent the implementations from diverging.\n *\n * The regex detection guard (checking for \"(\" or \"\\\\\") is critical.\n * Without it, dot-escaping corrupts regex patterns like\n * /((?!api|_next).*), causing middleware to silently skip paths.\n */\n\n/**\n * Returns the generated JavaScript source for `__isSafeRegex` and `__safeRegExp`.\n *\n * @param style - \"modern\" emits const/let (for RSC entry), \"es5\" emits var (for prod entry)\n */\nexport function generateSafeRegExpCode(style: \"modern\" | \"es5\" = \"modern\"): string {\n const v = style === \"modern\" ? \"const\" : \"var\";\n const l = style === \"modern\" ? \"let\" : \"var\";\n return `\nfunction __isSafeRegex(pattern) {\n ${v} quantifierAtDepth = [];\n ${l} depth = 0;\n ${l} i = 0;\n while (i < pattern.length) {\n ${v} ch = pattern[i];\n if (ch === \"\\\\\\\\\") { i += 2; continue; }\n if (ch === \"[\") {\n i++;\n while (i < pattern.length && pattern[i] !== \"]\") {\n if (pattern[i] === \"\\\\\\\\\") i++;\n i++;\n }\n i++;\n continue;\n }\n if (ch === \"(\") {\n depth++;\n if (quantifierAtDepth.length <= depth) quantifierAtDepth.push(false);\n else quantifierAtDepth[depth] = false;\n i++;\n continue;\n }\n if (ch === \")\") {\n ${v} hadQ = depth > 0 && quantifierAtDepth[depth];\n if (depth > 0) depth--;\n ${v} next = pattern[i + 1];\n if (next === \"+\" || next === \"*\" || next === \"{\") {\n if (hadQ) return false;\n if (depth >= 0 && depth < quantifierAtDepth.length) quantifierAtDepth[depth] = true;\n }\n i++;\n continue;\n }\n if (ch === \"+\" || ch === \"*\") {\n if (depth > 0) quantifierAtDepth[depth] = true;\n i++;\n continue;\n }\n if (ch === \"?\") {\n ${v} prev = i > 0 ? pattern[i - 1] : \"\";\n if (prev !== \"+\" && prev !== \"*\" && prev !== \"?\" && prev !== \"}\") {\n if (depth > 0) quantifierAtDepth[depth] = true;\n }\n i++;\n continue;\n }\n if (ch === \"{\") {\n ${l} j = i + 1;\n while (j < pattern.length && /[\\\\d,]/.test(pattern[j])) j++;\n if (j < pattern.length && pattern[j] === \"}\" && j > i + 1) {\n if (depth > 0) quantifierAtDepth[depth] = true;\n i = j + 1;\n continue;\n }\n }\n i++;\n }\n return true;\n}\nfunction __safeRegExp(pattern, flags) {\n if (!__isSafeRegex(pattern)) {\n console.warn(\"[vinext] Ignoring potentially unsafe regex pattern (ReDoS risk): \" + pattern);\n return null;\n }\n try { return new RegExp(pattern, flags); } catch { return null; }\n}`;\n}\n\n/**\n * Returns the generated JavaScript source for `__normalizePath`.\n *\n * This must be kept in sync with `normalizePath()` in `normalize-path.ts`.\n * The inline version is used by codegen entries that can't import modules.\n *\n * @param style - \"modern\" emits const/let, \"es5\" emits var\n */\nexport function generateNormalizePathCode(style: \"modern\" | \"es5\" = \"modern\"): string {\n const v = style === \"modern\" ? \"const\" : \"var\";\n const l = style === \"modern\" ? \"let\" : \"var\";\n return `\nfunction __normalizePath(pathname) {\n if (\n pathname === \"/\" ||\n (pathname.length > 1 &&\n pathname[0] === \"/\" &&\n !pathname.includes(\"//\") &&\n !pathname.includes(\"/./\") &&\n !pathname.includes(\"/../\") &&\n !pathname.endsWith(\"/.\") &&\n !pathname.endsWith(\"/..\"))\n ) {\n return pathname;\n }\n ${v} segments = pathname.split(\"/\");\n ${v} resolved = [];\n for (${l} i = 0; i < segments.length; i++) {\n ${v} seg = segments[i];\n if (seg === \"\" || seg === \".\") continue;\n if (seg === \"..\") { resolved.pop(); }\n else { resolved.push(seg); }\n }\n return \"/\" + resolved.join(\"/\");\n}`;\n}\n\n/**\n * Returns the generated JavaScript source for middleware pattern matching.\n *\n * This includes:\n * - `matchMiddlewarePattern(pathname, pattern)` — matches a single pattern\n * - `matchesMiddleware(pathname, matcher)` — matches the full matcher config\n *\n * The generated code depends on `__safeRegExp` being defined in the same scope\n * (use `generateSafeRegExpCode` to emit it).\n *\n * @param style - \"modern\" emits const/let/arrow functions, \"es5\" emits var/function\n */\nexport function generateMiddlewareMatcherCode(style: \"modern\" | \"es5\" = \"modern\"): string {\n const v = style === \"modern\" ? \"const\" : \"var\";\n const l = style === \"modern\" ? \"let\" : \"var\";\n const fn = style === \"modern\"\n ? (params: string, body: string) => `(${params}) => { ${body} }`\n : (params: string, body: string) => `function(${params}) { ${body} }`;\n\n // The pattern matching logic must be identical to matchPattern() in\n // packages/vinext/src/server/middleware.ts. Any changes here must be\n // mirrored there and vice versa.\n return `\nfunction matchMiddlewarePattern(pathname, pattern) {\n // Regex patterns: if the pattern contains \"(\" or \"\\\\\" it's a regex —\n // pass it through to RegExp directly WITHOUT dot-escaping.\n // This guard prevents regex pattern corruption from dot-escaping.\n if (pattern.includes(\"(\") || pattern.includes(\"\\\\\\\\\")) {\n ${v} re = __safeRegExp(\"^\" + pattern + \"$\");\n if (re) return re.test(pathname);\n }\n // Single-pass tokenizer (avoids chained .replace() flagged by CodeQL as\n // incomplete sanitization — later passes could re-process earlier outputs).\n ${l} regexStr = \"\";\n ${v} tokenRe = /\\\\/:([\\\\w-]+)\\\\*|\\\\/:([\\\\w-]+)\\\\+|:([\\\\w-]+)|[.]|[^/:.]+|./g;\n ${l} tok;\n while ((tok = tokenRe.exec(pattern)) !== null) {\n if (tok[1] !== undefined) { regexStr += \"(?:/.*)?\"; }\n else if (tok[2] !== undefined) { regexStr += \"(?:/.+)\"; }\n else if (tok[3] !== undefined) { regexStr += \"([^/]+)\"; }\n else if (tok[0] === \".\") { regexStr += \"\\\\\\\\.\"; }\n else { regexStr += tok[0]; }\n }\n ${v} re2 = __safeRegExp(\"^\" + regexStr + \"$\");\n return re2 ? re2.test(pathname) : pathname === pattern;\n}\n\nfunction matchesMiddleware(pathname, matcher) {\n if (!matcher) {\n return true;\n }\n ${v} patterns = [];\n if (typeof matcher === \"string\") { patterns.push(matcher); }\n else if (Array.isArray(matcher)) {\n for (${v} m of matcher) {\n if (typeof m === \"string\") patterns.push(m);\n else if (m && typeof m === \"object\" && \"source\" in m) patterns.push(m.source);\n }\n }\n return patterns.some(${fn(\"p\", \"return matchMiddlewarePattern(pathname, p);\")});\n}`;\n}\n\n\n"]}
@@ -17,7 +17,7 @@
17
17
  *
18
18
  * Supports the `config.matcher` export for path filtering.
19
19
  */
20
- import type { ViteDevServer } from "vite";
20
+ import type { ModuleRunner } from "vite/module-runner";
21
21
  /**
22
22
  * Determine whether a middleware/proxy file path refers to a proxy file.
23
23
  * proxy.ts files accept `proxy` or `default` exports.
@@ -89,11 +89,15 @@ export interface MiddlewareResult {
89
89
  /**
90
90
  * Load and execute middleware for a given request.
91
91
  *
92
- * @param server - Vite dev server (for SSR module loading)
92
+ * @param runner - A ModuleRunner used to load the middleware module.
93
+ * Must be a long-lived instance created once (e.g. in configureServer) via
94
+ * createDirectRunner() — NOT recreated per request. Using server.ssrLoadModule
95
+ * directly crashes with `outsideEmitter` when @cloudflare/vite-plugin is
96
+ * present because SSRCompatModuleRunner reads environment.hot.api synchronously.
93
97
  * @param middlewarePath - Absolute path to the middleware file
94
98
  * @param request - The incoming Request object
95
99
  * @returns Middleware result describing what action to take
96
100
  */
97
- export declare function runMiddleware(server: ViteDevServer, middlewarePath: string, request: Request): Promise<MiddlewareResult>;
101
+ export declare function runMiddleware(runner: ModuleRunner, middlewarePath: string, request: Request): Promise<MiddlewareResult>;
98
102
  export {};
99
103
  //# sourceMappingURL=middleware.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/server/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAO1C;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,QAAQ,EAAE,MAAM,GACf,QAAQ,CAeV;AA0BD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAqB9D;AAED,qDAAqD;AACrD,KAAK,aAAa,GACd,MAAM,GACN,MAAM,EAAE,GACR;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,EAAE,CAAC;AAE1F;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,aAAa,GAAG,SAAS,GACjC,OAAO,CAqBT;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAkCvE;AAED,oCAAoC;AACpC,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,QAAQ,EAAE,OAAO,CAAC;IAClB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0FAA0F;IAC1F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,EACrB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,gBAAgB,CAAC,CA8H3B"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/server/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAOvD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,QAAQ,EAAE,MAAM,GACf,QAAQ,CAeV;AA0BD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAqB9D;AAED,qDAAqD;AACrD,KAAK,aAAa,GACd,MAAM,GACN,MAAM,EAAE,GACR;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,EAAE,CAAC;AAE1F;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,aAAa,GAAG,SAAS,GACjC,OAAO,CAqBT;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAkCvE;AAED,oCAAoC;AACpC,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,QAAQ,EAAE,OAAO,CAAC;IAClB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0FAA0F;IAC1F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,gBAAgB,CAAC,CAqI3B"}
@@ -19,7 +19,7 @@
19
19
  */
20
20
  import fs from "node:fs";
21
21
  import path from "node:path";
22
- import { NextRequest } from "../shims/server.js";
22
+ import { NextRequest, NextFetchEvent } from "../shims/server.js";
23
23
  import { safeRegExp } from "../config/config-matchers.js";
24
24
  import { normalizePath } from "./normalize-path.js";
25
25
  /**
@@ -181,14 +181,20 @@ export function matchPattern(pathname, pattern) {
181
181
  /**
182
182
  * Load and execute middleware for a given request.
183
183
  *
184
- * @param server - Vite dev server (for SSR module loading)
184
+ * @param runner - A ModuleRunner used to load the middleware module.
185
+ * Must be a long-lived instance created once (e.g. in configureServer) via
186
+ * createDirectRunner() — NOT recreated per request. Using server.ssrLoadModule
187
+ * directly crashes with `outsideEmitter` when @cloudflare/vite-plugin is
188
+ * present because SSRCompatModuleRunner reads environment.hot.api synchronously.
185
189
  * @param middlewarePath - Absolute path to the middleware file
186
190
  * @param request - The incoming Request object
187
191
  * @returns Middleware result describing what action to take
188
192
  */
189
- export async function runMiddleware(server, middlewarePath, request) {
190
- // Load the middleware module via Vite's SSR module loader
191
- const mod = await server.ssrLoadModule(middlewarePath);
193
+ export async function runMiddleware(runner, middlewarePath, request) {
194
+ // Load the middleware module via the direct-call ModuleRunner.
195
+ // This bypasses the hot channel entirely and is safe with all Vite plugin
196
+ // combinations, including @cloudflare/vite-plugin.
197
+ const mod = await runner.import(middlewarePath);
192
198
  // Resolve the handler based on file type (proxy.ts vs middleware.ts).
193
199
  // Throws if the file doesn't export a valid function, matching Next.js behavior.
194
200
  // https://github.com/vercel/next.js/blob/canary/test/e2e/app-dir/proxy-missing-export/proxy-missing-export.test.ts
@@ -221,10 +227,11 @@ export async function runMiddleware(server, middlewarePath, request) {
221
227
  }
222
228
  // Wrap in NextRequest so middleware gets .nextUrl, .cookies, .geo, .ip, etc.
223
229
  const nextRequest = mwRequest instanceof NextRequest ? mwRequest : new NextRequest(mwRequest);
230
+ const fetchEvent = new NextFetchEvent({ page: normalizedPathname });
224
231
  // Execute the middleware
225
232
  let response;
226
233
  try {
227
- response = await middlewareFn(nextRequest);
234
+ response = await middlewareFn(nextRequest, fetchEvent);
228
235
  }
229
236
  catch (e) {
230
237
  console.error("[vinext] Middleware error:", e);
@@ -238,6 +245,9 @@ export async function runMiddleware(server, middlewarePath, request) {
238
245
  }),
239
246
  };
240
247
  }
248
+ // Drain waitUntil promises (fire-and-forget: we don't block the response
249
+ // on these — matches platform semantics where waitUntil runs after response).
250
+ fetchEvent.drainWaitUntil();
241
251
  // No response = continue
242
252
  if (!response) {
243
253
  return { continue: true };
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/server/middleware.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * proxy.ts / middleware.ts runner\n *\n * Loads and executes the user's proxy.ts (Next.js 16) or middleware.ts file\n * before routing. Runs in Node (not Edge Runtime), per the vinext design.\n *\n * In Next.js 16, proxy.ts replaces middleware.ts:\n * - proxy.ts: default export OR named `proxy` function, runs on Node.js runtime\n * - middleware.ts: deprecated but still supported for Edge runtime use cases\n *\n * The proxy/middleware receives a NextRequest and can:\n * - Return NextResponse.next() to continue to the route\n * - Return NextResponse.redirect() to redirect\n * - Return NextResponse.rewrite() to rewrite the URL\n * - Set/modify headers and cookies\n * - Return a Response directly (e.g., for auth guards)\n *\n * Supports the `config.matcher` export for path filtering.\n */\n\nimport type { ViteDevServer } from \"vite\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { NextRequest } from \"../shims/server.js\";\nimport { safeRegExp } from \"../config/config-matchers.js\";\nimport { normalizePath } from \"./normalize-path.js\";\n\n/**\n * Determine whether a middleware/proxy file path refers to a proxy file.\n * proxy.ts files accept `proxy` or `default` exports.\n * middleware.ts files accept `middleware` or `default` exports.\n *\n * Matches Next.js behavior where each file type only accepts its own\n * named export or a default export:\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/build/templates/middleware.ts\n */\nexport function isProxyFile(filePath: string): boolean {\n const base = path.basename(filePath).replace(/\\.\\w+$/, \"\");\n return base === \"proxy\";\n}\n\n/**\n * Resolve the middleware/proxy handler function from a module's exports.\n * Matches Next.js behavior: for proxy files, check `proxy` then `default`;\n * for middleware files, check `middleware` then `default`.\n *\n * Throws if the file exists but doesn't export a valid function, matching\n * Next.js's ProxyMissingExportError behavior.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/build/templates/middleware.ts\n * @see https://github.com/vercel/next.js/blob/canary/test/e2e/app-dir/proxy-missing-export/proxy-missing-export.test.ts\n */\nexport function resolveMiddlewareHandler(\n mod: Record<string, unknown>,\n filePath: string,\n): Function {\n const isProxy = isProxyFile(filePath);\n const handler = isProxy\n ? (mod.proxy ?? mod.default)\n : (mod.middleware ?? mod.default);\n\n if (typeof handler !== \"function\") {\n const fileType = isProxy ? \"Proxy\" : \"Middleware\";\n const expectedExport = isProxy ? \"proxy\" : \"middleware\";\n throw new Error(\n `The ${fileType} file \"${filePath}\" must export a function named \\`${expectedExport}\\` or a \\`default\\` function.`,\n );\n }\n\n return handler as Function;\n}\n\n/**\n * Possible proxy/middleware file names.\n * proxy.ts (Next.js 16) is checked first, then middleware.ts (deprecated).\n */\nconst PROXY_FILES = [\n \"proxy.ts\",\n \"proxy.js\",\n \"proxy.mjs\",\n \"src/proxy.ts\",\n \"src/proxy.js\",\n \"src/proxy.mjs\",\n];\n\nconst MIDDLEWARE_FILES = [\n \"middleware.ts\",\n \"middleware.tsx\",\n \"middleware.js\",\n \"middleware.mjs\",\n \"src/middleware.ts\",\n \"src/middleware.tsx\",\n \"src/middleware.js\",\n \"src/middleware.mjs\",\n];\n\n/**\n * Find the proxy or middleware file in the project root.\n * Checks for proxy.ts (Next.js 16) first, then falls back to middleware.ts.\n * If middleware.ts is found, logs a deprecation warning.\n */\nexport function findMiddlewareFile(root: string): string | null {\n // Check proxy.ts first (Next.js 16 replacement for middleware.ts)\n for (const file of PROXY_FILES) {\n const fullPath = path.join(root, file);\n if (fs.existsSync(fullPath)) {\n return fullPath;\n }\n }\n\n // Fall back to middleware.ts (deprecated in Next.js 16)\n for (const file of MIDDLEWARE_FILES) {\n const fullPath = path.join(root, file);\n if (fs.existsSync(fullPath)) {\n console.warn(\n \"[vinext] middleware.ts is deprecated in Next.js 16. \" +\n \"Rename to proxy.ts and export a default or named proxy function.\",\n );\n return fullPath;\n }\n }\n return null;\n}\n\n/** Matcher pattern from middleware config export. */\ntype MatcherConfig =\n | string\n | string[]\n | { source: string; regexp?: string; locale?: boolean; has?: any[]; missing?: any[] }[];\n\n/**\n * Check if a pathname matches the middleware matcher config.\n * If no matcher is configured, middleware runs on all paths\n * except static files and internal Next.js paths.\n */\nexport function matchesMiddleware(\n pathname: string,\n matcher: MatcherConfig | undefined,\n): boolean {\n if (!matcher) {\n // Next.js default: middleware runs on ALL paths when no matcher is configured.\n // Users opt out of specific paths by configuring a matcher pattern.\n return true;\n }\n\n const patterns: string[] = [];\n if (typeof matcher === \"string\") {\n patterns.push(matcher);\n } else if (Array.isArray(matcher)) {\n for (const m of matcher) {\n if (typeof m === \"string\") {\n patterns.push(m);\n } else if (m && typeof m === \"object\" && \"source\" in m) {\n patterns.push(m.source);\n }\n }\n }\n\n return patterns.some((pattern) => matchPattern(pathname, pattern));\n}\n\n/**\n * Match a single pattern against a pathname.\n * Supports Next.js matcher patterns:\n * /about -> exact match\n * /dashboard/:path* -> prefix match with params\n * /api/:path+ -> one or more segments\n * /((?!api|_next).*) -> regex patterns\n */\nexport function matchPattern(pathname: string, pattern: string): boolean {\n // Handle regex patterns (starts with /)\n if (pattern.includes(\"(\") || pattern.includes(\"\\\\\")) {\n const re = safeRegExp(\"^\" + pattern + \"$\");\n if (re) return re.test(pathname);\n // Fall through to simple matching\n }\n\n // Convert Next.js path patterns to regex in a single pass.\n // Matches /:param*, /:param+, :param, dots, and literal text.\n // Param names may contain hyphens (e.g. [[...sign-in]]).\n let regexStr = \"\";\n const tokenRe = /\\/:([\\w-]+)\\*|\\/:([\\w-]+)\\+|:([\\w-]+)|[.]|[^/:.]+|./g;\n let tok: RegExpExecArray | null;\n while ((tok = tokenRe.exec(pattern)) !== null) {\n if (tok[1] !== undefined) {\n // /:param* → optionally match slash + zero or more segments\n regexStr += \"(?:/.*)?\";\n } else if (tok[2] !== undefined) {\n // /:param+ → match slash + one or more segments\n regexStr += \"(?:/.+)\";\n } else if (tok[3] !== undefined) {\n // :param → match one segment\n regexStr += \"([^/]+)\";\n } else if (tok[0] === \".\") {\n regexStr += \"\\\\.\";\n } else {\n regexStr += tok[0];\n }\n }\n\n const re = safeRegExp(\"^\" + regexStr + \"$\");\n if (re) return re.test(pathname);\n return pathname === pattern;\n}\n\n/** Result of running middleware. */\nexport interface MiddlewareResult {\n /** Whether to continue to the route handler. */\n continue: boolean;\n /** If set, redirect to this URL. */\n redirectUrl?: string;\n /** HTTP status for redirect (default 307). */\n redirectStatus?: number;\n /** If set, rewrite to this URL (internal). */\n rewriteUrl?: string;\n /** HTTP status for rewrite (e.g. 403 from NextResponse.rewrite(url, { status: 403 })). */\n rewriteStatus?: number;\n /** Headers to set on the response. */\n responseHeaders?: Headers;\n /** If the middleware returned a full Response, use it directly. */\n response?: Response;\n}\n\n/**\n * Load and execute middleware for a given request.\n *\n * @param server - Vite dev server (for SSR module loading)\n * @param middlewarePath - Absolute path to the middleware file\n * @param request - The incoming Request object\n * @returns Middleware result describing what action to take\n */\nexport async function runMiddleware(\n server: ViteDevServer,\n middlewarePath: string,\n request: Request,\n): Promise<MiddlewareResult> {\n // Load the middleware module via Vite's SSR module loader\n const mod = await server.ssrLoadModule(middlewarePath);\n\n // Resolve the handler based on file type (proxy.ts vs middleware.ts).\n // Throws if the file doesn't export a valid function, matching Next.js behavior.\n // https://github.com/vercel/next.js/blob/canary/test/e2e/app-dir/proxy-missing-export/proxy-missing-export.test.ts\n const middlewareFn = resolveMiddlewareHandler(mod, middlewarePath);\n\n // Check matcher config\n const config = mod.config;\n const matcher = config?.matcher;\n const url = new URL(request.url);\n\n // Normalize the pathname before middleware matching to prevent bypasses\n // via percent-encoding (/%61dmin → /admin) or double slashes (/dashboard//settings).\n let decodedPathname: string;\n try {\n decodedPathname = decodeURIComponent(url.pathname);\n } catch {\n // Malformed percent-encoding (e.g. /%E0%A4%A) — return 400 instead of throwing.\n return { continue: false, response: new Response(\"Bad Request\", { status: 400 }) };\n }\n const normalizedPathname = normalizePath(decodedPathname);\n\n if (!matchesMiddleware(normalizedPathname, matcher)) {\n return { continue: true };\n }\n\n // Construct a new Request with the fully decoded + normalized pathname so\n // middleware always sees the same canonical path that the router uses.\n let mwRequest = request;\n if (normalizedPathname !== url.pathname) {\n const mwUrl = new URL(url);\n mwUrl.pathname = normalizedPathname;\n mwRequest = new Request(mwUrl, request);\n }\n\n // Wrap in NextRequest so middleware gets .nextUrl, .cookies, .geo, .ip, etc.\n const nextRequest = mwRequest instanceof NextRequest ? mwRequest : new NextRequest(mwRequest);\n\n // Execute the middleware\n let response: Response | undefined;\n try {\n response = await middlewareFn(nextRequest);\n } catch (e: any) {\n console.error(\"[vinext] Middleware error:\", e);\n const message =\n process.env.NODE_ENV === \"production\"\n ? \"Internal Server Error\"\n : \"Middleware Error: \" + (e?.message ?? String(e));\n return {\n continue: false,\n response: new Response(message, {\n status: 500,\n }),\n };\n }\n\n // No response = continue\n if (!response) {\n return { continue: true };\n }\n\n // Check for x-middleware-next header (NextResponse.next())\n if (response.headers.get(\"x-middleware-next\") === \"1\") {\n // Continue to the route, but apply any headers the middleware set.\n // Strip ALL x-middleware-* headers (including x-middleware-request-*)\n // so they never leak to the client — they are internal routing signals.\n const responseHeaders = new Headers();\n for (const [key, value] of response.headers) {\n if (!key.startsWith(\"x-middleware-\")) {\n responseHeaders.append(key, value);\n }\n }\n return { continue: true, responseHeaders };\n }\n\n // Check for redirect (3xx status)\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get(\"Location\") ?? response.headers.get(\"location\");\n if (location) {\n // Collect non-internal headers (e.g. Set-Cookie) to forward with the redirect.\n const responseHeaders = new Headers();\n for (const [key, value] of response.headers) {\n if (!key.startsWith(\"x-middleware-\") && key.toLowerCase() !== \"location\") {\n responseHeaders.append(key, value);\n }\n }\n return {\n continue: false,\n redirectUrl: location,\n redirectStatus: response.status,\n responseHeaders,\n };\n }\n }\n\n // Check for rewrite (x-middleware-rewrite header)\n const rewriteUrl = response.headers.get(\"x-middleware-rewrite\");\n if (rewriteUrl) {\n // Continue to the route but with a rewritten URL\n const responseHeaders = new Headers();\n for (const [key, value] of response.headers) {\n if (!key.startsWith(\"x-middleware-\")) {\n responseHeaders.append(key, value);\n }\n }\n // Parse the rewrite URL — may be absolute or relative\n let rewritePath: string;\n try {\n const rewriteParsed = new URL(rewriteUrl, request.url);\n rewritePath = rewriteParsed.pathname + rewriteParsed.search;\n } catch {\n rewritePath = rewriteUrl;\n }\n return {\n continue: true,\n rewriteUrl: rewritePath,\n rewriteStatus: response.status !== 200 ? response.status : undefined,\n responseHeaders,\n };\n }\n\n // Middleware returned a full Response (e.g., blocking, custom body)\n return { continue: false, response };\n}\n"]}
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/server/middleware.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * proxy.ts / middleware.ts runner\n *\n * Loads and executes the user's proxy.ts (Next.js 16) or middleware.ts file\n * before routing. Runs in Node (not Edge Runtime), per the vinext design.\n *\n * In Next.js 16, proxy.ts replaces middleware.ts:\n * - proxy.ts: default export OR named `proxy` function, runs on Node.js runtime\n * - middleware.ts: deprecated but still supported for Edge runtime use cases\n *\n * The proxy/middleware receives a NextRequest and can:\n * - Return NextResponse.next() to continue to the route\n * - Return NextResponse.redirect() to redirect\n * - Return NextResponse.rewrite() to rewrite the URL\n * - Set/modify headers and cookies\n * - Return a Response directly (e.g., for auth guards)\n *\n * Supports the `config.matcher` export for path filtering.\n */\n\nimport type { ModuleRunner } from \"vite/module-runner\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { NextRequest, NextFetchEvent } from \"../shims/server.js\";\nimport { safeRegExp } from \"../config/config-matchers.js\";\nimport { normalizePath } from \"./normalize-path.js\";\n\n/**\n * Determine whether a middleware/proxy file path refers to a proxy file.\n * proxy.ts files accept `proxy` or `default` exports.\n * middleware.ts files accept `middleware` or `default` exports.\n *\n * Matches Next.js behavior where each file type only accepts its own\n * named export or a default export:\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/build/templates/middleware.ts\n */\nexport function isProxyFile(filePath: string): boolean {\n const base = path.basename(filePath).replace(/\\.\\w+$/, \"\");\n return base === \"proxy\";\n}\n\n/**\n * Resolve the middleware/proxy handler function from a module's exports.\n * Matches Next.js behavior: for proxy files, check `proxy` then `default`;\n * for middleware files, check `middleware` then `default`.\n *\n * Throws if the file exists but doesn't export a valid function, matching\n * Next.js's ProxyMissingExportError behavior.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/build/templates/middleware.ts\n * @see https://github.com/vercel/next.js/blob/canary/test/e2e/app-dir/proxy-missing-export/proxy-missing-export.test.ts\n */\nexport function resolveMiddlewareHandler(\n mod: Record<string, unknown>,\n filePath: string,\n): Function {\n const isProxy = isProxyFile(filePath);\n const handler = isProxy\n ? (mod.proxy ?? mod.default)\n : (mod.middleware ?? mod.default);\n\n if (typeof handler !== \"function\") {\n const fileType = isProxy ? \"Proxy\" : \"Middleware\";\n const expectedExport = isProxy ? \"proxy\" : \"middleware\";\n throw new Error(\n `The ${fileType} file \"${filePath}\" must export a function named \\`${expectedExport}\\` or a \\`default\\` function.`,\n );\n }\n\n return handler as Function;\n}\n\n/**\n * Possible proxy/middleware file names.\n * proxy.ts (Next.js 16) is checked first, then middleware.ts (deprecated).\n */\nconst PROXY_FILES = [\n \"proxy.ts\",\n \"proxy.js\",\n \"proxy.mjs\",\n \"src/proxy.ts\",\n \"src/proxy.js\",\n \"src/proxy.mjs\",\n];\n\nconst MIDDLEWARE_FILES = [\n \"middleware.ts\",\n \"middleware.tsx\",\n \"middleware.js\",\n \"middleware.mjs\",\n \"src/middleware.ts\",\n \"src/middleware.tsx\",\n \"src/middleware.js\",\n \"src/middleware.mjs\",\n];\n\n/**\n * Find the proxy or middleware file in the project root.\n * Checks for proxy.ts (Next.js 16) first, then falls back to middleware.ts.\n * If middleware.ts is found, logs a deprecation warning.\n */\nexport function findMiddlewareFile(root: string): string | null {\n // Check proxy.ts first (Next.js 16 replacement for middleware.ts)\n for (const file of PROXY_FILES) {\n const fullPath = path.join(root, file);\n if (fs.existsSync(fullPath)) {\n return fullPath;\n }\n }\n\n // Fall back to middleware.ts (deprecated in Next.js 16)\n for (const file of MIDDLEWARE_FILES) {\n const fullPath = path.join(root, file);\n if (fs.existsSync(fullPath)) {\n console.warn(\n \"[vinext] middleware.ts is deprecated in Next.js 16. \" +\n \"Rename to proxy.ts and export a default or named proxy function.\",\n );\n return fullPath;\n }\n }\n return null;\n}\n\n/** Matcher pattern from middleware config export. */\ntype MatcherConfig =\n | string\n | string[]\n | { source: string; regexp?: string; locale?: boolean; has?: any[]; missing?: any[] }[];\n\n/**\n * Check if a pathname matches the middleware matcher config.\n * If no matcher is configured, middleware runs on all paths\n * except static files and internal Next.js paths.\n */\nexport function matchesMiddleware(\n pathname: string,\n matcher: MatcherConfig | undefined,\n): boolean {\n if (!matcher) {\n // Next.js default: middleware runs on ALL paths when no matcher is configured.\n // Users opt out of specific paths by configuring a matcher pattern.\n return true;\n }\n\n const patterns: string[] = [];\n if (typeof matcher === \"string\") {\n patterns.push(matcher);\n } else if (Array.isArray(matcher)) {\n for (const m of matcher) {\n if (typeof m === \"string\") {\n patterns.push(m);\n } else if (m && typeof m === \"object\" && \"source\" in m) {\n patterns.push(m.source);\n }\n }\n }\n\n return patterns.some((pattern) => matchPattern(pathname, pattern));\n}\n\n/**\n * Match a single pattern against a pathname.\n * Supports Next.js matcher patterns:\n * /about -> exact match\n * /dashboard/:path* -> prefix match with params\n * /api/:path+ -> one or more segments\n * /((?!api|_next).*) -> regex patterns\n */\nexport function matchPattern(pathname: string, pattern: string): boolean {\n // Handle regex patterns (starts with /)\n if (pattern.includes(\"(\") || pattern.includes(\"\\\\\")) {\n const re = safeRegExp(\"^\" + pattern + \"$\");\n if (re) return re.test(pathname);\n // Fall through to simple matching\n }\n\n // Convert Next.js path patterns to regex in a single pass.\n // Matches /:param*, /:param+, :param, dots, and literal text.\n // Param names may contain hyphens (e.g. [[...sign-in]]).\n let regexStr = \"\";\n const tokenRe = /\\/:([\\w-]+)\\*|\\/:([\\w-]+)\\+|:([\\w-]+)|[.]|[^/:.]+|./g;\n let tok: RegExpExecArray | null;\n while ((tok = tokenRe.exec(pattern)) !== null) {\n if (tok[1] !== undefined) {\n // /:param* → optionally match slash + zero or more segments\n regexStr += \"(?:/.*)?\";\n } else if (tok[2] !== undefined) {\n // /:param+ → match slash + one or more segments\n regexStr += \"(?:/.+)\";\n } else if (tok[3] !== undefined) {\n // :param → match one segment\n regexStr += \"([^/]+)\";\n } else if (tok[0] === \".\") {\n regexStr += \"\\\\.\";\n } else {\n regexStr += tok[0];\n }\n }\n\n const re = safeRegExp(\"^\" + regexStr + \"$\");\n if (re) return re.test(pathname);\n return pathname === pattern;\n}\n\n/** Result of running middleware. */\nexport interface MiddlewareResult {\n /** Whether to continue to the route handler. */\n continue: boolean;\n /** If set, redirect to this URL. */\n redirectUrl?: string;\n /** HTTP status for redirect (default 307). */\n redirectStatus?: number;\n /** If set, rewrite to this URL (internal). */\n rewriteUrl?: string;\n /** HTTP status for rewrite (e.g. 403 from NextResponse.rewrite(url, { status: 403 })). */\n rewriteStatus?: number;\n /** Headers to set on the response. */\n responseHeaders?: Headers;\n /** If the middleware returned a full Response, use it directly. */\n response?: Response;\n}\n\n/**\n * Load and execute middleware for a given request.\n *\n * @param runner - A ModuleRunner used to load the middleware module.\n * Must be a long-lived instance created once (e.g. in configureServer) via\n * createDirectRunner() — NOT recreated per request. Using server.ssrLoadModule\n * directly crashes with `outsideEmitter` when @cloudflare/vite-plugin is\n * present because SSRCompatModuleRunner reads environment.hot.api synchronously.\n * @param middlewarePath - Absolute path to the middleware file\n * @param request - The incoming Request object\n * @returns Middleware result describing what action to take\n */\nexport async function runMiddleware(\n runner: ModuleRunner,\n middlewarePath: string,\n request: Request,\n): Promise<MiddlewareResult> {\n // Load the middleware module via the direct-call ModuleRunner.\n // This bypasses the hot channel entirely and is safe with all Vite plugin\n // combinations, including @cloudflare/vite-plugin.\n const mod = await runner.import(middlewarePath) as Record<string, unknown>;\n\n // Resolve the handler based on file type (proxy.ts vs middleware.ts).\n // Throws if the file doesn't export a valid function, matching Next.js behavior.\n // https://github.com/vercel/next.js/blob/canary/test/e2e/app-dir/proxy-missing-export/proxy-missing-export.test.ts\n const middlewareFn = resolveMiddlewareHandler(mod, middlewarePath);\n\n // Check matcher config\n const config = mod.config as { matcher?: MatcherConfig } | undefined;\n const matcher = config?.matcher;\n const url = new URL(request.url);\n\n // Normalize the pathname before middleware matching to prevent bypasses\n // via percent-encoding (/%61dmin → /admin) or double slashes (/dashboard//settings).\n let decodedPathname: string;\n try {\n decodedPathname = decodeURIComponent(url.pathname);\n } catch {\n // Malformed percent-encoding (e.g. /%E0%A4%A) — return 400 instead of throwing.\n return { continue: false, response: new Response(\"Bad Request\", { status: 400 }) };\n }\n const normalizedPathname = normalizePath(decodedPathname);\n\n if (!matchesMiddleware(normalizedPathname, matcher)) {\n return { continue: true };\n }\n\n // Construct a new Request with the fully decoded + normalized pathname so\n // middleware always sees the same canonical path that the router uses.\n let mwRequest = request;\n if (normalizedPathname !== url.pathname) {\n const mwUrl = new URL(url);\n mwUrl.pathname = normalizedPathname;\n mwRequest = new Request(mwUrl, request);\n }\n\n // Wrap in NextRequest so middleware gets .nextUrl, .cookies, .geo, .ip, etc.\n const nextRequest = mwRequest instanceof NextRequest ? mwRequest : new NextRequest(mwRequest);\n const fetchEvent = new NextFetchEvent({ page: normalizedPathname });\n\n // Execute the middleware\n let response: Response | undefined;\n try {\n response = await middlewareFn(nextRequest, fetchEvent);\n } catch (e: any) {\n console.error(\"[vinext] Middleware error:\", e);\n const message =\n process.env.NODE_ENV === \"production\"\n ? \"Internal Server Error\"\n : \"Middleware Error: \" + (e?.message ?? String(e));\n return {\n continue: false,\n response: new Response(message, {\n status: 500,\n }),\n };\n }\n\n // Drain waitUntil promises (fire-and-forget: we don't block the response\n // on these — matches platform semantics where waitUntil runs after response).\n fetchEvent.drainWaitUntil();\n\n // No response = continue\n if (!response) {\n return { continue: true };\n }\n\n // Check for x-middleware-next header (NextResponse.next())\n if (response.headers.get(\"x-middleware-next\") === \"1\") {\n // Continue to the route, but apply any headers the middleware set.\n // Strip ALL x-middleware-* headers (including x-middleware-request-*)\n // so they never leak to the client — they are internal routing signals.\n const responseHeaders = new Headers();\n for (const [key, value] of response.headers) {\n if (!key.startsWith(\"x-middleware-\")) {\n responseHeaders.append(key, value);\n }\n }\n return { continue: true, responseHeaders };\n }\n\n // Check for redirect (3xx status)\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get(\"Location\") ?? response.headers.get(\"location\");\n if (location) {\n // Collect non-internal headers (e.g. Set-Cookie) to forward with the redirect.\n const responseHeaders = new Headers();\n for (const [key, value] of response.headers) {\n if (!key.startsWith(\"x-middleware-\") && key.toLowerCase() !== \"location\") {\n responseHeaders.append(key, value);\n }\n }\n return {\n continue: false,\n redirectUrl: location,\n redirectStatus: response.status,\n responseHeaders,\n };\n }\n }\n\n // Check for rewrite (x-middleware-rewrite header)\n const rewriteUrl = response.headers.get(\"x-middleware-rewrite\");\n if (rewriteUrl) {\n // Continue to the route but with a rewritten URL\n const responseHeaders = new Headers();\n for (const [key, value] of response.headers) {\n if (!key.startsWith(\"x-middleware-\")) {\n responseHeaders.append(key, value);\n }\n }\n // Parse the rewrite URL — may be absolute or relative\n let rewritePath: string;\n try {\n const rewriteParsed = new URL(rewriteUrl, request.url);\n rewritePath = rewriteParsed.pathname + rewriteParsed.search;\n } catch {\n rewritePath = rewriteUrl;\n }\n return {\n continue: true,\n rewriteUrl: rewritePath,\n rewriteStatus: response.status !== 200 ? response.status : undefined,\n responseHeaders,\n };\n }\n\n // Middleware returned a full Response (e.g., blocking, custom body)\n return { continue: false, response };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"prod-server.d.ts","sourceRoot":"","sources":["../../src/server/prod-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAuBpF,MAAM,WAAW,iBAAiB;IAChC,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,mDAAmD;AACnD,QAAA,MAAM,kBAAkB,aAetB,CAAC;AAEH,0GAA0G;AAC1G,QAAA,MAAM,kBAAkB,OAAO,CAAC;AAEhC;;;GAGG;AACH,iBAAS,iBAAiB,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,CAQjF;AAoBD;;;;GAIG;AACH,iBAAS,oBAAoB,CAC3B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EACpD,QAAQ,EAAE,QAAQ,GACjB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAqBnC;AAED;;;GAGG;AACH,iBAAS,cAAc,CACrB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAM,EACpD,QAAQ,GAAE,OAAc,GACvB,IAAI,CAmCN;AAkGD;;;;;;;;;;;GAWG;AACH,iBAAS,WAAW,CAAC,GAAG,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAcnE;AAED,4EAA4E;AAC5E,QAAA,MAAM,YAAY,EAAE,GAAG,CAAC,MAAM,CAK7B,CAAC;AAEF;;;;GAIG;AACH,QAAA,MAAM,UAAU,SAAkE,CAAC;AAEnF;;GAEG;AACH,iBAAS,gBAAgB,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAmCvD;AA+ED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,OAAO,GAAE,iBAAsB,sFA6BpE;AA4iBD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,CAAC"}
1
+ {"version":3,"file":"prod-server.d.ts","sourceRoot":"","sources":["../../src/server/prod-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAuBpF,MAAM,WAAW,iBAAiB;IAChC,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,mDAAmD;AACnD,QAAA,MAAM,kBAAkB,aAetB,CAAC;AAEH,0GAA0G;AAC1G,QAAA,MAAM,kBAAkB,OAAO,CAAC;AAEhC;;;GAGG;AACH,iBAAS,iBAAiB,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,CAQjF;AAoBD;;;;GAIG;AACH,iBAAS,oBAAoB,CAC3B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EACpD,QAAQ,EAAE,QAAQ,GACjB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAqBnC;AAED;;;GAGG;AACH,iBAAS,cAAc,CACrB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAM,EACpD,QAAQ,GAAE,OAAc,GACvB,IAAI,CAmCN;AAkGD;;;;;;;;;;;GAWG;AACH,iBAAS,WAAW,CAAC,GAAG,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAcnE;AAED,4EAA4E;AAC5E,QAAA,MAAM,YAAY,EAAE,GAAG,CAAC,MAAM,CAK7B,CAAC;AAEF;;;;GAIG;AACH,QAAA,MAAM,UAAU,SAAkE,CAAC;AAEnF;;GAEG;AACH,iBAAS,gBAAgB,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAmCvD;AA+ED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,OAAO,GAAE,iBAAsB,sFA6BpE;AA+iBD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,CAAC"}
@@ -23,7 +23,7 @@ import { pathToFileURL } from "node:url";
23
23
  import fs from "node:fs";
24
24
  import path from "node:path";
25
25
  import zlib from "node:zlib";
26
- import { matchRedirect, matchRewrite, matchHeaders, requestContextFromRequest, isExternalUrl, proxyExternalRequest, sanitizeDestination } from "../config/config-matchers.js";
26
+ import { matchRedirect, matchRewrite, matchHeaders, requestContextFromRequest, applyMiddlewareRequestHeaders, isExternalUrl, proxyExternalRequest, sanitizeDestination } from "../config/config-matchers.js";
27
27
  import { IMAGE_OPTIMIZATION_PATH, IMAGE_CONTENT_SECURITY_POLICY, parseImageParams, isSafeImageContentType, DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES } from "./image-optimization.js";
28
28
  import { normalizePath } from "./normalize-path.js";
29
29
  import { computeLazyChunks } from "../index.js";
@@ -526,7 +526,7 @@ async function startAppRouterServer(options) {
526
526
  * Uses the server entry (dist/server/entry.js) which exports:
527
527
  * - renderPage(request, url, manifest) — SSR rendering (Web Request → Response)
528
528
  * - handleApiRoute(request, url) — API route handling (Web Request → Response)
529
- * - runMiddleware(request) — middleware execution
529
+ * - runMiddleware(request, ctx?) — middleware execution (ctx optional; pass for ctx.waitUntil() on Workers)
530
530
  * - vinextConfig — embedded next.config.js settings
531
531
  */
532
532
  async function startPagesRouterServer(options) {
@@ -648,7 +648,7 @@ async function startPagesRouterServer(options) {
648
648
  pathname = stripped;
649
649
  }
650
650
  // ── 3. Trailing slash normalization ───────────────────────────
651
- if (pathname !== "/" && !pathname.startsWith("/api")) {
651
+ if (pathname !== "/" && pathname !== "/api" && !pathname.startsWith("/api/")) {
652
652
  const hasTrailing = pathname.endsWith("/");
653
653
  if (trailingSlash && !hasTrailing) {
654
654
  const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
@@ -676,7 +676,7 @@ async function startPagesRouterServer(options) {
676
676
  }, new Headers());
677
677
  const method = req.method ?? "GET";
678
678
  const hasBody = method !== "GET" && method !== "HEAD";
679
- const webRequest = new Request(`${protocol}://${hostHeader}${url}`, {
679
+ let webRequest = new Request(`${protocol}://${hostHeader}${url}`, {
680
680
  method,
681
681
  headers: reqHeaders,
682
682
  body: hasBody ? readNodeStream(req) : undefined,
@@ -693,12 +693,27 @@ async function startPagesRouterServer(options) {
693
693
  const middlewareHeaders = {};
694
694
  let middlewareRewriteStatus;
695
695
  if (typeof runMiddleware === "function") {
696
- const result = await runMiddleware(webRequest);
696
+ const result = await runMiddleware(webRequest, undefined);
697
697
  if (!result.continue) {
698
698
  if (result.redirectUrl) {
699
- res.writeHead(result.redirectStatus ?? 307, {
699
+ const redirectHeaders = {
700
700
  Location: result.redirectUrl,
701
- });
701
+ };
702
+ if (result.responseHeaders) {
703
+ for (const [key, value] of result.responseHeaders) {
704
+ const existing = redirectHeaders[key];
705
+ if (existing === undefined) {
706
+ redirectHeaders[key] = value;
707
+ }
708
+ else if (Array.isArray(existing)) {
709
+ existing.push(value);
710
+ }
711
+ else {
712
+ redirectHeaders[key] = [existing, value];
713
+ }
714
+ }
715
+ }
716
+ res.writeHead(result.redirectStatus ?? 307, redirectHeaders);
702
717
  res.end();
703
718
  return;
704
719
  }
@@ -750,31 +765,19 @@ async function startPagesRouterServer(options) {
750
765
  // (e.g. NextResponse.rewrite(url, { status: 403 }))
751
766
  middlewareRewriteStatus = result.rewriteStatus;
752
767
  }
753
- // Unpack x-middleware-request-* headers into the actual request so that
754
- // renderPage / handleApiRoute see the middleware-modified headers.
755
- // Strip ALL x-middleware-* headers from the response this prefix is
756
- // reserved for internal routing signals and must never reach clients.
757
- // (Matches Next.js behavior where x-middleware-* headers are internal.)
758
- const mwReqPrefix = "x-middleware-request-";
759
- for (const key of Object.keys(middlewareHeaders)) {
760
- if (key.startsWith(mwReqPrefix)) {
761
- const realName = key.slice(mwReqPrefix.length);
762
- webRequest.headers.set(realName, middlewareHeaders[key]);
763
- delete middlewareHeaders[key];
764
- }
765
- else if (key.startsWith("x-middleware-")) {
766
- delete middlewareHeaders[key];
767
- }
768
- }
769
- // Rebuild context after middleware has unpacked x-middleware-request-*
770
- // headers into webRequest. Used only for afterFiles and fallback rewrites,
771
- // which run after middleware in the App Router execution order.
772
- const postMwReqCtx = requestContextFromRequest(webRequest);
768
+ // Unpack x-middleware-request-* headers into the actual request and strip
769
+ // all x-middleware-* internal signals. Rebuilds postMwReqCtx for use by
770
+ // beforeFiles, afterFiles, and fallback config rules (which run after
771
+ // middleware per the Next.js execution order).
772
+ const { postMwReqCtx, request: postMwReq } = applyMiddlewareRequestHeaders(middlewareHeaders, webRequest);
773
+ webRequest = postMwReq;
773
774
  let resolvedPathname = resolvedUrl.split("?")[0];
774
775
  // ── 5. Apply custom headers from next.config.js ───────────────
775
776
  // Config headers are additive for multi-value headers (Vary,
776
777
  // Set-Cookie) and override for everything else. Set-Cookie values
777
778
  // are stored as arrays (RFC 6265 forbids comma-joining cookies).
779
+ // Middleware headers take precedence: skip config keys already set
780
+ // by middleware so middleware always wins for the same key.
778
781
  if (configHeaders.length) {
779
782
  const matched = matchHeaders(resolvedPathname, configHeaders, reqCtx);
780
783
  for (const h of matched) {
@@ -794,7 +797,9 @@ async function startPagesRouterServer(options) {
794
797
  else if (lk === "vary" && middlewareHeaders[lk]) {
795
798
  middlewareHeaders[lk] += ", " + h.value;
796
799
  }
797
- else {
800
+ else if (!(lk in middlewareHeaders)) {
801
+ // Middleware headers take precedence: only set if middleware
802
+ // did not already place this key on the response.
798
803
  middlewareHeaders[lk] = h.value;
799
804
  }
800
805
  }