@reckona/mreact-router 0.0.152 → 0.0.154

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 (105) hide show
  1. package/README.md +1 -1
  2. package/dist/actions.d.ts +10 -0
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +6 -0
  5. package/dist/actions.js.map +1 -1
  6. package/dist/adapters/aws-lambda.d.ts +18 -0
  7. package/dist/adapters/aws-lambda.d.ts.map +1 -1
  8. package/dist/adapters/aws-lambda.js +18 -0
  9. package/dist/adapters/aws-lambda.js.map +1 -1
  10. package/dist/adapters/cloudflare.d.ts +33 -0
  11. package/dist/adapters/cloudflare.d.ts.map +1 -1
  12. package/dist/adapters/cloudflare.js +33 -0
  13. package/dist/adapters/cloudflare.js.map +1 -1
  14. package/dist/adapters/edge.d.ts +5 -0
  15. package/dist/adapters/edge.d.ts.map +1 -1
  16. package/dist/adapters/edge.js +5 -0
  17. package/dist/adapters/edge.js.map +1 -1
  18. package/dist/adapters/node.d.ts +5 -0
  19. package/dist/adapters/node.d.ts.map +1 -1
  20. package/dist/adapters/node.js +5 -0
  21. package/dist/adapters/node.js.map +1 -1
  22. package/dist/adapters/static.d.ts +5 -0
  23. package/dist/adapters/static.d.ts.map +1 -1
  24. package/dist/adapters/static.js +5 -0
  25. package/dist/adapters/static.js.map +1 -1
  26. package/dist/build.d.ts +15 -0
  27. package/dist/build.d.ts.map +1 -1
  28. package/dist/build.js +85 -2
  29. package/dist/build.js.map +1 -1
  30. package/dist/cache.d.ts +15 -0
  31. package/dist/cache.d.ts.map +1 -1
  32. package/dist/cache.js +15 -0
  33. package/dist/cache.js.map +1 -1
  34. package/dist/cookies.d.ts +16 -0
  35. package/dist/cookies.d.ts.map +1 -1
  36. package/dist/cookies.js +16 -0
  37. package/dist/cookies.js.map +1 -1
  38. package/dist/dev-server.d.ts +5 -0
  39. package/dist/dev-server.d.ts.map +1 -1
  40. package/dist/dev-server.js +5 -0
  41. package/dist/dev-server.js.map +1 -1
  42. package/dist/link.d.ts +10 -0
  43. package/dist/link.d.ts.map +1 -1
  44. package/dist/link.js +5 -0
  45. package/dist/link.js.map +1 -1
  46. package/dist/middleware.d.ts.map +1 -1
  47. package/dist/middleware.js +39 -4
  48. package/dist/middleware.js.map +1 -1
  49. package/dist/module-runner.d.ts +6 -0
  50. package/dist/module-runner.d.ts.map +1 -1
  51. package/dist/module-runner.js +71 -0
  52. package/dist/module-runner.js.map +1 -1
  53. package/dist/navigation.d.ts +53 -0
  54. package/dist/navigation.d.ts.map +1 -1
  55. package/dist/navigation.js +48 -0
  56. package/dist/navigation.js.map +1 -1
  57. package/dist/render.d.ts +34 -0
  58. package/dist/render.d.ts.map +1 -1
  59. package/dist/render.js +161 -27
  60. package/dist/render.js.map +1 -1
  61. package/dist/route-module-loader.d.ts +6 -1
  62. package/dist/route-module-loader.d.ts.map +1 -1
  63. package/dist/route-module-loader.js +8 -1
  64. package/dist/route-module-loader.js.map +1 -1
  65. package/dist/serve.d.ts +5 -0
  66. package/dist/serve.d.ts.map +1 -1
  67. package/dist/serve.js +5 -0
  68. package/dist/serve.js.map +1 -1
  69. package/dist/session.d.ts +19 -0
  70. package/dist/session.d.ts.map +1 -1
  71. package/dist/session.js +19 -0
  72. package/dist/session.js.map +1 -1
  73. package/dist/typed-routes.d.ts +5 -0
  74. package/dist/typed-routes.d.ts.map +1 -1
  75. package/dist/typed-routes.js +5 -0
  76. package/dist/typed-routes.js.map +1 -1
  77. package/dist/types.d.ts +15 -0
  78. package/dist/types.d.ts.map +1 -1
  79. package/dist/types.js +5 -0
  80. package/dist/types.js.map +1 -1
  81. package/dist/vite.d.ts.map +1 -1
  82. package/dist/vite.js +1 -0
  83. package/dist/vite.js.map +1 -1
  84. package/package.json +11 -11
  85. package/src/actions.ts +18 -0
  86. package/src/adapters/aws-lambda.ts +18 -0
  87. package/src/adapters/cloudflare.ts +33 -0
  88. package/src/adapters/edge.ts +5 -0
  89. package/src/adapters/node.ts +5 -0
  90. package/src/adapters/static.ts +5 -0
  91. package/src/build.ts +118 -1
  92. package/src/cache.ts +15 -0
  93. package/src/cookies.ts +16 -0
  94. package/src/dev-server.ts +5 -0
  95. package/src/link.ts +10 -0
  96. package/src/middleware.ts +54 -4
  97. package/src/module-runner.ts +91 -0
  98. package/src/navigation.ts +53 -0
  99. package/src/render.ts +229 -25
  100. package/src/route-module-loader.ts +15 -0
  101. package/src/serve.ts +5 -0
  102. package/src/session.ts +19 -0
  103. package/src/typed-routes.ts +5 -0
  104. package/src/types.ts +15 -0
  105. package/src/vite.ts +1 -0
@@ -46,6 +46,11 @@ function throwUnsafeRedirect(location) {
46
46
  function throwUnsafeRewrite(location) {
47
47
  throw new TypeError(`unsafe rewrite target: ${JSON.stringify(location)}`);
48
48
  }
49
+ /**
50
+ * Throws an internal redirect for loaders, middleware, route handlers, or server actions.
51
+ *
52
+ * The target must be same-origin or relative; use `redirectExternal()` for trusted `http` or `https` destinations. The default status is `303`.
53
+ */
49
54
  export function redirect(location, options = {}) {
50
55
  if (!isSafeInternalRedirect(location)) {
51
56
  throwUnsafeRedirect(location);
@@ -56,6 +61,11 @@ export function redirect(location, options = {}) {
56
61
  status: options.status ?? 303,
57
62
  });
58
63
  }
64
+ /**
65
+ * Throws an external redirect for trusted `http` or `https` destinations.
66
+ *
67
+ * This helper is intentionally separate from `redirect()` so off-site navigation is explicit. The default status is `307`.
68
+ */
59
69
  export function redirectExternal(location, options = {}) {
60
70
  if (!isSafeExternalRedirect(location)) {
61
71
  throwUnsafeRedirect(location);
@@ -66,6 +76,11 @@ export function redirectExternal(location, options = {}) {
66
76
  status: options.status ?? 307,
67
77
  });
68
78
  }
79
+ /**
80
+ * Creates a same-origin `303 See Other` redirect response.
81
+ *
82
+ * Use this from route handlers when returning a `Response` is more convenient than throwing through the app-router control flow.
83
+ */
69
84
  export function redirect303(location, init = {}) {
70
85
  if (!isSafeInternalRedirect(location)) {
71
86
  throwUnsafeRedirect(location);
@@ -78,6 +93,9 @@ export function redirect303(location, init = {}) {
78
93
  status: 303,
79
94
  });
80
95
  }
96
+ /**
97
+ * Creates a plain-text error response with a default `text/plain` content type.
98
+ */
81
99
  export function textError(message, status = 400, init = {}) {
82
100
  const headers = new Headers(init.headers);
83
101
  if (!headers.has("content-type")) {
@@ -93,18 +111,34 @@ export async function parseForm(request, schema) {
93
111
  const form = await request.formData();
94
112
  return schema === undefined ? form : schema.parse(form);
95
113
  }
114
+ /**
115
+ * Throws a route-level 404 control error.
116
+ *
117
+ * Use this from loaders, metadata, middleware, or route handlers when the matched route is valid but the requested resource is absent.
118
+ */
96
119
  export function notFound() {
97
120
  throw Object.assign(new Error("Not Found"), {
98
121
  name: notFoundErrorName,
99
122
  status: 404,
100
123
  });
101
124
  }
125
+ /**
126
+ * Alias for `notFound()` for codebases that prefer an explicit throwing helper name.
127
+ */
102
128
  export function throwNotFound() {
103
129
  return notFound();
104
130
  }
131
+ /**
132
+ * Continues middleware processing without changing the request.
133
+ */
105
134
  export function next() {
106
135
  return undefined;
107
136
  }
137
+ /**
138
+ * Creates an internal rewrite response consumed by app-router middleware.
139
+ *
140
+ * The target must be a same-origin route path, query, hash, or relative URL; protocol-relative, external, and control-character targets are rejected.
141
+ */
108
142
  export function rewrite(location, init = {}) {
109
143
  if (!isSafeInternalRedirect(location)) {
110
144
  throwUnsafeRewrite(location);
@@ -120,9 +154,15 @@ export function rewrite(location, init = {}) {
120
154
  });
121
155
  return response;
122
156
  }
157
+ /**
158
+ * Creates a JSON response using the platform `Response.json()` implementation.
159
+ */
123
160
  export function json(value, init) {
124
161
  return Response.json(value, init);
125
162
  }
163
+ /**
164
+ * Creates an HTML response and defaults the content type to `text/html; charset=utf-8`.
165
+ */
126
166
  export function html(value, init = {}) {
127
167
  if (init.headers === undefined) {
128
168
  return new Response(value, {
@@ -139,9 +179,17 @@ export function html(value, init = {}) {
139
179
  headers,
140
180
  });
141
181
  }
182
+ /**
183
+ * Returns the request headers object for route code that follows app-router helper naming.
184
+ */
142
185
  export function headers(request) {
143
186
  return request.headers;
144
187
  }
188
+ /**
189
+ * Parses request cookies into a small read-only helper.
190
+ *
191
+ * Values are decoded with `decodeURIComponent`; malformed encoded values are ignored rather than throwing during request handling.
192
+ */
145
193
  export function cookies(request) {
146
194
  let values;
147
195
  const cookieValues = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,iBAAiB,GAAG,gBAAgB,CAAC;AAC3C,MAAM,iBAAiB,GAAG,gBAAgB,CAAC;AAC3C,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAC7C,MAAM,qBAAqB,GAAG,MAAM,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;AAY1E,uEAAuE;AACvE,uEAAuE;AACvE,sEAAsE;AACtE,SAAS,+BAA+B,CAAC,KAAa;IACpD,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,OAAO,KAAK,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;QAC/D,KAAK,IAAI,CAAC,CAAC;IACb,CAAC;IAED,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,8EAA8E;AAC9E,0EAA0E;AAC1E,+EAA+E;AAC/E,uEAAuE;AACvE,SAAS,sBAAsB,CAAC,QAAgB;IAC9C,MAAM,OAAO,GAAG,+BAA+B,CAAC,QAAQ,CAAC,CAAC;IAC1D,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IACjC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3C,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3C,sDAAsD;IACtD,IAAI,2BAA2B,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,sBAAsB,CAAC,QAAgB;IAC9C,MAAM,OAAO,GAAG,+BAA+B,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,6BAA6B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1D,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC3D,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACtC,OAAO,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,OAAO,CAAC;AACjD,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAgB;IAC3C,MAAM,IAAI,SAAS,CACjB,2BAA2B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,mFAAmF,CACvI,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,MAAM,IAAI,SAAS,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,QAAgB,EAAE,UAA2B,EAAE;IACtE,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IACD,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,eAAe,QAAQ,EAAE,CAAC,EAAE;QACxD,QAAQ;QACR,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,GAAG;KAC9B,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,QAAgB,EAChB,UAA2B,EAAE;IAE7B,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IACD,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,eAAe,QAAQ,EAAE,CAAC,EAAE;QACxD,QAAQ;QACR,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,GAAG;KAC9B,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,OAAqB,EAAE;IACnE,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAElC,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;QACxB,GAAG,IAAI;QACP,OAAO;QACP,MAAM,EAAE,GAAG;KACZ,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,MAAM,GAAG,GAAG,EAAE,OAAqB,EAAE;IAC9E,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE1C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,2BAA2B,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE;QAC3B,GAAG,IAAI;QACP,OAAO;QACP,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAID,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAgB,EAChB,MAAuB;IAEvB,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;IAEtC,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,EAAE;QAC1C,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,GAAG;KACZ,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,QAAQ,EAAE,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,QAAgB,EAAE,OAAqB,EAAE;IAC/D,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE;QAClC,GAAG,IAAI;QACP,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,GAAG;KAC3B,CAAC,CAAC;IAEH,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,qBAAqB,EAAE;QACrD,YAAY,EAAE,KAAK;QACnB,UAAU,EAAE,KAAK;QACjB,KAAK,EAAE,QAAQ;KAChB,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,KAAc,EAAE,IAAmB;IACtD,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,KAAa,EAAE,OAAqB,EAAE;IACzD,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,IAAI,QAAQ,CAAC,KAAK,EAAE;YACzB,GAAG,IAAI;YACP,OAAO,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE;SACxD,CAAC,CAAC;IACL,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE1C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,0BAA0B,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,IAAI,QAAQ,CAAC,KAAK,EAAE;QACzB,GAAG,IAAI;QACP,OAAO;KACR,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAgB;IACtC,OAAO,OAAO,CAAC,OAAO,CAAC;AACzB,CAAC;AAQD,MAAM,UAAU,OAAO,CAAC,OAAgB;IACtC,IAAI,MAA+C,CAAC;IACpD,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,MAAM,KAAK,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC5D,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE;QACvC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;QACvC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;KACxC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAkB;IAChD,MAAM,MAAM,GAAI,QAAkD,CAAC,qBAAqB,CAAC,CAAC;IAC1F,MAAM,SAAS,GAAG,OAAO,MAAM,KAAK,QAAQ;QAC1C,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,SAAS,CAAC;IAEzD,OAAO,SAAS,KAAK,SAAS,IAAI,sBAAsB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9F,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,KAAK,YAAY,KAAK;QAC3B,KAAK,CAAC,IAAI,KAAK,iBAAiB;QAChC,OAAQ,KAAgC,CAAC,QAAQ,KAAK,QAAQ,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB,CAAC;AACpE,CAAC","sourcesContent":["import { parseCookieHeader } from \"./cookies.js\";\n\nconst redirectErrorName = \"MReactRedirect\";\nconst notFoundErrorName = \"MReactNotFound\";\nconst rewriteHeaderName = \"x-mreact-rewrite\";\nconst rewriteLocationSymbol = Symbol.for(\"mreact.router.rewriteLocation\");\n\nexport interface RedirectOptions {\n status?: 301 | 302 | 303 | 307 | 308;\n}\n\nexport type MiddlewareNext = undefined;\n\nexport interface ParseSchema<T> {\n parse(value: FormData): T;\n}\n\n// Strip leading C0 controls + ASCII whitespace per WHATWG URL parsing.\n// Browsers ignore these characters when resolving the Location header,\n// so attacker payloads must be rejected after the same normalization.\nfunction stripLeadingControlOrWhitespace(value: string): string {\n let start = 0;\n\n while (start < value.length && value.charCodeAt(start) <= 0x20) {\n start += 1;\n }\n\n return value.slice(start);\n}\n\n// Returns true if `location` is safe to use as a same-origin Location header.\n// Allowed: path-absolute (`/foo`), query-only (`?x=1`), hash-only (`#x`),\n// relative (`foo`). Rejected: protocol-relative (`//evil`), backslash variants\n// (`/\\evil`, `\\\\evil`), and anything with a scheme like `javascript:`.\nfunction isSafeInternalRedirect(location: string): boolean {\n const trimmed = stripLeadingControlOrWhitespace(location);\n if (trimmed === \"\") return false;\n if (trimmed.startsWith(\"//\")) return false;\n if (trimmed.startsWith(\"/\\\\\")) return false;\n if (trimmed.startsWith(\"\\\\\")) return false;\n // Reject anything that parses as a URL with a scheme.\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) return false;\n return true;\n}\n\nfunction isSafeExternalRedirect(location: string): boolean {\n const trimmed = stripLeadingControlOrWhitespace(location);\n const match = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(trimmed);\n if (match === null || match[1] === undefined) return false;\n const scheme = match[1].toLowerCase();\n return scheme === \"http\" || scheme === \"https\";\n}\n\nfunction throwUnsafeRedirect(location: string): never {\n throw new TypeError(\n `unsafe redirect target: ${JSON.stringify(location)} - use redirectExternal() for off-site destinations and ensure the URL is http(s)`,\n );\n}\n\nfunction throwUnsafeRewrite(location: string): never {\n throw new TypeError(`unsafe rewrite target: ${JSON.stringify(location)}`);\n}\n\nexport function redirect(location: string, options: RedirectOptions = {}): never {\n if (!isSafeInternalRedirect(location)) {\n throwUnsafeRedirect(location);\n }\n throw Object.assign(new Error(`Redirect to ${location}`), {\n location,\n name: redirectErrorName,\n status: options.status ?? 303,\n });\n}\n\nexport function redirectExternal(\n location: string,\n options: RedirectOptions = {},\n): never {\n if (!isSafeExternalRedirect(location)) {\n throwUnsafeRedirect(location);\n }\n throw Object.assign(new Error(`Redirect to ${location}`), {\n location,\n name: redirectErrorName,\n status: options.status ?? 307,\n });\n}\n\nexport function redirect303(location: string, init: ResponseInit = {}): Response {\n if (!isSafeInternalRedirect(location)) {\n throwUnsafeRedirect(location);\n }\n\n const headers = new Headers(init.headers);\n headers.set(\"location\", location);\n\n return new Response(null, {\n ...init,\n headers,\n status: 303,\n });\n}\n\nexport function textError(message: string, status = 400, init: ResponseInit = {}): Response {\n const headers = new Headers(init.headers);\n\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"text/plain; charset=utf-8\");\n }\n\n return new Response(message, {\n ...init,\n headers,\n status,\n });\n}\n\nexport async function parseForm(request: Request): Promise<FormData>;\nexport async function parseForm<T>(request: Request, schema: ParseSchema<T>): Promise<T>;\nexport async function parseForm<T>(\n request: Request,\n schema?: ParseSchema<T>,\n): Promise<FormData | T> {\n const form = await request.formData();\n\n return schema === undefined ? form : schema.parse(form);\n}\n\nexport function notFound(): never {\n throw Object.assign(new Error(\"Not Found\"), {\n name: notFoundErrorName,\n status: 404,\n });\n}\n\nexport function throwNotFound(): never {\n return notFound();\n}\n\nexport function next(): MiddlewareNext {\n return undefined;\n}\n\nexport function rewrite(location: string, init: ResponseInit = {}): Response {\n if (!isSafeInternalRedirect(location)) {\n throwUnsafeRewrite(location);\n }\n\n const response = new Response(null, {\n ...init,\n status: init.status ?? 200,\n });\n\n Object.defineProperty(response, rewriteLocationSymbol, {\n configurable: false,\n enumerable: false,\n value: location,\n });\n\n return response;\n}\n\nexport function json(value: unknown, init?: ResponseInit): Response {\n return Response.json(value, init);\n}\n\nexport function html(value: string, init: ResponseInit = {}): Response {\n if (init.headers === undefined) {\n return new Response(value, {\n ...init,\n headers: { \"content-type\": \"text/html; charset=utf-8\" },\n });\n }\n\n const headers = new Headers(init.headers);\n\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"text/html; charset=utf-8\");\n }\n\n return new Response(value, {\n ...init,\n headers,\n });\n}\n\nexport function headers(request: Request): Headers {\n return request.headers;\n}\n\nexport interface RequestCookies {\n entries(): IterableIterator<[string, string]>;\n get(name: string): string | undefined;\n has(name: string): boolean;\n}\n\nexport function cookies(request: Request): RequestCookies {\n let values: ReadonlyMap<string, string> | undefined;\n const cookieValues = () => {\n values ??= parseCookieHeader(request.headers.get(\"cookie\"));\n return values;\n };\n\n return {\n entries: () => cookieValues().entries(),\n get: (name) => cookieValues().get(name),\n has: (name) => cookieValues().has(name),\n };\n}\n\nexport function rewriteLocation(response: Response): string | undefined {\n const marked = (response as { [rewriteLocationSymbol]?: unknown })[rewriteLocationSymbol];\n const candidate = typeof marked === \"string\"\n ? marked\n : response.headers.get(rewriteHeaderName) ?? undefined;\n\n return candidate !== undefined && isSafeInternalRedirect(candidate) ? candidate : undefined;\n}\n\nexport function isRedirectError(error: unknown): error is Error & { location: string; status: number } {\n return error instanceof Error &&\n error.name === redirectErrorName &&\n typeof (error as { location?: unknown }).location === \"string\";\n}\n\nexport function isNotFoundError(error: unknown): boolean {\n return error instanceof Error && error.name === notFoundErrorName;\n}\n"]}
1
+ {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseCookieHeader } from \"./cookies.js\";\n\nconst redirectErrorName = \"MReactRedirect\";\nconst notFoundErrorName = \"MReactNotFound\";\nconst rewriteHeaderName = \"x-mreact-rewrite\";\nconst rewriteLocationSymbol = Symbol.for(\"mreact.router.rewriteLocation\");\n\nexport interface RedirectOptions {\n status?: 301 | 302 | 303 | 307 | 308;\n}\n\nexport type MiddlewareNext = undefined;\n\nexport interface ParseSchema<T> {\n parse(value: FormData): T;\n}\n\n// Strip leading C0 controls + ASCII whitespace per WHATWG URL parsing.\n// Browsers ignore these characters when resolving the Location header,\n// so attacker payloads must be rejected after the same normalization.\nfunction stripLeadingControlOrWhitespace(value: string): string {\n let start = 0;\n\n while (start < value.length && value.charCodeAt(start) <= 0x20) {\n start += 1;\n }\n\n return value.slice(start);\n}\n\n// Returns true if `location` is safe to use as a same-origin Location header.\n// Allowed: path-absolute (`/foo`), query-only (`?x=1`), hash-only (`#x`),\n// relative (`foo`). Rejected: protocol-relative (`//evil`), backslash variants\n// (`/\\evil`, `\\\\evil`), and anything with a scheme like `javascript:`.\nfunction isSafeInternalRedirect(location: string): boolean {\n const trimmed = stripLeadingControlOrWhitespace(location);\n if (trimmed === \"\") return false;\n if (trimmed.startsWith(\"//\")) return false;\n if (trimmed.startsWith(\"/\\\\\")) return false;\n if (trimmed.startsWith(\"\\\\\")) return false;\n // Reject anything that parses as a URL with a scheme.\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) return false;\n return true;\n}\n\nfunction isSafeExternalRedirect(location: string): boolean {\n const trimmed = stripLeadingControlOrWhitespace(location);\n const match = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(trimmed);\n if (match === null || match[1] === undefined) return false;\n const scheme = match[1].toLowerCase();\n return scheme === \"http\" || scheme === \"https\";\n}\n\nfunction throwUnsafeRedirect(location: string): never {\n throw new TypeError(\n `unsafe redirect target: ${JSON.stringify(location)} - use redirectExternal() for off-site destinations and ensure the URL is http(s)`,\n );\n}\n\nfunction throwUnsafeRewrite(location: string): never {\n throw new TypeError(`unsafe rewrite target: ${JSON.stringify(location)}`);\n}\n\n/**\n * Throws an internal redirect for loaders, middleware, route handlers, or server actions.\n *\n * The target must be same-origin or relative; use `redirectExternal()` for trusted `http` or `https` destinations. The default status is `303`.\n */\nexport function redirect(location: string, options: RedirectOptions = {}): never {\n if (!isSafeInternalRedirect(location)) {\n throwUnsafeRedirect(location);\n }\n throw Object.assign(new Error(`Redirect to ${location}`), {\n location,\n name: redirectErrorName,\n status: options.status ?? 303,\n });\n}\n\n/**\n * Throws an external redirect for trusted `http` or `https` destinations.\n *\n * This helper is intentionally separate from `redirect()` so off-site navigation is explicit. The default status is `307`.\n */\nexport function redirectExternal(\n location: string,\n options: RedirectOptions = {},\n): never {\n if (!isSafeExternalRedirect(location)) {\n throwUnsafeRedirect(location);\n }\n throw Object.assign(new Error(`Redirect to ${location}`), {\n location,\n name: redirectErrorName,\n status: options.status ?? 307,\n });\n}\n\n/**\n * Creates a same-origin `303 See Other` redirect response.\n *\n * Use this from route handlers when returning a `Response` is more convenient than throwing through the app-router control flow.\n */\nexport function redirect303(location: string, init: ResponseInit = {}): Response {\n if (!isSafeInternalRedirect(location)) {\n throwUnsafeRedirect(location);\n }\n\n const headers = new Headers(init.headers);\n headers.set(\"location\", location);\n\n return new Response(null, {\n ...init,\n headers,\n status: 303,\n });\n}\n\n/**\n * Creates a plain-text error response with a default `text/plain` content type.\n */\nexport function textError(message: string, status = 400, init: ResponseInit = {}): Response {\n const headers = new Headers(init.headers);\n\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"text/plain; charset=utf-8\");\n }\n\n return new Response(message, {\n ...init,\n headers,\n status,\n });\n}\n\n/**\n * Reads `request.formData()` and optionally validates it with a schema-like parser.\n *\n * Pass a schema object with `parse(FormData)` when a route handler or server action should receive typed form data.\n */\nexport async function parseForm(request: Request): Promise<FormData>;\nexport async function parseForm<T>(request: Request, schema: ParseSchema<T>): Promise<T>;\nexport async function parseForm<T>(\n request: Request,\n schema?: ParseSchema<T>,\n): Promise<FormData | T> {\n const form = await request.formData();\n\n return schema === undefined ? form : schema.parse(form);\n}\n\n/**\n * Throws a route-level 404 control error.\n *\n * Use this from loaders, metadata, middleware, or route handlers when the matched route is valid but the requested resource is absent.\n */\nexport function notFound(): never {\n throw Object.assign(new Error(\"Not Found\"), {\n name: notFoundErrorName,\n status: 404,\n });\n}\n\n/**\n * Alias for `notFound()` for codebases that prefer an explicit throwing helper name.\n */\nexport function throwNotFound(): never {\n return notFound();\n}\n\n/**\n * Continues middleware processing without changing the request.\n */\nexport function next(): MiddlewareNext {\n return undefined;\n}\n\n/**\n * Creates an internal rewrite response consumed by app-router middleware.\n *\n * The target must be a same-origin route path, query, hash, or relative URL; protocol-relative, external, and control-character targets are rejected.\n */\nexport function rewrite(location: string, init: ResponseInit = {}): Response {\n if (!isSafeInternalRedirect(location)) {\n throwUnsafeRewrite(location);\n }\n\n const response = new Response(null, {\n ...init,\n status: init.status ?? 200,\n });\n\n Object.defineProperty(response, rewriteLocationSymbol, {\n configurable: false,\n enumerable: false,\n value: location,\n });\n\n return response;\n}\n\n/**\n * Creates a JSON response using the platform `Response.json()` implementation.\n */\nexport function json(value: unknown, init?: ResponseInit): Response {\n return Response.json(value, init);\n}\n\n/**\n * Creates an HTML response and defaults the content type to `text/html; charset=utf-8`.\n */\nexport function html(value: string, init: ResponseInit = {}): Response {\n if (init.headers === undefined) {\n return new Response(value, {\n ...init,\n headers: { \"content-type\": \"text/html; charset=utf-8\" },\n });\n }\n\n const headers = new Headers(init.headers);\n\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"text/html; charset=utf-8\");\n }\n\n return new Response(value, {\n ...init,\n headers,\n });\n}\n\n/**\n * Returns the request headers object for route code that follows app-router helper naming.\n */\nexport function headers(request: Request): Headers {\n return request.headers;\n}\n\nexport interface RequestCookies {\n entries(): IterableIterator<[string, string]>;\n get(name: string): string | undefined;\n has(name: string): boolean;\n}\n\n/**\n * Parses request cookies into a small read-only helper.\n *\n * Values are decoded with `decodeURIComponent`; malformed encoded values are ignored rather than throwing during request handling.\n */\nexport function cookies(request: Request): RequestCookies {\n let values: ReadonlyMap<string, string> | undefined;\n const cookieValues = () => {\n values ??= parseCookieHeader(request.headers.get(\"cookie\"));\n return values;\n };\n\n return {\n entries: () => cookieValues().entries(),\n get: (name) => cookieValues().get(name),\n has: (name) => cookieValues().has(name),\n };\n}\n\nexport function rewriteLocation(response: Response): string | undefined {\n const marked = (response as { [rewriteLocationSymbol]?: unknown })[rewriteLocationSymbol];\n const candidate = typeof marked === \"string\"\n ? marked\n : response.headers.get(rewriteHeaderName) ?? undefined;\n\n return candidate !== undefined && isSafeInternalRedirect(candidate) ? candidate : undefined;\n}\n\nexport function isRedirectError(error: unknown): error is Error & { location: string; status: number } {\n return error instanceof Error &&\n error.name === redirectErrorName &&\n typeof (error as { location?: unknown }).location === \"string\";\n}\n\nexport function isNotFoundError(error: unknown): boolean {\n return error instanceof Error && error.name === notFoundErrorName;\n}\n"]}
package/dist/render.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { ServerOutputMode, TransformOutput } from "@reckona/mreact-shared/compiler-contract";
1
2
  import { type QueryClient } from "@reckona/mreact-query";
2
3
  import { type ClientRouteInferenceCache } from "./client-route-inference.js";
3
4
  import type { AppRoute, MatchedRoute, RouteMatcher } from "./routes.js";
@@ -36,6 +37,7 @@ export interface RenderAppRequestOptions {
36
37
  routes?: readonly AppRoute[] | undefined;
37
38
  serverModules?: ReadonlyMap<string, BuiltServerModuleArtifact> | undefined;
38
39
  serverModuleCacheVersion?: string | undefined;
40
+ dev?: boolean | undefined;
39
41
  serverSourceFiles?: ReadonlyMap<string, string> | undefined;
40
42
  serverActions?: AppRouterServerActionOptions | undefined;
41
43
  serverActionReferencesByFile?: ReadonlyMap<string, readonly PreparedFormActionReference[]> | undefined;
@@ -92,6 +94,21 @@ export declare function bundleMiddlewareModuleCode(options: {
92
94
  importPolicy?: AppRouterImportPolicy | undefined;
93
95
  vitePlugins?: readonly PluginOption[] | undefined;
94
96
  }): Promise<string>;
97
+ declare function transformServerModule(options: {
98
+ code: string;
99
+ clientBoundaryImports?: readonly string[];
100
+ clientBoundaryFallbackImports?: readonly string[];
101
+ filename: string;
102
+ serverModules?: ReadonlyMap<string, BuiltServerModuleArtifact> | undefined;
103
+ serverOutput: ServerOutputMode;
104
+ serverAwaitHydration?: boolean;
105
+ }): TransformOutput;
106
+ export declare const __transformServerModuleForTesting: typeof transformServerModule;
107
+ export declare function __resetProductionRenderWarningsForTesting(): void;
108
+ export declare function __warnProductionRenderWithoutPrebuiltModulesForTesting(options: {
109
+ dev?: boolean | undefined;
110
+ serverModules?: ReadonlyMap<string, BuiltServerModuleArtifact> | undefined;
111
+ }): void;
95
112
  export declare function bundleRouteLoaderModuleCode(options: {
96
113
  appDir: string;
97
114
  code: string;
@@ -101,5 +118,22 @@ export declare function bundleRouteLoaderModuleCode(options: {
101
118
  importPolicy?: AppRouterImportPolicy | undefined;
102
119
  vitePlugins?: readonly PluginOption[] | undefined;
103
120
  }): Promise<string>;
121
+ declare function composedRouteMetadataCacheKey(options: {
122
+ appDir: string;
123
+ code: string;
124
+ define?: UserConfig["define"] | undefined;
125
+ filename: string;
126
+ importPolicy?: AppRouterImportPolicy | undefined;
127
+ serverModuleCacheVersion?: string | undefined;
128
+ vitePlugins?: readonly PluginOption[] | undefined;
129
+ }): string | undefined;
130
+ export declare const __composedRouteMetadataCacheKeyForTesting: typeof composedRouteMetadataCacheKey;
131
+ interface InlineCspTag {
132
+ attributes: ReadonlyMap<string, string>;
133
+ content: string;
134
+ name: "script" | "style";
135
+ }
136
+ declare function inlineCspTags(html: string): InlineCspTag[];
137
+ export declare const __inlineCspTagsForTesting: typeof inlineCspTags;
104
138
  export {};
105
139
  //# sourceMappingURL=render.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
package/dist/render.js CHANGED
@@ -29,7 +29,7 @@ import { invokeRouterInstrumentation, traceContextFromRequest, } from "./trace.j
29
29
  import { mergeRouteMiddlewareControls, middlewareMatches, parseRouteMiddlewareControl, parseStaticMiddlewareConfig, shouldSkipMiddleware, validateRouteMiddlewareControl, } from "./middleware.js";
30
30
  import { applyFileConventionMetadata, injectHeadMetadata, mergeRouteMetadata, responseHeadersForMetadata, serializeRobots, serializeSitemap, validateRouteMetadata, } from "./metadata.js";
31
31
  import { createSlotRenderContext, markShellBoundary, shellBoundaryId, splitLayoutSlot, warnUnconsumedRouteSlots, } from "./layout-composer.js";
32
- import { importPolicyCacheKey, memoizedHashText, prebuiltRequestModuleArtifact, prebuiltRouteLoaderModuleArtifact, prebuiltServerComponentModuleCode, prebuiltServerModuleOutputMatches, } from "./route-module-loader.js";
32
+ import { importPolicyCacheKey, memoizedHashText, prebuiltRequestModuleArtifact, prebuiltRouteLoaderModuleArtifact, prebuiltServerComponentModuleCode, prebuiltServerModuleOutputMatches, prebuiltServerModuleOutputOptionsMatch, } from "./route-module-loader.js";
33
33
  const nativeEscapeTransform = {
34
34
  batchImportName: "escapeHtmlBatch",
35
35
  batchImportSource: "@reckona/mreact-router/native-escape",
@@ -134,7 +134,7 @@ async function preloadBuiltPageRouteModules(options) {
134
134
  serverAwaitHydration: options.analysis.clientInference.client,
135
135
  });
136
136
  assertNoFatalServerDiagnostics(options.file, streamOutput.diagnostics);
137
- await loadServerStreamModule(streamOutput.code, options.file, options.serverModules, options.serverModuleCacheVersion, options.define, options.vitePlugins);
137
+ await loadServerStreamModule(streamOutput.code, options.file, options.serverModules, options.serverModuleCacheVersion, options.define, options.vitePlugins, undefined, { serverAwaitHydration: options.analysis.clientInference.client });
138
138
  }
139
139
  await preloadShellModulesForPage({
140
140
  appDir: options.appDir,
@@ -193,6 +193,7 @@ function assertNoFatalServerDiagnostics(filename, diagnostics) {
193
193
  }
194
194
  const serverTransformCache = new Map();
195
195
  const serverTransformCacheCounters = createRouterRuntimeCacheCounters();
196
+ const productionDynamicServerTransformWarned = new Set();
196
197
  const serverSourceFileCache = new Map();
197
198
  const serverSourceFileCacheCounters = createRouterRuntimeCacheCounters();
198
199
  const routeSourceAnalysisCache = new Map();
@@ -275,12 +276,25 @@ function finishRenderTimingPhase(timing, startedAt, phaseName) {
275
276
  }
276
277
  timing.phases[phaseName] = logDurationMs(startedAt);
277
278
  }
279
+ async function readSettledPromiseAtNextTask(promise) {
280
+ return await Promise.race([
281
+ promise.then((value) => ({ settled: true, value })),
282
+ new Promise((resolve) => {
283
+ setTimeout(() => resolve({ settled: false }), 0);
284
+ }),
285
+ ]);
286
+ }
278
287
  function addRenderTimingPhaseDuration(timing, startedAt, phaseName) {
279
288
  if (timing === undefined || startedAt === undefined) {
280
289
  return;
281
290
  }
282
291
  timing.phases[phaseName] = (timing.phases[phaseName] ?? 0) + logDurationMs(startedAt);
283
292
  }
293
+ function routeLoaderMayReturnControlResponse(code) {
294
+ return /\b(?:redirect|redirectExternal|rewrite|notFound|throwNotFound)\s*\(/.test(code) ||
295
+ /\bnew\s+Response\s*\(/.test(code) ||
296
+ /\bResponse\.(?:redirect|json)\s*\(/.test(code);
297
+ }
284
298
  async function waitForRenderPreload(options, timing) {
285
299
  if (options.preload?.wait !== "before-render") {
286
300
  return;
@@ -333,6 +347,7 @@ export async function resolveAppRouterMiddleware(options) {
333
347
  return { response: middlewareResponse, type: "response" };
334
348
  }
335
349
  async function renderAppRequestInternal(options) {
350
+ warnProductionRenderWithoutPrebuiltModules(options);
336
351
  const timing = createRenderTiming(options.logger);
337
352
  const clientRouteInferenceCache = options.clientRouteInferenceCache ?? createClientRouteInferenceCache();
338
353
  let phaseStartedAt = renderTimingPhaseStartedAt(timing);
@@ -413,6 +428,7 @@ async function renderAppRequestInternal(options) {
413
428
  appDir: options.appDir,
414
429
  filename: "not-found.mreact.tsx",
415
430
  pathname: url.pathname,
431
+ serverSourceFiles: options.serverSourceFiles,
416
432
  });
417
433
  const response = await renderSpecialRoute({
418
434
  appDir: options.appDir,
@@ -735,8 +751,9 @@ async function renderAppRequestInternal(options) {
735
751
  return response;
736
752
  }
737
753
  let streamData;
738
- if (loadingFile === undefined) {
739
- phaseStartedAt = renderTimingPhaseStartedAt(timing);
754
+ let streamDataPromise = dataPromise ?? Promise.resolve(undefined);
755
+ phaseStartedAt = renderTimingPhaseStartedAt(timing);
756
+ if (loadingFile === undefined || routeLoaderMayReturnControlResponse(code)) {
740
757
  try {
741
758
  streamData = dataPromise === undefined ? undefined : await dataPromise;
742
759
  }
@@ -747,6 +764,22 @@ async function renderAppRequestInternal(options) {
747
764
  emitRenderTiming(options, timing, streamData.status);
748
765
  return streamData;
749
766
  }
767
+ streamDataPromise = Promise.resolve(streamData);
768
+ }
769
+ else {
770
+ try {
771
+ const settledData = await readSettledPromiseAtNextTask(streamDataPromise);
772
+ if (settledData.settled) {
773
+ if (settledData.value instanceof Response) {
774
+ emitRenderTiming(options, timing, settledData.value.status);
775
+ return settledData.value;
776
+ }
777
+ streamDataPromise = Promise.resolve(settledData.value);
778
+ }
779
+ }
780
+ finally {
781
+ finishRenderTimingPhase(timing, phaseStartedAt, "loaderWaitMs");
782
+ }
750
783
  }
751
784
  await waitForRenderPreload(options, timing);
752
785
  await loadServerRenderArtifacts(options, matched.route.file, timing);
@@ -774,7 +807,7 @@ async function renderAppRequestInternal(options) {
774
807
  appDir: options.appDir,
775
808
  assetBaseUrl: options.assetBaseUrl,
776
809
  clientRoute,
777
- data: dataPromise ?? Promise.resolve(undefined),
810
+ data: streamDataPromise,
778
811
  define: options.define,
779
812
  loadingFile,
780
813
  pageFile: matched.route.file,
@@ -1149,17 +1182,24 @@ async function nearestBoundaryFileForPath(options) {
1149
1182
  const parts = options.pathname
1150
1183
  .replace(/^\/+|\/+$/g, "")
1151
1184
  .split("/")
1152
- .filter((part) => part.length > 0);
1153
- return nearestBoundaryFileFromParts({
1185
+ .filter((part) => part.length > 0 && part !== "." && part !== "..");
1186
+ return await nearestBoundaryFileFromParts({
1154
1187
  appDir: options.appDir,
1155
1188
  filename: options.filename,
1156
1189
  parts,
1190
+ serverSourceFiles: options.serverSourceFiles,
1157
1191
  });
1158
1192
  }
1159
1193
  async function nearestBoundaryFileFromParts(options) {
1160
1194
  for (let count = options.parts.length; count >= 0; count -= 1) {
1161
1195
  for (const filename of boundaryFilenameCandidates(options.filename)) {
1162
1196
  const candidate = join(options.appDir, ...options.parts.slice(0, count), filename);
1197
+ if (options.serverSourceFiles !== undefined) {
1198
+ if (options.serverSourceFiles.has(candidate)) {
1199
+ return candidate;
1200
+ }
1201
+ continue;
1202
+ }
1163
1203
  try {
1164
1204
  await access(candidate);
1165
1205
  return candidate;
@@ -1200,11 +1240,18 @@ function boundaryFilenameCandidates(filename) {
1200
1240
  return [standardFilename, filename];
1201
1241
  }
1202
1242
  async function renderSpecialRoute(options) {
1203
- try {
1204
- await access(options.routeFile);
1243
+ if (options.serverSourceFiles !== undefined) {
1244
+ if (!options.serverSourceFiles.has(options.routeFile)) {
1245
+ return new Response(options.textFallback, { status: options.status });
1246
+ }
1205
1247
  }
1206
- catch {
1207
- return new Response(options.textFallback, { status: options.status });
1248
+ else {
1249
+ try {
1250
+ await access(options.routeFile);
1251
+ }
1252
+ catch {
1253
+ return new Response(options.textFallback, { status: options.status });
1254
+ }
1208
1255
  }
1209
1256
  const props = {
1210
1257
  data: undefined,
@@ -1286,7 +1333,10 @@ async function dispatchServerRoute(options) {
1286
1333
  const module = await loadServerRouteModule(options);
1287
1334
  const handler = module[options.request.method] ?? module.ALL ?? module.default;
1288
1335
  if (typeof handler !== "function") {
1289
- return new Response("Method Not Allowed", { status: 405 });
1336
+ return new Response("Method Not Allowed", {
1337
+ headers: { allow: allowedServerRouteMethods(module).join(", ") },
1338
+ status: 405,
1339
+ });
1290
1340
  }
1291
1341
  let response;
1292
1342
  try {
@@ -1307,6 +1357,9 @@ async function dispatchServerRoute(options) {
1307
1357
  ? response
1308
1358
  : new Response("Invalid route response", { status: 500 });
1309
1359
  }
1360
+ function allowedServerRouteMethods(module) {
1361
+ return ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"].filter((method) => typeof module[method] === "function");
1362
+ }
1310
1363
  async function dispatchConventionAssetRoute(options) {
1311
1364
  if (options.request.method !== "GET" && options.request.method !== "HEAD") {
1312
1365
  return new Response("Method Not Allowed", {
@@ -1664,7 +1717,7 @@ function transformServerModule(options) {
1664
1717
  const artifact = options.serverModules?.get(options.filename)?.[options.serverOutput];
1665
1718
  if (artifact !== undefined &&
1666
1719
  artifact.sourceHash === sourceHash &&
1667
- options.serverAwaitHydration !== true) {
1720
+ prebuiltServerModuleOutputOptionsMatch(artifact, options.serverAwaitHydration === true ? { serverAwaitHydration: true } : {})) {
1668
1721
  return {
1669
1722
  code: artifact.code,
1670
1723
  diagnostics: [],
@@ -1690,6 +1743,15 @@ function transformServerModule(options) {
1690
1743
  if (cached !== undefined) {
1691
1744
  return cached;
1692
1745
  }
1746
+ // Only renders that were handed a prebuild map can have a prebuild gap;
1747
+ // dev servers pass no serverModules and transform at request time by design.
1748
+ if (options.serverModules !== undefined) {
1749
+ warnProductionDynamicServerTransform(options.filename, options.serverOutput, artifact === undefined
1750
+ ? "no prebuilt server module for this output mode"
1751
+ : !prebuiltServerModuleOutputOptionsMatch(artifact, options.serverAwaitHydration === true ? { serverAwaitHydration: true } : {})
1752
+ ? `serverAwaitHydration mismatch (artifact=${artifact.metadata?.serverAwaitHydration === true}, requested=${options.serverAwaitHydration === true})`
1753
+ : "stale prebuilt server module (source hash changed)");
1754
+ }
1693
1755
  const output = transform({
1694
1756
  code: options.code,
1695
1757
  ...(options.clientBoundaryImports === undefined
@@ -1708,6 +1770,39 @@ function transformServerModule(options) {
1708
1770
  setBoundedCacheEntry(serverTransformCache, key, output, maxServerTransformCacheEntries, serverTransformCacheCounters);
1709
1771
  return output;
1710
1772
  }
1773
+ export const __transformServerModuleForTesting = transformServerModule;
1774
+ let productionRenderWithoutPrebuiltModulesWarned = false;
1775
+ export function __resetProductionRenderWarningsForTesting() {
1776
+ productionRenderWithoutPrebuiltModulesWarned = false;
1777
+ productionDynamicServerTransformWarned.clear();
1778
+ }
1779
+ // Covers the deployment that forgot prebuilt modules entirely; per-module
1780
+ // gaps inside a provided prebuild map are reported by
1781
+ // warnProductionDynamicServerTransform with the affected file instead.
1782
+ export function __warnProductionRenderWithoutPrebuiltModulesForTesting(options) {
1783
+ warnProductionRenderWithoutPrebuiltModules(options);
1784
+ }
1785
+ function warnProductionRenderWithoutPrebuiltModules(options) {
1786
+ if (process.env.NODE_ENV !== "production" ||
1787
+ options.dev === true ||
1788
+ options.serverModules !== undefined ||
1789
+ productionRenderWithoutPrebuiltModulesWarned) {
1790
+ return;
1791
+ }
1792
+ productionRenderWithoutPrebuiltModulesWarned = true;
1793
+ console.warn("mreact router: production render without prebuilt serverModules. Request-time transforms use development compiler settings; pass the build output's serverModules (or set dev: true for dev servers).");
1794
+ }
1795
+ function warnProductionDynamicServerTransform(filename, serverOutput, reason) {
1796
+ if (process.env.NODE_ENV !== "production") {
1797
+ return;
1798
+ }
1799
+ const warnedKey = `${filename}\0${serverOutput}`;
1800
+ if (productionDynamicServerTransformWarned.has(warnedKey)) {
1801
+ return;
1802
+ }
1803
+ productionDynamicServerTransformWarned.add(warnedKey);
1804
+ console.warn(`mreact router: dynamic server transform path ran in production for ${filename} (serverOutput=${serverOutput}): ${reason}. Production deployments should provide prebuilt serverModules; otherwise request-time transforms use development compiler settings.`);
1805
+ }
1711
1806
  async function analyzeRouteSource(options) {
1712
1807
  const sourceHash = memoizedHashText(options.code);
1713
1808
  if (options.artifact !== undefined &&
@@ -2123,11 +2218,12 @@ async function renderServerStreamSlots(code, options) {
2123
2218
  function hasRouteSlotsExport(code) {
2124
2219
  return /^\s*export\s+const\s+slots\s*=/m.test(code);
2125
2220
  }
2126
- async function loadServerStreamModule(code, sourcefile, serverModules, serverModuleCacheVersion, define, vitePlugins, importPolicy) {
2221
+ async function loadServerStreamModule(code, sourcefile, serverModules, serverModuleCacheVersion, define, vitePlugins, importPolicy, outputOptions = {}) {
2127
2222
  const artifactCode = serverModules?.get(sourcefile)?.stream;
2128
2223
  const codeHash = memoizedHashText(code);
2129
- const prebuiltCode = prebuiltServerComponentModuleCode(artifactCode, code, codeHash);
2224
+ const prebuiltCode = prebuiltServerComponentModuleCode(artifactCode, code, codeHash, outputOptions);
2130
2225
  if (artifactCode !== undefined &&
2226
+ prebuiltServerModuleOutputOptionsMatch(artifactCode, outputOptions) &&
2131
2227
  prebuiltServerModuleOutputMatches(artifactCode, code, codeHash) &&
2132
2228
  artifactCode.moduleFile !== undefined) {
2133
2229
  return await importBuiltServerModuleFile({
@@ -2806,9 +2902,7 @@ async function bundleRouteMetadataModuleCode(options) {
2806
2902
  return code;
2807
2903
  }
2808
2904
  async function loadComposedRouteMetadata(options) {
2809
- const cacheKey = options.serverModuleCacheVersion === undefined
2810
- ? undefined
2811
- : `${options.appDir}\0${options.filename}\0${options.serverModuleCacheVersion}\0${memoizedHashText(options.code)}\0${viteDefineCacheKey(options.define)}\0${vitePluginsCacheKey(options.vitePlugins)}`;
2905
+ const cacheKey = composedRouteMetadataCacheKey(options);
2812
2906
  if (cacheKey !== undefined) {
2813
2907
  const cached = readRouterRuntimeCacheEntry(composedRouteMetadataCache, cacheKey, composedRouteMetadataCacheCounters);
2814
2908
  if (cached !== undefined) {
@@ -2829,6 +2923,12 @@ async function loadComposedRouteMetadata(options) {
2829
2923
  throw error;
2830
2924
  }
2831
2925
  }
2926
+ function composedRouteMetadataCacheKey(options) {
2927
+ return options.serverModuleCacheVersion === undefined
2928
+ ? undefined
2929
+ : `${options.appDir}\0${options.filename}\0${options.serverModuleCacheVersion}\0${memoizedHashText(options.code)}\0${importPolicyCacheKey(options.importPolicy)}\0${viteDefineCacheKey(options.define)}\0${vitePluginsCacheKey(options.vitePlugins)}`;
2930
+ }
2931
+ export const __composedRouteMetadataCacheKeyForTesting = composedRouteMetadataCacheKey;
2832
2932
  async function loadComposedRouteMetadataUncached(options) {
2833
2933
  const layoutFiles = await shellFilesForPage(options.appDir, options.filename, options.serverModuleCacheVersion);
2834
2934
  const metadata = [];
@@ -2951,21 +3051,47 @@ function cspDirectiveNonces(csp, directive) {
2951
3051
  }
2952
3052
  function inlineCspTags(html) {
2953
3053
  const tags = [];
2954
- const pattern = /<(script|style)\b([^>]*)>([\s\S]*?)<\/\1>/gi;
2955
- let match;
2956
- while ((match = pattern.exec(html)) !== null) {
2957
- const name = match[1]?.toLowerCase();
2958
- if (name !== "script" && name !== "style") {
3054
+ const lowerHtml = html.toLowerCase();
3055
+ let position = 0;
3056
+ while (position < html.length) {
3057
+ const scriptIndex = lowerHtml.indexOf("<script", position);
3058
+ const styleIndex = lowerHtml.indexOf("<style", position);
3059
+ const openerIndex = scriptIndex === -1
3060
+ ? styleIndex
3061
+ : styleIndex === -1
3062
+ ? scriptIndex
3063
+ : Math.min(scriptIndex, styleIndex);
3064
+ if (openerIndex === -1) {
3065
+ break;
3066
+ }
3067
+ const name = lowerHtml.startsWith("<script", openerIndex) ? "script" : "style";
3068
+ const tagEnd = html.indexOf(">", openerIndex + 1);
3069
+ if (tagEnd === -1) {
3070
+ break;
3071
+ }
3072
+ const closeToken = `</${name}>`;
3073
+ const closeIndex = lowerHtml.indexOf(closeToken, tagEnd + 1);
3074
+ const nextScriptIndex = lowerHtml.indexOf("<script", tagEnd + 1);
3075
+ const nextStyleIndex = lowerHtml.indexOf("<style", tagEnd + 1);
3076
+ const nextOpenerIndex = nextScriptIndex === -1
3077
+ ? nextStyleIndex
3078
+ : nextStyleIndex === -1
3079
+ ? nextScriptIndex
3080
+ : Math.min(nextScriptIndex, nextStyleIndex);
3081
+ if (closeIndex === -1 || (nextOpenerIndex !== -1 && nextOpenerIndex < closeIndex)) {
3082
+ position = tagEnd + 1;
2959
3083
  continue;
2960
3084
  }
2961
3085
  tags.push({
2962
- attributes: parseTagAttributes(match[2] ?? ""),
2963
- content: match[3] ?? "",
3086
+ attributes: parseTagAttributes(html.slice(openerIndex + name.length + 1, tagEnd)),
3087
+ content: html.slice(tagEnd + 1, closeIndex),
2964
3088
  name,
2965
3089
  });
3090
+ position = closeIndex + closeToken.length;
2966
3091
  }
2967
3092
  return tags;
2968
3093
  }
3094
+ export const __inlineCspTagsForTesting = inlineCspTags;
2969
3095
  function parseTagAttributes(source) {
2970
3096
  const attributes = new Map();
2971
3097
  const pattern = /([^\s=/>]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
@@ -2996,7 +3122,7 @@ function injectQueryState(html, state) {
2996
3122
  }
2997
3123
  const script = `<script type="application/json" id="${__MREACT_QUERY_STATE_SCRIPT_ID}">${escapeJsonForHtml(JSON.stringify(state))}</script>`;
2998
3124
  return /<\/body>/i.test(html)
2999
- ? html.replace(/<\/body>/i, () => `${script}</body>`)
3125
+ ? replaceFinalBodyCloseTag(html, script)
3000
3126
  : `${html}${script}`;
3001
3127
  }
3002
3128
  function injectAuthSessionClaims(html, claims) {
@@ -3005,9 +3131,17 @@ function injectAuthSessionClaims(html, claims) {
3005
3131
  }
3006
3132
  const script = `<script type="application/json" id="${authSessionScriptId}">${escapeJsonForHtml(JSON.stringify(claims))}</script>`;
3007
3133
  return /<\/body>/i.test(html)
3008
- ? html.replace(/<\/body>/i, () => `${script}</body>`)
3134
+ ? replaceFinalBodyCloseTag(html, script)
3009
3135
  : `${html}${script}`;
3010
3136
  }
3137
+ function replaceFinalBodyCloseTag(html, insertion) {
3138
+ const matches = [...html.matchAll(/<\/body>/gi)];
3139
+ const last = matches.at(-1);
3140
+ if (last?.index === undefined) {
3141
+ return `${html}${insertion}`;
3142
+ }
3143
+ return `${html.slice(0, last.index)}${insertion}${html.slice(last.index)}`;
3144
+ }
3011
3145
  function authIncludesClaims(code) {
3012
3146
  return /\bexport\s+const\s+auth\s*=\s*["']include-claims["']\s*;?/.test(code);
3013
3147
  }