vinext 1.0.0-beta.1 → 1.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/README.md +10 -10
  2. package/dist/build/client-build-config.js +8 -1
  3. package/dist/build/report.d.ts +8 -1
  4. package/dist/build/report.js +12 -2
  5. package/dist/check.js +19 -2
  6. package/dist/cli.js +3 -2
  7. package/dist/config/config-matchers.d.ts +13 -37
  8. package/dist/config/config-matchers.js +35 -122
  9. package/dist/config/next-config.d.ts +15 -5
  10. package/dist/config/next-config.js +7 -1
  11. package/dist/config/request-context.d.ts +14 -0
  12. package/dist/config/request-context.js +26 -0
  13. package/dist/entries/app-browser-entry.d.ts +4 -10
  14. package/dist/entries/app-browser-entry.js +20 -4
  15. package/dist/entries/app-rsc-entry.js +30 -9
  16. package/dist/entries/app-rsc-manifest.js +36 -0
  17. package/dist/entries/pages-client-entry.js +0 -1
  18. package/dist/entries/pages-server-entry.js +13 -5
  19. package/dist/index.js +194 -101
  20. package/dist/init-cloudflare.d.ts +3 -1
  21. package/dist/init-cloudflare.js +59 -5
  22. package/dist/init.d.ts +6 -4
  23. package/dist/init.js +20 -22
  24. package/dist/plugins/extensionless-dynamic-import.js +23 -18
  25. package/dist/plugins/ignore-dynamic-requests.js +3 -1
  26. package/dist/plugins/import-meta-url.js +17 -6
  27. package/dist/plugins/og-assets.js +1 -1
  28. package/dist/plugins/require-context.js +20 -15
  29. package/dist/plugins/transform-cache.d.ts +19 -0
  30. package/dist/plugins/transform-cache.js +36 -0
  31. package/dist/routing/app-route-graph.d.ts +27 -11
  32. package/dist/routing/app-route-graph.js +158 -22
  33. package/dist/routing/app-router.js +12 -6
  34. package/dist/routing/file-matcher.d.ts +11 -22
  35. package/dist/routing/file-matcher.js +21 -33
  36. package/dist/routing/pages-router.js +23 -29
  37. package/dist/routing/route-matching.d.ts +14 -1
  38. package/dist/routing/route-matching.js +13 -1
  39. package/dist/routing/route-pattern.d.ts +2 -1
  40. package/dist/routing/route-pattern.js +7 -4
  41. package/dist/routing/route-trie.d.ts +5 -1
  42. package/dist/routing/route-trie.js +5 -2
  43. package/dist/server/api-handler.d.ts +2 -0
  44. package/dist/server/api-handler.js +3 -3
  45. package/dist/server/app-browser-entry.js +110 -37
  46. package/dist/server/app-browser-history-controller.d.ts +1 -1
  47. package/dist/server/app-browser-history-controller.js +3 -3
  48. package/dist/server/app-browser-navigation-controller.d.ts +23 -21
  49. package/dist/server/app-browser-navigation-controller.js +2 -2
  50. package/dist/server/app-browser-state.js +1 -1
  51. package/dist/server/app-browser-visible-commit.js +1 -1
  52. package/dist/server/app-fallback-renderer.d.ts +3 -0
  53. package/dist/server/app-fallback-renderer.js +4 -2
  54. package/dist/server/app-middleware.js +2 -1
  55. package/dist/server/app-page-boundary-render.d.ts +12 -1
  56. package/dist/server/app-page-boundary-render.js +84 -2
  57. package/dist/server/app-page-cache-finalizer.d.ts +1 -1
  58. package/dist/server/app-page-cache-finalizer.js +1 -1
  59. package/dist/server/app-page-cache.d.ts +2 -2
  60. package/dist/server/app-page-cache.js +16 -2
  61. package/dist/server/app-page-dispatch.d.ts +19 -2
  62. package/dist/server/app-page-dispatch.js +45 -23
  63. package/dist/server/app-page-element-builder.d.ts +9 -2
  64. package/dist/server/app-page-element-builder.js +144 -33
  65. package/dist/server/app-page-head.d.ts +56 -4
  66. package/dist/server/app-page-head.js +216 -85
  67. package/dist/server/app-page-http-access-fallback-metadata.d.ts +29 -0
  68. package/dist/server/app-page-http-access-fallback-metadata.js +114 -0
  69. package/dist/server/app-page-probe.d.ts +4 -0
  70. package/dist/server/app-page-probe.js +6 -2
  71. package/dist/server/app-page-render.d.ts +2 -2
  72. package/dist/server/app-page-render.js +1 -1
  73. package/dist/server/app-page-request.d.ts +15 -0
  74. package/dist/server/app-page-request.js +134 -14
  75. package/dist/server/app-page-response.js +1 -1
  76. package/dist/server/app-page-route-wiring.d.ts +16 -0
  77. package/dist/server/app-page-route-wiring.js +254 -52
  78. package/dist/server/app-pages-bridge.d.ts +1 -1
  79. package/dist/server/app-pages-bridge.js +2 -1
  80. package/dist/server/app-post-middleware-context.d.ts +1 -1
  81. package/dist/server/app-post-middleware-context.js +1 -1
  82. package/dist/server/app-route-handler-cache.js +4 -0
  83. package/dist/server/app-route-handler-dispatch.js +40 -20
  84. package/dist/server/app-route-handler-execution.d.ts +6 -1
  85. package/dist/server/app-route-handler-execution.js +42 -16
  86. package/dist/server/app-route-handler-policy.d.ts +2 -0
  87. package/dist/server/app-route-handler-policy.js +3 -3
  88. package/dist/server/app-route-handler-response.js +1 -1
  89. package/dist/server/app-route-module-loader.d.ts +9 -1
  90. package/dist/server/app-route-module-loader.js +4 -0
  91. package/dist/server/app-router-entry.js +6 -3
  92. package/dist/server/app-rsc-cache-busting.d.ts +1 -1
  93. package/dist/server/app-rsc-errors.d.ts +1 -1
  94. package/dist/server/app-rsc-errors.js +22 -2
  95. package/dist/server/app-rsc-handler.d.ts +10 -5
  96. package/dist/server/app-rsc-handler.js +73 -33
  97. package/dist/server/app-rsc-request-normalization.d.ts +3 -2
  98. package/dist/server/app-rsc-request-normalization.js +8 -2
  99. package/dist/server/app-rsc-response-finalizer.d.ts +2 -2
  100. package/dist/server/app-rsc-response-finalizer.js +5 -11
  101. package/dist/server/app-rsc-route-matching.d.ts +29 -0
  102. package/dist/server/app-rsc-route-matching.js +93 -11
  103. package/dist/server/app-segment-config.js +13 -3
  104. package/dist/server/app-server-action-execution.d.ts +3 -1
  105. package/dist/server/app-server-action-execution.js +9 -7
  106. package/dist/server/app-ssr-entry.js +6 -6
  107. package/dist/server/app-ssr-stream.d.ts +1 -7
  108. package/dist/server/app-ssr-stream.js +2 -10
  109. package/dist/server/cache-control.d.ts +2 -2
  110. package/dist/server/cache-control.js +2 -1
  111. package/dist/server/config-headers.d.ts +24 -0
  112. package/dist/server/config-headers.js +52 -0
  113. package/dist/server/dev-initial-server-error.d.ts +1 -1
  114. package/dist/server/dev-server.d.ts +3 -1
  115. package/dist/server/dev-server.js +170 -321
  116. package/dist/server/headers.d.ts +2 -2
  117. package/dist/server/headers.js +4 -3
  118. package/dist/server/isr-cache.d.ts +11 -34
  119. package/dist/server/isr-cache.js +33 -43
  120. package/dist/server/isr-decision.d.ts +2 -2
  121. package/dist/server/middleware-matcher-pattern.d.ts +22 -0
  122. package/dist/server/middleware-matcher-pattern.js +219 -0
  123. package/dist/server/middleware-matcher.d.ts +2 -7
  124. package/dist/server/middleware-matcher.js +13 -60
  125. package/dist/server/middleware-path-to-regexp.d.ts +14 -0
  126. package/dist/server/middleware-path-to-regexp.js +228 -0
  127. package/dist/server/middleware-runtime.js +4 -3
  128. package/dist/server/middleware.d.ts +1 -1
  129. package/dist/server/middleware.js +2 -1
  130. package/dist/server/pages-api-route.d.ts +2 -0
  131. package/dist/server/pages-api-route.js +4 -1
  132. package/dist/server/pages-data-route.d.ts +11 -1
  133. package/dist/server/pages-data-route.js +16 -1
  134. package/dist/server/pages-dev-hydration.js +0 -1
  135. package/dist/server/pages-get-initial-props.d.ts +16 -3
  136. package/dist/server/pages-get-initial-props.js +17 -10
  137. package/dist/server/pages-i18n.js +64 -16
  138. package/dist/server/pages-node-compat.d.ts +2 -0
  139. package/dist/server/pages-node-compat.js +7 -3
  140. package/dist/server/pages-page-data.d.ts +64 -10
  141. package/dist/server/pages-page-data.js +349 -80
  142. package/dist/server/pages-page-handler.d.ts +9 -3
  143. package/dist/server/pages-page-handler.js +131 -36
  144. package/dist/server/pages-page-response.d.ts +5 -3
  145. package/dist/server/pages-page-response.js +24 -27
  146. package/dist/server/pages-readiness.d.ts +3 -3
  147. package/dist/server/pages-request-pipeline.d.ts +8 -0
  148. package/dist/server/pages-request-pipeline.js +30 -12
  149. package/dist/server/pages-revalidate.d.ts +1 -1
  150. package/dist/server/pages-revalidate.js +54 -8
  151. package/dist/server/pages-router-entry.d.ts +1 -0
  152. package/dist/server/pages-router-entry.js +16 -4
  153. package/dist/server/prerender-route-params.js +2 -2
  154. package/dist/server/prod-server.d.ts +3 -5
  155. package/dist/server/prod-server.js +72 -35
  156. package/dist/server/request-pipeline.d.ts +15 -29
  157. package/dist/server/request-pipeline.js +24 -59
  158. package/dist/server/revalidation-host.d.ts +11 -0
  159. package/dist/server/revalidation-host.js +19 -0
  160. package/dist/server/rsc-stream-hints.js +122 -18
  161. package/dist/server/worker-revalidation-context.d.ts +13 -0
  162. package/dist/server/worker-revalidation-context.js +29 -0
  163. package/dist/shims/app.d.ts +1 -1
  164. package/dist/shims/cache-handler.d.ts +1 -1
  165. package/dist/shims/cache-handler.js +10 -7
  166. package/dist/shims/cache-request-state.d.ts +27 -1
  167. package/dist/shims/cache-request-state.js +60 -1
  168. package/dist/shims/cache-runtime.d.ts +18 -1
  169. package/dist/shims/cache-runtime.js +26 -8
  170. package/dist/shims/cache.d.ts +5 -5
  171. package/dist/shims/cache.js +27 -11
  172. package/dist/shims/document.d.ts +42 -83
  173. package/dist/shims/document.js +62 -53
  174. package/dist/shims/dynamic.d.ts +5 -25
  175. package/dist/shims/dynamic.js +29 -8
  176. package/dist/shims/error.d.ts +1 -1
  177. package/dist/shims/error.js +2 -2
  178. package/dist/shims/fetch-cache.js +13 -4
  179. package/dist/shims/font-google-base.d.ts +11 -4
  180. package/dist/shims/font-google-base.js +17 -8
  181. package/dist/shims/font-local.d.ts +10 -3
  182. package/dist/shims/font-local.js +41 -10
  183. package/dist/shims/head.d.ts +13 -2
  184. package/dist/shims/head.js +3 -3
  185. package/dist/shims/headers.d.ts +37 -43
  186. package/dist/shims/headers.js +183 -74
  187. package/dist/shims/image.d.ts +27 -37
  188. package/dist/shims/image.js +21 -14
  189. package/dist/shims/internal/cookie-serialize.d.ts +12 -9
  190. package/dist/shims/internal/cookie-serialize.js +10 -7
  191. package/dist/shims/internal/hybrid-client-route-owner.js +3 -1
  192. package/dist/shims/internal/interpolate-as.d.ts +15 -1
  193. package/dist/shims/internal/interpolate-as.js +27 -2
  194. package/dist/shims/internal/utils.d.ts +3 -3
  195. package/dist/shims/legacy-image.d.ts +3 -37
  196. package/dist/shims/legacy-image.js +6 -16
  197. package/dist/shims/link.d.ts +15 -22
  198. package/dist/shims/link.js +34 -13
  199. package/dist/shims/metadata.d.ts +7 -17
  200. package/dist/shims/metadata.js +74 -24
  201. package/dist/shims/navigation-context-state.d.ts +1 -1
  202. package/dist/shims/navigation.d.ts +7 -3
  203. package/dist/shims/navigation.js +25 -14
  204. package/dist/shims/navigation.react-server.js +1 -1
  205. package/dist/shims/next-shims-augmentations.d.ts +1 -0
  206. package/dist/shims/next-shims-public.d.ts +1 -0
  207. package/dist/shims/public-shim-map.json.js +103 -0
  208. package/dist/shims/readonly-url-search-params.d.ts +3 -3
  209. package/dist/shims/readonly-url-search-params.js +3 -3
  210. package/dist/shims/request-context.d.ts +4 -1
  211. package/dist/shims/request-state-types.d.ts +1 -1
  212. package/dist/shims/router.d.ts +55 -21
  213. package/dist/shims/router.js +180 -44
  214. package/dist/shims/script.d.ts +6 -10
  215. package/dist/shims/script.js +7 -4
  216. package/dist/shims/server.d.ts +50 -26
  217. package/dist/shims/server.js +193 -55
  218. package/dist/shims/unified-request-context.d.ts +22 -3
  219. package/dist/shims/unified-request-context.js +84 -1
  220. package/dist/shims/url-safety.d.ts +1 -1
  221. package/dist/shims/url-safety.js +2 -2
  222. package/dist/typegen.d.ts +8 -2
  223. package/dist/typegen.js +76 -15
  224. package/dist/utils/cache-control-metadata.d.ts +2 -1
  225. package/dist/utils/cache-control-metadata.js +5 -1
  226. package/dist/utils/domain-locale.d.ts +2 -2
  227. package/dist/utils/external-url.d.ts +5 -0
  228. package/dist/utils/external-url.js +7 -0
  229. package/dist/utils/html-limited-bots.js +1 -1
  230. package/dist/utils/protocol-headers.d.ts +7 -1
  231. package/dist/utils/protocol-headers.js +7 -1
  232. package/dist/utils/regex-safety.d.ts +8 -0
  233. package/dist/utils/regex-safety.js +737 -0
  234. package/package.json +13 -2
@@ -9,28 +9,36 @@
9
9
  * This is a pragmatic subset — we implement the most commonly used APIs
10
10
  * rather than bug-for-bug parity with Next.js internals.
11
11
  */
12
+ /** @deprecated Import ImageResponse from `next/og` instead. */
13
+ declare function ImageResponse(): never;
14
+ type RequestInit = globalThis.RequestInit & {
15
+ nextConfig?: {
16
+ basePath?: string;
17
+ i18n?: {
18
+ locales: readonly string[];
19
+ defaultLocale: string;
20
+ domains?: ReadonlyArray<{
21
+ domain: string;
22
+ defaultLocale: string;
23
+ locales?: readonly string[];
24
+ http?: true;
25
+ }>;
26
+ } | null;
27
+ trailingSlash?: boolean;
28
+ };
29
+ signal?: AbortSignal;
30
+ duplex?: "half";
31
+ };
12
32
  declare class NextRequest extends Request {
13
33
  private _nextUrl;
14
34
  private _url;
15
35
  private _cookies;
16
- constructor(input: URL | RequestInfo, init?: RequestInit & {
17
- nextConfig?: {
18
- basePath?: string;
19
- i18n?: {
20
- locales: string[];
21
- defaultLocale: string;
22
- domains?: Array<{
23
- domain: string;
24
- defaultLocale: string;
25
- locales?: string[];
26
- }>;
27
- };
28
- trailingSlash?: boolean;
29
- };
30
- });
36
+ constructor(input: URL | RequestInfo, init?: RequestInit);
31
37
  get nextUrl(): NextURL;
32
38
  get url(): string;
33
39
  get cookies(): RequestCookies;
40
+ get page(): void;
41
+ get ua(): void;
34
42
  /**
35
43
  * Client IP address. Prefers Cloudflare's trusted CF-Connecting-IP header
36
44
  * over the spoofable X-Forwarded-For. Returns undefined if unavailable.
@@ -65,12 +73,16 @@ declare class NextResponse<_Body = unknown> extends Response {
65
73
  /**
66
74
  * Create a redirect response.
67
75
  */
68
- static redirect(url: string | URL | NextURL, init?: number | ResponseInit): NextResponse;
76
+ static redirect(url: string | URL | {
77
+ toString(): string;
78
+ }, init?: number | ResponseInit): NextResponse;
69
79
  /**
70
80
  * Create a rewrite response (middleware pattern).
71
81
  * Sets the x-middleware-rewrite header.
72
82
  */
73
- static rewrite(destination: string | URL | NextURL, init?: MiddlewareResponseInit): NextResponse;
83
+ static rewrite(destination: string | URL | {
84
+ toString(): string;
85
+ }, init?: MiddlewareResponseInit): NextResponse;
74
86
  /**
75
87
  * Continue to the next handler (middleware pattern).
76
88
  * Sets the x-middleware-next header.
@@ -176,6 +188,7 @@ declare class NextURL {
176
188
  get locales(): string[] | undefined;
177
189
  clone(): NextURL;
178
190
  toString(): string;
191
+ toJSON(): string;
179
192
  /**
180
193
  * The build ID of the Next.js application.
181
194
  * Set from `generateBuildId` in next.config.js, or a random UUID if not configured.
@@ -202,7 +215,7 @@ declare class RequestCookies {
202
215
  toString(): string;
203
216
  private _serialize;
204
217
  private _syncHeader;
205
- [Symbol.iterator](): IterableIterator<[string, CookieEntry]>;
218
+ [Symbol.iterator](): MapIterator<[string, CookieEntry]>;
206
219
  }
207
220
  declare function sealRequestHeaders(headers: Headers): Headers;
208
221
  declare function sealRequestCookies(cookies: RequestCookies): RequestCookies;
@@ -217,15 +230,16 @@ declare class ResponseCookies {
217
230
  }]): this;
218
231
  get(...args: [name: string] | [options: {
219
232
  name: string;
220
- }]): CookieEntry | undefined;
233
+ }]): ResponseCookieEntry | undefined;
221
234
  has(name: string): boolean;
222
235
  getAll(...args: [name: string] | [options: {
223
236
  name: string;
224
- }] | []): CookieEntry[];
237
+ }] | []): ResponseCookieEntry[];
225
238
  delete(...args: [name: string] | [options: Omit<CookieOptions & {
226
239
  name: string;
227
240
  }, "maxAge" | "expires">]): this;
228
- [Symbol.iterator](): IterableIterator<[string, CookieEntry]>;
241
+ [Symbol.iterator](): MapIterator<[string, ResponseCookieEntry]>;
242
+ toString(): string;
229
243
  /** Delete all Set-Cookie headers and re-append from the internal map. */
230
244
  private _syncHeaders;
231
245
  }
@@ -233,11 +247,14 @@ type CookieOptions = {
233
247
  path?: string;
234
248
  domain?: string;
235
249
  maxAge?: number;
236
- expires?: Date;
250
+ expires?: Date | number;
237
251
  httpOnly?: boolean;
238
252
  secure?: boolean;
239
- sameSite?: "Strict" | "Lax" | "None";
253
+ sameSite?: true | false | "strict" | "lax" | "none";
254
+ partitioned?: boolean;
255
+ priority?: "low" | "medium" | "high";
240
256
  };
257
+ type ResponseCookieEntry = CookieEntry & CookieOptions;
241
258
  type MiddlewareResponseInit = {
242
259
  request?: {
243
260
  headers?: Headers;
@@ -253,8 +270,16 @@ declare class NextFetchEvent {
253
270
  sourcePage: string;
254
271
  private _waitUntilPromises;
255
272
  constructor(params: {
273
+ request?: Request;
256
274
  page: string;
275
+ context?: {
276
+ waitUntil(promise: Promise<unknown>): void;
277
+ };
257
278
  });
279
+ private _externalWaitUntil?;
280
+ get request(): void;
281
+ respondWith(): void;
282
+ passThroughOnException(): void;
258
283
  waitUntil(promise: Promise<unknown>): void;
259
284
  get waitUntilPromises(): Promise<unknown>[];
260
285
  /** Drain all waitUntil promises. Returns a single promise that settles when all are done. */
@@ -300,8 +325,7 @@ type UserAgent = {
300
325
  *
301
326
  * Uses the platform's `waitUntil` (via the per-request ExecutionContext) when
302
327
  * available so the task survives past the response on Cloudflare Workers.
303
- * Falls back to a fire-and-forget microtask on runtimes without an execution
304
- * context (e.g. Node.js dev server).
328
+ * Node.js dev drains callbacks from its response finish/close lifecycle.
305
329
  *
306
330
  * Throws when called inside a cached scope — request-specific
307
331
  * side-effects must not leak into cached results.
@@ -320,4 +344,4 @@ declare function connection(): Promise<void>;
320
344
  */
321
345
  declare const URLPattern: typeof globalThis.URLPattern;
322
346
  //#endregion
323
- export { MiddlewareResponseInit, NextFetchEvent, NextMiddleware, NextMiddlewareResult, NextRequest, NextResponse, NextURL, NextURLConfig, RequestCookies, ResponseCookies, URLPattern, UserAgent, after, connection, sealRequestCookies, sealRequestHeaders, userAgent, userAgentFromString };
347
+ export { ImageResponse, MiddlewareResponseInit, NextFetchEvent, NextMiddleware, NextMiddlewareResult, NextRequest, NextResponse, NextURL, NextURLConfig, RequestCookies, RequestInit, ResponseCookies, URLPattern, UserAgent, after, connection, sealRequestCookies, sealRequestHeaders, userAgent, userAgentFromString };
@@ -1,9 +1,10 @@
1
+ import { bindRequestContextSnapshot, getRequestContext, isInsideUnifiedScope, queueAfterCallback } from "./unified-request-context.js";
1
2
  import { hasBasePath, stripBasePath } from "../utils/base-path.js";
2
3
  import { getRequestExecutionContext } from "./request-context.js";
3
4
  import { MIDDLEWARE_SET_COOKIE_HEADER } from "../utils/protocol-headers.js";
4
5
  import { MIDDLEWARE_NEXT_HEADER, MIDDLEWARE_REWRITE_HEADER } from "../server/headers.js";
5
6
  import { encodeMiddlewareRequestHeaders } from "../utils/middleware-request-headers.js";
6
- import { serializeSetCookie, validateCookieName } from "./internal/cookie-serialize.js";
7
+ import { validateCookieAttributeValue, validateCookieName } from "./internal/cookie-serialize.js";
7
8
  import { parseEdgeRequestCookieHeader } from "../utils/parse-cookie.js";
8
9
  import { assertSafeNavigationUrl } from "./url-safety.js";
9
10
  //#region src/shims/server.ts
@@ -17,6 +18,10 @@ import { assertSafeNavigationUrl } from "./url-safety.js";
17
18
  * This is a pragmatic subset — we implement the most commonly used APIs
18
19
  * rather than bug-for-bug parity with Next.js internals.
19
20
  */
21
+ /** @deprecated Import ImageResponse from `next/og` instead. */
22
+ function ImageResponse() {
23
+ throw new Error("ImageResponse has moved from next/server to next/og");
24
+ }
20
25
  const _USE_CACHE_ALS_KEY = Symbol.for("vinext.cacheRuntime.contextAls");
21
26
  const _UNSTABLE_CACHE_ALS_KEY = Symbol.for("vinext.unstableCache.als");
22
27
  const _g = globalThis;
@@ -60,10 +65,18 @@ var NextRequest = class extends Request {
60
65
  });
61
66
  } else super(input, requestInit);
62
67
  const url = typeof input === "string" ? new URL(input, "http://localhost") : input instanceof URL ? input : new URL(input.url, "http://localhost");
68
+ const i18n = _nextConfig?.i18n ? {
69
+ locales: [..._nextConfig.i18n.locales],
70
+ defaultLocale: _nextConfig.i18n.defaultLocale,
71
+ domains: _nextConfig.i18n.domains?.map((domain) => ({
72
+ ...domain,
73
+ locales: domain.locales ? [...domain.locales] : void 0
74
+ }))
75
+ } : void 0;
63
76
  const urlConfig = _nextConfig ? {
64
77
  basePath: _nextConfig.basePath,
65
78
  nextConfig: {
66
- i18n: _nextConfig.i18n,
79
+ i18n,
67
80
  trailingSlash: _nextConfig.trailingSlash
68
81
  }
69
82
  } : void 0;
@@ -80,6 +93,12 @@ var NextRequest = class extends Request {
80
93
  get cookies() {
81
94
  return this._cookies;
82
95
  }
96
+ get page() {
97
+ throw new Error("NextRequest.page has been removed; use URLPattern instead");
98
+ }
99
+ get ua() {
100
+ throw new Error("NextRequest.ua has been removed; use userAgent() instead");
101
+ }
83
102
  /**
84
103
  * Client IP address. Prefers Cloudflare's trusted CF-Connecting-IP header
85
104
  * over the spoofable X-Forwarded-For. Returns undefined if unavailable.
@@ -140,12 +159,8 @@ var NextResponse = class NextResponse extends Response {
140
159
  * Create a JSON response.
141
160
  */
142
161
  static json(body, init) {
143
- const headers = new Headers(init?.headers);
144
- if (!headers.has("content-type")) headers.set("content-type", "application/json");
145
- return new NextResponse(JSON.stringify(body), {
146
- ...init,
147
- headers
148
- });
162
+ const response = Response.json(body, init);
163
+ return new NextResponse(response.body, response);
149
164
  }
150
165
  /**
151
166
  * Create a redirect response.
@@ -399,7 +414,7 @@ var NextURL = class NextURL {
399
414
  };
400
415
  if (this._trailingSlash) nextConfig.trailingSlash = true;
401
416
  const config = {
402
- basePath: this._basePath,
417
+ basePath: this._configBasePath,
403
418
  nextConfig: Object.keys(nextConfig).length > 0 ? nextConfig : void 0
404
419
  };
405
420
  return new NextURL(this.href, void 0, config);
@@ -407,6 +422,9 @@ var NextURL = class NextURL {
407
422
  toString() {
408
423
  return this.href;
409
424
  }
425
+ toJSON() {
426
+ return this.href;
427
+ }
410
428
  /**
411
429
  * The build ID of the Next.js application.
412
430
  * Set from `generateBuildId` in next.config.js, or a random UUID if not configured.
@@ -489,7 +507,7 @@ var RequestCookies = class {
489
507
  else this._headers.set("cookie", this._serialize());
490
508
  }
491
509
  [Symbol.iterator]() {
492
- return this.getAll().map((c) => [c.name, c])[Symbol.iterator]();
510
+ return new Map(this.getAll().map((cookie) => [cookie.name, cookie])).entries();
493
511
  }
494
512
  };
495
513
  var ReadonlyRequestCookiesError = class ReadonlyRequestCookiesError extends Error {
@@ -533,74 +551,54 @@ var ResponseCookies = class {
533
551
  _parsed = /* @__PURE__ */ new Map();
534
552
  constructor(headers) {
535
553
  this._headers = headers;
536
- for (const header of headers.getSetCookie()) {
537
- const eq = header.indexOf("=");
538
- if (eq === -1) continue;
539
- const cookieName = header.slice(0, eq);
540
- const semi = header.indexOf(";", eq);
541
- const raw = header.slice(eq + 1, semi === -1 ? void 0 : semi);
542
- let value;
543
- try {
544
- value = decodeURIComponent(raw);
545
- } catch {
546
- value = raw;
547
- }
548
- this._parsed.set(cookieName, {
549
- serialized: header,
550
- entry: {
551
- name: cookieName,
552
- value
553
- }
554
- });
554
+ const setCookie = headers.getSetCookie?.() ?? headers.get("set-cookie") ?? [];
555
+ const cookieStrings = Array.isArray(setCookie) ? setCookie : splitSetCookieString(setCookie);
556
+ for (const header of cookieStrings) {
557
+ const entry = parseSetCookieHeader(header);
558
+ if (entry) this._parsed.set(entry.name, entry);
555
559
  }
556
560
  }
557
561
  set(...args) {
558
562
  const [name, value, opts] = parseCookieSetArgs(args);
559
563
  validateCookieName(name);
560
- const serialized = serializeSetCookie(name, value, opts);
561
- this._parsed.set(name, {
562
- serialized,
563
- entry: {
564
- name,
565
- value
566
- }
567
- });
564
+ const entry = normalizeResponseCookie(name, value, opts);
565
+ validateResponseCookieAttributes(entry);
566
+ this._parsed.set(name, entry);
568
567
  this._syncHeaders();
569
568
  return this;
570
569
  }
571
570
  get(...args) {
572
571
  const key = typeof args[0] === "string" ? args[0] : args[0].name;
573
- return this._parsed.get(key)?.entry;
572
+ return this._parsed.get(key);
574
573
  }
575
574
  has(name) {
576
575
  return this._parsed.has(name);
577
576
  }
578
577
  getAll(...args) {
579
- const all = [...this._parsed.values()].map((v) => v.entry);
578
+ const all = [...this._parsed.values()];
580
579
  if (args.length === 0) return all;
581
580
  const key = typeof args[0] === "string" ? args[0] : args[0].name;
582
581
  return all.filter((c) => c.name === key);
583
582
  }
584
583
  delete(...args) {
585
- const [name, opts] = typeof args[0] === "string" ? [args[0], void 0] : [args[0].name, args[0]];
584
+ const [name, options] = typeof args[0] === "string" ? [args[0], void 0] : [args[0].name, args[0]];
586
585
  return this.set({
586
+ ...options,
587
587
  name,
588
588
  value: "",
589
- expires: /* @__PURE__ */ new Date(0),
590
- path: opts?.path,
591
- domain: opts?.domain,
592
- httpOnly: opts?.httpOnly,
593
- secure: opts?.secure,
594
- sameSite: opts?.sameSite
589
+ expires: /* @__PURE__ */ new Date(0)
595
590
  });
596
591
  }
597
592
  [Symbol.iterator]() {
598
- return [...this._parsed.values()].map((v) => [v.entry.name, v.entry])[Symbol.iterator]();
593
+ return new Map([...this._parsed.values()].map((entry) => [entry.name, entry])).entries();
594
+ }
595
+ toString() {
596
+ return [...this._parsed.values()].map(stringifyResponseCookie).join("; ");
599
597
  }
600
598
  /** Delete all Set-Cookie headers and re-append from the internal map. */
601
599
  _syncHeaders() {
602
600
  this._headers.delete("Set-Cookie");
603
- for (const { serialized } of this._parsed.values()) this._headers.append("Set-Cookie", serialized);
601
+ for (const entry of this._parsed.values()) this._headers.append("Set-Cookie", stringifyResponseCookie(entry));
604
602
  }
605
603
  };
606
604
  var MiddlewareResponseCookies = class extends ResponseCookies {
@@ -628,6 +626,115 @@ var MiddlewareResponseCookies = class extends ResponseCookies {
628
626
  this._responseHeaders.set(MIDDLEWARE_SET_COOKIE_HEADER, cookies.join(","));
629
627
  }
630
628
  };
629
+ function normalizeResponseCookie(name, value, options) {
630
+ const cookie = {
631
+ name,
632
+ value,
633
+ ...options
634
+ };
635
+ if (typeof cookie.expires === "number") cookie.expires = new Date(cookie.expires);
636
+ if (cookie.maxAge) cookie.expires = new Date(Date.now() + cookie.maxAge * 1e3);
637
+ if (cookie.path == null) cookie.path = "/";
638
+ return cookie;
639
+ }
640
+ function parseSetCookieHeader(header) {
641
+ if (!header) return void 0;
642
+ const [[name, value], ...attributes] = parseResponseCookiePairs(header);
643
+ const { domain, expires, httponly, maxage, path, samesite, secure, partitioned, priority } = Object.fromEntries(attributes.map(([key, attributeValue]) => [key.toLowerCase().replaceAll("-", ""), attributeValue]));
644
+ return compactResponseCookie({
645
+ name,
646
+ value: decodeURIComponent(value),
647
+ domain,
648
+ ...expires && { expires: new Date(expires) },
649
+ ...httponly && { httpOnly: true },
650
+ ...typeof maxage === "string" && { maxAge: Number(maxage) },
651
+ path,
652
+ ...samesite && { sameSite: parseResponseCookieSameSite(samesite) },
653
+ ...secure && { secure: true },
654
+ ...priority && { priority: parseResponseCookiePriority(priority) },
655
+ ...partitioned && { partitioned: true }
656
+ });
657
+ }
658
+ function parseResponseCookiePairs(cookie) {
659
+ const map = /* @__PURE__ */ new Map();
660
+ for (const pair of cookie.split(/; */)) {
661
+ if (!pair) continue;
662
+ const splitAt = pair.indexOf("=");
663
+ if (splitAt === -1) {
664
+ map.set(pair, "true");
665
+ continue;
666
+ }
667
+ const key = pair.slice(0, splitAt);
668
+ const value = pair.slice(splitAt + 1);
669
+ try {
670
+ map.set(key, decodeURIComponent(value ?? "true"));
671
+ } catch {}
672
+ }
673
+ return map;
674
+ }
675
+ function compactResponseCookie(cookie) {
676
+ const compact = {};
677
+ for (const key in cookie) if (cookie[key]) compact[key] = cookie[key];
678
+ return compact;
679
+ }
680
+ function parseResponseCookieSameSite(value) {
681
+ const sameSite = value.toLowerCase();
682
+ return sameSite === "strict" || sameSite === "lax" || sameSite === "none" ? sameSite : void 0;
683
+ }
684
+ function parseResponseCookiePriority(value) {
685
+ const priority = value.toLowerCase();
686
+ return priority === "low" || priority === "medium" || priority === "high" ? priority : void 0;
687
+ }
688
+ function validateResponseCookieAttributes(cookie) {
689
+ if (cookie.path) validateCookieAttributeValue(cookie.path, "Path");
690
+ if (cookie.domain) validateCookieAttributeValue(cookie.domain, "Domain");
691
+ }
692
+ function stringifyResponseCookie(cookie) {
693
+ const attributes = [
694
+ cookie.path && `Path=${cookie.path}`,
695
+ (cookie.expires || cookie.expires === 0) && `Expires=${(typeof cookie.expires === "number" ? new Date(cookie.expires) : cookie.expires).toUTCString()}`,
696
+ typeof cookie.maxAge === "number" && `Max-Age=${cookie.maxAge}`,
697
+ cookie.domain && `Domain=${cookie.domain}`,
698
+ cookie.secure && "Secure",
699
+ cookie.httpOnly && "HttpOnly",
700
+ cookie.sameSite && `SameSite=${cookie.sameSite}`,
701
+ cookie.partitioned && "Partitioned",
702
+ cookie.priority && `Priority=${cookie.priority}`
703
+ ].filter(Boolean);
704
+ const stringified = `${cookie.name}=${encodeURIComponent(cookie.value ?? "")}`;
705
+ return attributes.length === 0 ? stringified : `${stringified}; ${attributes.join("; ")}`;
706
+ }
707
+ function splitSetCookieString(value) {
708
+ const cookies = [];
709
+ let position = 0;
710
+ let start = 0;
711
+ const skipWhitespace = () => {
712
+ while (position < value.length && /\s/.test(value.charAt(position))) position++;
713
+ return position < value.length;
714
+ };
715
+ while (position < value.length) {
716
+ start = position;
717
+ let separatorFound = false;
718
+ while (skipWhitespace()) {
719
+ if (value.charAt(position) !== ",") {
720
+ position++;
721
+ continue;
722
+ }
723
+ const lastComma = position++;
724
+ skipWhitespace();
725
+ const nextStart = position;
726
+ while (position < value.length && !"=;,".includes(value.charAt(position))) position++;
727
+ if (position < value.length && value.charAt(position) === "=") {
728
+ separatorFound = true;
729
+ position = nextStart;
730
+ cookies.push(value.substring(start, lastComma));
731
+ start = position;
732
+ } else position = lastComma + 1;
733
+ }
734
+ if (!separatorFound || position >= value.length) cookies.push(value.substring(start));
735
+ }
736
+ return cookies;
737
+ }
631
738
  /**
632
739
  * Parse the overloaded arguments for ResponseCookies.set():
633
740
  * - (name, value, options?) — positional form
@@ -655,8 +762,21 @@ var NextFetchEvent = class {
655
762
  _waitUntilPromises = [];
656
763
  constructor(params) {
657
764
  this.sourcePage = params.page;
765
+ if (params.context) this._externalWaitUntil = params.context.waitUntil.bind(params.context);
766
+ }
767
+ _externalWaitUntil;
768
+ get request() {
769
+ throw new Error(`The middleware signature for ${this.sourcePage} no longer exposes event.request`);
770
+ }
771
+ respondWith() {
772
+ throw new Error(`The middleware signature for ${this.sourcePage} no longer uses respondWith()`);
658
773
  }
774
+ passThroughOnException() {}
659
775
  waitUntil(promise) {
776
+ if (this._externalWaitUntil) {
777
+ this._externalWaitUntil(promise);
778
+ return;
779
+ }
660
780
  this._waitUntilPromises.push(promise);
661
781
  }
662
782
  get waitUntilPromises() {
@@ -691,18 +811,36 @@ function userAgent({ headers }) {
691
811
  *
692
812
  * Uses the platform's `waitUntil` (via the per-request ExecutionContext) when
693
813
  * available so the task survives past the response on Cloudflare Workers.
694
- * Falls back to a fire-and-forget microtask on runtimes without an execution
695
- * context (e.g. Node.js dev server).
814
+ * Node.js dev drains callbacks from its response finish/close lifecycle.
696
815
  *
697
816
  * Throws when called inside a cached scope — request-specific
698
817
  * side-effects must not leak into cached results.
699
818
  */
700
819
  function after(task) {
701
820
  _throwIfInsideCacheScope("after()");
702
- const guarded = (typeof task === "function" ? Promise.resolve().then(task) : task).catch((err) => {
703
- console.error("[vinext] after() task failed:", err);
704
- });
705
- getRequestExecutionContext()?.waitUntil(guarded);
821
+ const requestContext = isInsideUnifiedScope() ? getRequestContext() : null;
822
+ if (!requestContext) {
823
+ const executionContext = getRequestExecutionContext();
824
+ if (executionContext) {
825
+ if (typeof task !== "function" && (task == null || typeof task.then !== "function")) throw new TypeError("`after()`: Argument must be a promise or a function");
826
+ const promise = typeof task === "function" ? Promise.resolve().then(task) : task;
827
+ const guarded = Promise.resolve(promise).catch((error) => {
828
+ console.error("[vinext] after() task failed:", error);
829
+ });
830
+ executionContext.waitUntil(guarded);
831
+ return;
832
+ }
833
+ throw new Error("`after()` was called outside a request scope");
834
+ }
835
+ if (typeof task !== "function") {
836
+ if (task == null || typeof task.then !== "function") throw new TypeError("`after()`: Argument must be a promise or a function");
837
+ const guarded = Promise.resolve(task).catch((error) => {
838
+ console.error("[vinext] after() task failed:", error);
839
+ });
840
+ getRequestExecutionContext()?.waitUntil(guarded);
841
+ return;
842
+ }
843
+ queueAfterCallback(requestContext, bindRequestContextSnapshot(requestContext, task));
706
844
  }
707
845
  /**
708
846
  * connection() — signals that the response requires a live connection
@@ -727,4 +865,4 @@ const URLPattern = globalThis.URLPattern ?? (() => {
727
865
  throw new Error("URLPattern is not available in this runtime. Install the `urlpattern-polyfill` package or upgrade to Node 20+.");
728
866
  });
729
867
  //#endregion
730
- export { NextFetchEvent, NextRequest, NextResponse, NextURL, RequestCookies, ResponseCookies, URLPattern, after, connection, sealRequestCookies, sealRequestHeaders, userAgent, userAgentFromString };
868
+ export { ImageResponse, NextFetchEvent, NextRequest, NextResponse, NextURL, RequestCookies, ResponseCookies, URLPattern, after, connection, sealRequestCookies, sealRequestHeaders, userAgent, userAgentFromString };
@@ -1,5 +1,5 @@
1
- import { RootParamsState } from "./root-params.js";
2
1
  import { CacheState } from "./cache-request-state.js";
2
+ import { RootParamsState } from "./root-params.js";
3
3
  import { ExecutionContextLike } from "./request-context.js";
4
4
  import { FetchCacheState } from "./fetch-cache.js";
5
5
  import { VinextHeadersShimState } from "./headers.js";
@@ -18,13 +18,32 @@ import { NavigationState } from "./navigation-state.js";
18
18
  */
19
19
  type UnifiedRequestContext = {
20
20
  /** Cloudflare Workers ExecutionContext, or null on Node.js dev. */executionContext: ExecutionContextLike | null; /** Per-request cache for cacheForRequest(). Keyed by factory function reference. */
21
- requestCache: WeakMap<(...args: any[]) => any, unknown>;
21
+ requestCache: WeakMap<(...args: any[]) => any, unknown>; /** Shared lifecycle state for work deferred until the response closes. */
22
+ afterContext: AfterRequestContext;
22
23
  } & VinextHeadersShimState & I18nState & NavigationState & CacheState & PrivateCacheState & FetchCacheState & RouterState & HeadState & RootParamsState;
24
+ type AfterRequestContext = {
25
+ callbacks: Array<() => unknown>;
26
+ responseClosed: boolean;
27
+ pendingCallbacks: number;
28
+ completion: Promise<void> | null;
29
+ resolveCompletion: (() => void) | null;
30
+ };
23
31
  /**
24
32
  * Create a fresh `UnifiedRequestContext` with defaults for all fields.
25
33
  * Pass partial overrides for the fields you need to pre-populate.
26
34
  */
27
35
  declare function createRequestContext(opts?: Partial<UnifiedRequestContext>): UnifiedRequestContext;
36
+ /** Queue a callback until response close, or start it immediately once closed. */
37
+ declare function queueAfterCallback(ctx: UnifiedRequestContext, callback: () => unknown): void;
38
+ /** Bind a callback to every AsyncLocalStorage context active at registration. */
39
+ declare function bindRequestContextSnapshot<T>(ctx: UnifiedRequestContext, callback: () => T): () => T;
40
+ /**
41
+ * Release function-form `after()` work once the response body has closed.
42
+ * All queued callbacks start together, matching Next.js' unbounded PromiseQueue.
43
+ */
44
+ declare function closeAfterResponse(ctx: UnifiedRequestContext): Promise<void>;
45
+ /** Wrap a response so deferred callbacks start on stream completion or cancellation. */
46
+ declare function closeAfterResponseWithBody(response: Response, ctx: UnifiedRequestContext): Response;
28
47
  /**
29
48
  * Run `fn` within a unified request context scope.
30
49
  * All shim modules will read/write their state from `ctx` for the
@@ -65,4 +84,4 @@ declare function getRequestContext(): UnifiedRequestContext;
65
84
  */
66
85
  declare function isInsideUnifiedScope(): boolean;
67
86
  //#endregion
68
- export { UnifiedRequestContext, createRequestContext, getRequestContext, isInsideUnifiedScope, runWithRequestContext, runWithUnifiedStateMutation };
87
+ export { AfterRequestContext, UnifiedRequestContext, bindRequestContextSnapshot, closeAfterResponse, closeAfterResponseWithBody, createRequestContext, getRequestContext, isInsideUnifiedScope, queueAfterCallback, runWithRequestContext, runWithUnifiedStateMutation };
@@ -16,6 +16,8 @@ function createRequestContext(opts) {
16
16
  return {
17
17
  headersContext: null,
18
18
  actionRevalidationKind: 0,
19
+ pendingRevalidatedTags: /* @__PURE__ */ new Set(),
20
+ pendingRevalidations: /* @__PURE__ */ new Set(),
19
21
  dynamicUsageDetected: false,
20
22
  renderRequestApiUsage: /* @__PURE__ */ new Set(),
21
23
  connectionProbe: null,
@@ -41,6 +43,13 @@ function createRequestContext(opts) {
41
43
  currentFetchDedupeEntries: /* @__PURE__ */ new Map(),
42
44
  executionContext: _getInheritedExecutionContext(),
43
45
  requestCache: /* @__PURE__ */ new WeakMap(),
46
+ afterContext: {
47
+ callbacks: [],
48
+ responseClosed: false,
49
+ pendingCallbacks: 0,
50
+ completion: null,
51
+ resolveCompletion: null
52
+ },
44
53
  ssrContext: null,
45
54
  ssrHeadChildren: [],
46
55
  documentInitialHead: [],
@@ -48,6 +57,80 @@ function createRequestContext(opts) {
48
57
  ...opts
49
58
  };
50
59
  }
60
+ function ensureAfterCompletion(ctx) {
61
+ const state = ctx.afterContext;
62
+ if (state.resolveCompletion && state.completion) return;
63
+ let resolveCompletion;
64
+ const completion = new Promise((resolve) => {
65
+ resolveCompletion = resolve;
66
+ });
67
+ state.completion = completion;
68
+ state.resolveCompletion = resolveCompletion;
69
+ ctx.executionContext?.waitUntil(completion);
70
+ }
71
+ function finishAfterCallbacksIfIdle(ctx) {
72
+ const state = ctx.afterContext;
73
+ if (!state.responseClosed || state.pendingCallbacks !== 0 || state.callbacks.length !== 0 || !state.resolveCompletion) return;
74
+ const resolveCompletion = state.resolveCompletion;
75
+ state.resolveCompletion = null;
76
+ resolveCompletion();
77
+ }
78
+ function startAfterCallback(ctx, callback) {
79
+ const state = ctx.afterContext;
80
+ ensureAfterCompletion(ctx);
81
+ state.pendingCallbacks += 1;
82
+ Promise.resolve().then(callback).catch((error) => {
83
+ console.error("[vinext] after() task failed:", error);
84
+ }).finally(() => {
85
+ state.pendingCallbacks -= 1;
86
+ finishAfterCallbacksIfIdle(ctx);
87
+ });
88
+ }
89
+ /** Queue a callback until response close, or start it immediately once closed. */
90
+ function queueAfterCallback(ctx, callback) {
91
+ ensureAfterCompletion(ctx);
92
+ if (ctx.afterContext.responseClosed) startAfterCallback(ctx, callback);
93
+ else ctx.afterContext.callbacks.push(callback);
94
+ }
95
+ /** Bind a callback to every AsyncLocalStorage context active at registration. */
96
+ function bindRequestContextSnapshot(ctx, callback) {
97
+ const constructor = _als.constructor;
98
+ try {
99
+ const runInSnapshot = constructor.snapshot?.();
100
+ if (runInSnapshot) return () => runInSnapshot(callback);
101
+ } catch {}
102
+ return () => _als.run(ctx, callback);
103
+ }
104
+ /**
105
+ * Release function-form `after()` work once the response body has closed.
106
+ * All queued callbacks start together, matching Next.js' unbounded PromiseQueue.
107
+ */
108
+ async function closeAfterResponse(ctx) {
109
+ const state = ctx.afterContext;
110
+ if (!state.responseClosed) {
111
+ state.responseClosed = true;
112
+ const callbacks = state.callbacks.splice(0);
113
+ for (const callback of callbacks) startAfterCallback(ctx, callback);
114
+ finishAfterCallbacksIfIdle(ctx);
115
+ }
116
+ return state.completion ?? Promise.resolve();
117
+ }
118
+ /** Wrap a response so deferred callbacks start on stream completion or cancellation. */
119
+ function closeAfterResponseWithBody(response, ctx) {
120
+ if (!response.body) {
121
+ queueMicrotask(() => void closeAfterResponse(ctx));
122
+ return response;
123
+ }
124
+ const passthrough = new TransformStream();
125
+ response.body.pipeTo(passthrough.writable).then(() => void closeAfterResponse(ctx), () => void closeAfterResponse(ctx));
126
+ const wrapped = new Response(passthrough.readable, {
127
+ status: response.status,
128
+ statusText: response.statusText,
129
+ headers: response.headers
130
+ });
131
+ wrapped.__vinextStreamedHtmlResponse = response.__vinextStreamedHtmlResponse;
132
+ return wrapped;
133
+ }
51
134
  function runWithRequestContext(ctx, fn) {
52
135
  return _als.run(ctx, fn);
53
136
  }
@@ -84,4 +167,4 @@ function isInsideUnifiedScope() {
84
167
  return _als.getStore() != null;
85
168
  }
86
169
  //#endregion
87
- export { createRequestContext, getRequestContext, isInsideUnifiedScope, runWithRequestContext, runWithUnifiedStateMutation };
170
+ export { bindRequestContextSnapshot, closeAfterResponse, closeAfterResponseWithBody, createRequestContext, getRequestContext, isInsideUnifiedScope, queueAfterCallback, runWithRequestContext, runWithUnifiedStateMutation };