vinext 0.0.27 → 0.0.28

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 (114) hide show
  1. package/dist/build/static-export.d.ts +1 -1
  2. package/dist/build/static-export.d.ts.map +1 -1
  3. package/dist/build/static-export.js +2 -1
  4. package/dist/build/static-export.js.map +1 -1
  5. package/dist/cloudflare/kv-cache-handler.d.ts +28 -17
  6. package/dist/cloudflare/kv-cache-handler.d.ts.map +1 -1
  7. package/dist/cloudflare/kv-cache-handler.js +95 -30
  8. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  9. package/dist/config/config-matchers.d.ts +1 -0
  10. package/dist/config/config-matchers.d.ts.map +1 -1
  11. package/dist/config/config-matchers.js +51 -23
  12. package/dist/config/config-matchers.js.map +1 -1
  13. package/dist/deploy.d.ts +1 -1
  14. package/dist/deploy.d.ts.map +1 -1
  15. package/dist/deploy.js +48 -32
  16. package/dist/deploy.js.map +1 -1
  17. package/dist/entries/app-rsc-entry.d.ts +3 -1
  18. package/dist/entries/app-rsc-entry.d.ts.map +1 -1
  19. package/dist/entries/app-rsc-entry.js +495 -75
  20. package/dist/entries/app-rsc-entry.js.map +1 -1
  21. package/dist/entries/pages-server-entry.d.ts.map +1 -1
  22. package/dist/entries/pages-server-entry.js +68 -22
  23. package/dist/entries/pages-server-entry.js.map +1 -1
  24. package/dist/index.d.ts +23 -7
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +128 -41
  27. package/dist/index.js.map +1 -1
  28. package/dist/plugins/client-reference-dedup.d.ts +19 -0
  29. package/dist/plugins/client-reference-dedup.d.ts.map +1 -0
  30. package/dist/plugins/client-reference-dedup.js +96 -0
  31. package/dist/plugins/client-reference-dedup.js.map +1 -0
  32. package/dist/routing/app-router.d.ts.map +1 -1
  33. package/dist/routing/app-router.js +60 -89
  34. package/dist/routing/app-router.js.map +1 -1
  35. package/dist/routing/pages-router.d.ts +1 -1
  36. package/dist/routing/pages-router.d.ts.map +1 -1
  37. package/dist/routing/pages-router.js +25 -13
  38. package/dist/routing/pages-router.js.map +1 -1
  39. package/dist/routing/route-validation.d.ts +8 -0
  40. package/dist/routing/route-validation.d.ts.map +1 -0
  41. package/dist/routing/route-validation.js +124 -0
  42. package/dist/routing/route-validation.js.map +1 -0
  43. package/dist/server/api-handler.d.ts.map +1 -1
  44. package/dist/server/api-handler.js +24 -7
  45. package/dist/server/api-handler.js.map +1 -1
  46. package/dist/server/dev-server.d.ts.map +1 -1
  47. package/dist/server/dev-server.js +9 -3
  48. package/dist/server/dev-server.js.map +1 -1
  49. package/dist/server/isr-cache.d.ts +5 -13
  50. package/dist/server/isr-cache.d.ts.map +1 -1
  51. package/dist/server/isr-cache.js +13 -12
  52. package/dist/server/isr-cache.js.map +1 -1
  53. package/dist/server/metadata-routes.d.ts +8 -2
  54. package/dist/server/metadata-routes.d.ts.map +1 -1
  55. package/dist/server/metadata-routes.js +73 -28
  56. package/dist/server/metadata-routes.js.map +1 -1
  57. package/dist/server/middleware-codegen.d.ts +1 -1
  58. package/dist/server/middleware-codegen.d.ts.map +1 -1
  59. package/dist/server/middleware-codegen.js +165 -12
  60. package/dist/server/middleware-codegen.js.map +1 -1
  61. package/dist/server/middleware.d.ts +9 -8
  62. package/dist/server/middleware.d.ts.map +1 -1
  63. package/dist/server/middleware.js +74 -13
  64. package/dist/server/middleware.js.map +1 -1
  65. package/dist/server/prod-server.d.ts.map +1 -1
  66. package/dist/server/prod-server.js +84 -54
  67. package/dist/server/prod-server.js.map +1 -1
  68. package/dist/shims/cache.d.ts +2 -0
  69. package/dist/shims/cache.d.ts.map +1 -1
  70. package/dist/shims/cache.js +20 -8
  71. package/dist/shims/cache.js.map +1 -1
  72. package/dist/shims/fetch-cache.d.ts.map +1 -1
  73. package/dist/shims/fetch-cache.js +5 -2
  74. package/dist/shims/fetch-cache.js.map +1 -1
  75. package/dist/shims/form.d.ts.map +1 -1
  76. package/dist/shims/form.js +103 -8
  77. package/dist/shims/form.js.map +1 -1
  78. package/dist/shims/headers.d.ts +11 -3
  79. package/dist/shims/headers.d.ts.map +1 -1
  80. package/dist/shims/headers.js +180 -25
  81. package/dist/shims/headers.js.map +1 -1
  82. package/dist/shims/internal/parse-cookie-header.d.ts +12 -0
  83. package/dist/shims/internal/parse-cookie-header.d.ts.map +1 -0
  84. package/dist/shims/internal/parse-cookie-header.js +32 -0
  85. package/dist/shims/internal/parse-cookie-header.js.map +1 -0
  86. package/dist/shims/link.d.ts +2 -1
  87. package/dist/shims/link.d.ts.map +1 -1
  88. package/dist/shims/link.js +8 -2
  89. package/dist/shims/link.js.map +1 -1
  90. package/dist/shims/navigation.d.ts +3 -7
  91. package/dist/shims/navigation.d.ts.map +1 -1
  92. package/dist/shims/navigation.js +20 -10
  93. package/dist/shims/navigation.js.map +1 -1
  94. package/dist/shims/readonly-url-search-params.d.ts +11 -0
  95. package/dist/shims/readonly-url-search-params.d.ts.map +1 -0
  96. package/dist/shims/readonly-url-search-params.js +24 -0
  97. package/dist/shims/readonly-url-search-params.js.map +1 -0
  98. package/dist/shims/router.d.ts +4 -3
  99. package/dist/shims/router.d.ts.map +1 -1
  100. package/dist/shims/router.js +42 -29
  101. package/dist/shims/router.js.map +1 -1
  102. package/dist/shims/server.d.ts +1 -1
  103. package/dist/shims/server.d.ts.map +1 -1
  104. package/dist/shims/server.js +7 -13
  105. package/dist/shims/server.js.map +1 -1
  106. package/dist/utils/manifest-paths.d.ts +4 -0
  107. package/dist/utils/manifest-paths.d.ts.map +1 -0
  108. package/dist/utils/manifest-paths.js +20 -0
  109. package/dist/utils/manifest-paths.js.map +1 -0
  110. package/dist/utils/query.d.ts +9 -0
  111. package/dist/utils/query.d.ts.map +1 -1
  112. package/dist/utils/query.js +59 -9
  113. package/dist/utils/query.js.map +1 -1
  114. package/package.json +1 -1
@@ -19,8 +19,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
19
19
  */
20
20
  import { forwardRef, useActionState } from "react";
21
21
  import { isDangerousScheme } from "./url-safety.js";
22
+ import { toSameOriginPath } from "./url-utils.js";
22
23
  // Re-export useActionState from React 19 to match Next.js's next/form module
23
24
  export { useActionState };
25
+ const SUPPORTED_FORM_ENCTYPE = "application/x-www-form-urlencoded";
26
+ const SUPPORTED_FORM_METHOD = "GET";
27
+ const SUPPORTED_FORM_TARGET = "_self";
24
28
  function isSafeAction(action) {
25
29
  // Block dangerous URI schemes
26
30
  if (isDangerousScheme(action))
@@ -44,6 +48,86 @@ function isSafeAction(action) {
44
48
  }
45
49
  return true;
46
50
  }
51
+ function getSubmitter(nativeEvent) {
52
+ const submitter = nativeEvent &&
53
+ typeof nativeEvent === "object" &&
54
+ "submitter" in nativeEvent &&
55
+ nativeEvent.submitter instanceof Element
56
+ ? nativeEvent.submitter
57
+ : null;
58
+ if (submitter instanceof HTMLButtonElement || submitter instanceof HTMLInputElement) {
59
+ return submitter;
60
+ }
61
+ return null;
62
+ }
63
+ function getEffectiveMethod(submitter, formMethod) {
64
+ const override = submitter?.getAttribute("formmethod");
65
+ return (override ?? formMethod ?? "GET").toUpperCase();
66
+ }
67
+ function getEffectiveAction(submitter, formAction) {
68
+ return submitter?.getAttribute("formaction") ?? formAction;
69
+ }
70
+ function checkFormActionUrl(action, source) {
71
+ const aPropName = source === "action" ? "an `action`" : "a `formAction`";
72
+ let testUrl;
73
+ try {
74
+ testUrl = new URL(action, "http://n");
75
+ }
76
+ catch {
77
+ console.error(`<Form> received ${aPropName} that cannot be parsed as a URL: "${action}".`);
78
+ return;
79
+ }
80
+ if (testUrl.searchParams.size) {
81
+ console.warn(`<Form> received ${aPropName} that contains search params: "${action}". This is not supported, and they will be ignored. ` +
82
+ `If you need to pass in additional search params, use an \`<input type="hidden" />\` instead.`);
83
+ }
84
+ }
85
+ function hasUnsupportedSubmitterAttributes(submitter) {
86
+ const formEncType = submitter.getAttribute("formenctype");
87
+ if (formEncType !== null && formEncType !== SUPPORTED_FORM_ENCTYPE) {
88
+ console.error(`<Form>'s \`encType\` was set to an unsupported value via \`formEncType="${formEncType}"\`. ` +
89
+ `This will disable <Form>'s navigation functionality. If you need this, use a native <form> element instead.`);
90
+ return true;
91
+ }
92
+ const formMethod = submitter.getAttribute("formmethod");
93
+ if (formMethod !== null && formMethod.toUpperCase() !== SUPPORTED_FORM_METHOD) {
94
+ console.error(`<Form>'s \`method\` was set to an unsupported value via \`formMethod="${formMethod}"\`. ` +
95
+ `This will disable <Form>'s navigation functionality. If you need this, use a native <form> element instead.`);
96
+ return true;
97
+ }
98
+ const formTarget = submitter.getAttribute("formtarget");
99
+ if (formTarget !== null && formTarget !== SUPPORTED_FORM_TARGET) {
100
+ console.error(`<Form>'s \`target\` was set to an unsupported value via \`formTarget="${formTarget}"\`. ` +
101
+ `This will disable <Form>'s navigation functionality. If you need this, use a native <form> element instead.`);
102
+ return true;
103
+ }
104
+ return false;
105
+ }
106
+ function createFormSubmitDestinationUrl(action, form, submitter) {
107
+ const targetUrl = new URL(action, window.location.href);
108
+ if (targetUrl.searchParams.size) {
109
+ targetUrl.search = "";
110
+ }
111
+ const formData = buildFormData(form, submitter);
112
+ for (const [name, value] of formData) {
113
+ targetUrl.searchParams.append(name, typeof value === "string" ? value : value.name);
114
+ }
115
+ return toSameOriginPath(targetUrl.href) ?? targetUrl.href;
116
+ }
117
+ function buildFormData(form, submitter) {
118
+ if (!submitter)
119
+ return new FormData(form);
120
+ try {
121
+ return new FormData(form, submitter);
122
+ }
123
+ catch {
124
+ const formData = new FormData(form);
125
+ if (!submitter.disabled && submitter.name) {
126
+ formData.append(submitter.name, submitter.value);
127
+ }
128
+ return formData;
129
+ }
130
+ }
47
131
  const Form = forwardRef(function Form(props, ref) {
48
132
  const { action, replace = false, scroll = true, onSubmit, ...rest } = props;
49
133
  // If action is a function (server action), pass it directly to React
@@ -52,6 +136,9 @@ const Form = forwardRef(function Form(props, ref) {
52
136
  }
53
137
  // Block dangerous action URLs. Render <form> without action attribute
54
138
  // so it submits to the current page (safe default).
139
+ if (process.env.NODE_ENV !== "production") {
140
+ checkFormActionUrl(action, "action");
141
+ }
55
142
  if (!isSafeAction(action)) {
56
143
  if (process.env.NODE_ENV !== "production") {
57
144
  console.warn(`<Form> blocked unsafe action: ${action}`);
@@ -65,19 +152,27 @@ const Form = forwardRef(function Form(props, ref) {
65
152
  if (e.defaultPrevented)
66
153
  return;
67
154
  }
155
+ const submitter = getSubmitter(e.nativeEvent);
156
+ if (submitter && hasUnsupportedSubmitterAttributes(submitter)) {
157
+ return;
158
+ }
68
159
  // Only intercept GET forms for client-side navigation
69
- const method = (rest.method ?? "GET").toUpperCase();
160
+ const method = getEffectiveMethod(submitter, rest.method);
70
161
  if (method !== "GET")
71
162
  return;
72
- e.preventDefault();
73
- const formData = new FormData(e.currentTarget);
74
- const params = new URLSearchParams();
75
- for (const [key, value] of formData) {
76
- if (typeof value === "string") {
77
- params.append(key, value);
163
+ const effectiveAction = getEffectiveAction(submitter, action);
164
+ if (process.env.NODE_ENV !== "production" && submitter?.getAttribute("formaction") !== null) {
165
+ checkFormActionUrl(effectiveAction, "formAction");
166
+ }
167
+ if (!isSafeAction(effectiveAction)) {
168
+ if (process.env.NODE_ENV !== "production") {
169
+ console.warn(`<Form> blocked unsafe action: ${effectiveAction}`);
78
170
  }
171
+ e.preventDefault();
172
+ return;
79
173
  }
80
- const url = `${action}?${params.toString()}`;
174
+ e.preventDefault();
175
+ const url = createFormSubmitDestinationUrl(effectiveAction, e.currentTarget, submitter);
81
176
  // Navigate client-side
82
177
  if (typeof window.__VINEXT_RSC_NAVIGATE__ === "function") {
83
178
  // App Router: RSC navigation. Await so scroll happens after new content renders.
@@ -1 +1 @@
1
- {"version":3,"file":"form.js","sourceRoot":"","sources":["../../src/shims/form.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\n/**\n * next/form shim\n *\n * Progressive enhancement form component. In Next.js, this replaces\n * the standard <form> element with one that intercepts submissions\n * and performs client-side navigation for GET forms (search forms).\n *\n * For POST forms with server actions, it delegates to React's built-in\n * form action handling.\n *\n * Usage:\n * import Form from 'next/form';\n * <Form action=\"/search\">\n * <input name=\"q\" />\n * <button type=\"submit\">Search</button>\n * </Form>\n */\n\nimport { forwardRef, useActionState, type FormHTMLAttributes, type ForwardedRef } from \"react\";\nimport { isDangerousScheme } from \"./url-safety.js\";\n\n// Re-export useActionState from React 19 to match Next.js's next/form module\nexport { useActionState };\n\nfunction isSafeAction(action: string): boolean {\n // Block dangerous URI schemes\n if (isDangerousScheme(action)) return false;\n // Block protocol-relative URLs (//evil.com/...)\n if (action.startsWith(\"//\")) return false;\n // Block absolute URLs to external origins (client-side: compare origins)\n if (/^https?:\\/\\//i.test(action)) {\n if (typeof window !== \"undefined\") {\n try {\n const actionUrl = new URL(action);\n return actionUrl.origin === window.location.origin;\n } catch {\n return false;\n }\n }\n // Server-side: block all absolute URLs (can't compare origins)\n return false;\n }\n return true;\n}\n\ninterface FormProps extends FormHTMLAttributes<HTMLFormElement> {\n /** Target URL for GET forms, or server action for POST forms */\n action: string | ((formData: FormData) => void | Promise<void>);\n /** Replace instead of push in history (default: false) */\n replace?: boolean;\n /** Scroll to top after navigation (default: true) */\n scroll?: boolean;\n}\n\nconst Form = forwardRef(function Form(props: FormProps, ref: ForwardedRef<HTMLFormElement>) {\n const { action, replace = false, scroll = true, onSubmit, ...rest } = props;\n\n // If action is a function (server action), pass it directly to React\n if (typeof action === \"function\") {\n return <form ref={ref} action={action as any} onSubmit={onSubmit as any} {...rest} />;\n }\n\n // Block dangerous action URLs. Render <form> without action attribute\n // so it submits to the current page (safe default).\n if (!isSafeAction(action)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(`<Form> blocked unsafe action: ${action}`);\n }\n return <form ref={ref} onSubmit={onSubmit as any} {...rest} />;\n }\n\n async function handleSubmit(e: any) {\n // Call user's onSubmit first\n if (onSubmit) {\n (onSubmit as any)(e);\n if (e.defaultPrevented) return;\n }\n\n // Only intercept GET forms for client-side navigation\n const method = (rest.method ?? \"GET\").toUpperCase();\n if (method !== \"GET\") return;\n\n e.preventDefault();\n\n const formData = new FormData(e.currentTarget);\n const params = new URLSearchParams();\n for (const [key, value] of formData) {\n if (typeof value === \"string\") {\n params.append(key, value);\n }\n }\n\n const url = `${action as string}?${params.toString()}`;\n\n // Navigate client-side\n if (typeof window.__VINEXT_RSC_NAVIGATE__ === \"function\") {\n // App Router: RSC navigation. Await so scroll happens after new content renders.\n if (replace) {\n window.history.replaceState(null, \"\", url);\n } else {\n window.history.pushState(null, \"\", url);\n }\n await window.__VINEXT_RSC_NAVIGATE__(url);\n } else {\n // Pages Router: use router or fallback\n if (replace) {\n window.history.replaceState({}, \"\", url);\n } else {\n window.history.pushState({}, \"\", url);\n }\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }\n\n if (scroll) {\n window.scrollTo(0, 0);\n }\n }\n\n return <form ref={ref} action={action} onSubmit={handleSubmit} {...rest} />;\n});\n\nexport default Form;\n"]}
1
+ {"version":3,"file":"form.js","sourceRoot":"","sources":["../../src/shims/form.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\n/**\n * next/form shim\n *\n * Progressive enhancement form component. In Next.js, this replaces\n * the standard <form> element with one that intercepts submissions\n * and performs client-side navigation for GET forms (search forms).\n *\n * For POST forms with server actions, it delegates to React's built-in\n * form action handling.\n *\n * Usage:\n * import Form from 'next/form';\n * <Form action=\"/search\">\n * <input name=\"q\" />\n * <button type=\"submit\">Search</button>\n * </Form>\n */\n\nimport { forwardRef, useActionState, type FormHTMLAttributes, type ForwardedRef } from \"react\";\nimport { isDangerousScheme } from \"./url-safety.js\";\nimport { toSameOriginPath } from \"./url-utils.js\";\n\n// Re-export useActionState from React 19 to match Next.js's next/form module\nexport { useActionState };\n\ntype FormSubmitter = HTMLButtonElement | HTMLInputElement;\nconst SUPPORTED_FORM_ENCTYPE = \"application/x-www-form-urlencoded\";\nconst SUPPORTED_FORM_METHOD = \"GET\";\nconst SUPPORTED_FORM_TARGET = \"_self\";\n\nfunction isSafeAction(action: string): boolean {\n // Block dangerous URI schemes\n if (isDangerousScheme(action)) return false;\n // Block protocol-relative URLs (//evil.com/...)\n if (action.startsWith(\"//\")) return false;\n // Block absolute URLs to external origins (client-side: compare origins)\n if (/^https?:\\/\\//i.test(action)) {\n if (typeof window !== \"undefined\") {\n try {\n const actionUrl = new URL(action);\n return actionUrl.origin === window.location.origin;\n } catch {\n return false;\n }\n }\n // Server-side: block all absolute URLs (can't compare origins)\n return false;\n }\n return true;\n}\n\nfunction getSubmitter(nativeEvent: unknown): FormSubmitter | null {\n const submitter =\n nativeEvent &&\n typeof nativeEvent === \"object\" &&\n \"submitter\" in nativeEvent &&\n nativeEvent.submitter instanceof Element\n ? nativeEvent.submitter\n : null;\n\n if (submitter instanceof HTMLButtonElement || submitter instanceof HTMLInputElement) {\n return submitter;\n }\n return null;\n}\n\nfunction getEffectiveMethod(\n submitter: FormSubmitter | null,\n formMethod: FormHTMLAttributes<HTMLFormElement>[\"method\"],\n): string {\n const override = submitter?.getAttribute(\"formmethod\");\n return (override ?? formMethod ?? \"GET\").toUpperCase();\n}\n\nfunction getEffectiveAction(submitter: FormSubmitter | null, formAction: string): string {\n return submitter?.getAttribute(\"formaction\") ?? formAction;\n}\n\nfunction checkFormActionUrl(action: string, source: \"action\" | \"formAction\"): void {\n const aPropName = source === \"action\" ? \"an `action`\" : \"a `formAction`\";\n\n let testUrl: URL;\n try {\n testUrl = new URL(action, \"http://n\");\n } catch {\n console.error(`<Form> received ${aPropName} that cannot be parsed as a URL: \"${action}\".`);\n return;\n }\n\n if (testUrl.searchParams.size) {\n console.warn(\n `<Form> received ${aPropName} that contains search params: \"${action}\". This is not supported, and they will be ignored. ` +\n `If you need to pass in additional search params, use an \\`<input type=\"hidden\" />\\` instead.`,\n );\n }\n}\n\nfunction hasUnsupportedSubmitterAttributes(submitter: FormSubmitter): boolean {\n const formEncType = submitter.getAttribute(\"formenctype\");\n if (formEncType !== null && formEncType !== SUPPORTED_FORM_ENCTYPE) {\n console.error(\n `<Form>'s \\`encType\\` was set to an unsupported value via \\`formEncType=\"${formEncType}\"\\`. ` +\n `This will disable <Form>'s navigation functionality. If you need this, use a native <form> element instead.`,\n );\n return true;\n }\n\n const formMethod = submitter.getAttribute(\"formmethod\");\n if (formMethod !== null && formMethod.toUpperCase() !== SUPPORTED_FORM_METHOD) {\n console.error(\n `<Form>'s \\`method\\` was set to an unsupported value via \\`formMethod=\"${formMethod}\"\\`. ` +\n `This will disable <Form>'s navigation functionality. If you need this, use a native <form> element instead.`,\n );\n return true;\n }\n\n const formTarget = submitter.getAttribute(\"formtarget\");\n if (formTarget !== null && formTarget !== SUPPORTED_FORM_TARGET) {\n console.error(\n `<Form>'s \\`target\\` was set to an unsupported value via \\`formTarget=\"${formTarget}\"\\`. ` +\n `This will disable <Form>'s navigation functionality. If you need this, use a native <form> element instead.`,\n );\n return true;\n }\n\n return false;\n}\n\nfunction createFormSubmitDestinationUrl(\n action: string,\n form: HTMLFormElement,\n submitter: FormSubmitter | null,\n): string {\n const targetUrl = new URL(action, window.location.href);\n if (targetUrl.searchParams.size) {\n targetUrl.search = \"\";\n }\n\n const formData = buildFormData(form, submitter);\n for (const [name, value] of formData) {\n targetUrl.searchParams.append(name, typeof value === \"string\" ? value : value.name);\n }\n\n return toSameOriginPath(targetUrl.href) ?? targetUrl.href;\n}\n\nfunction buildFormData(form: HTMLFormElement, submitter: FormSubmitter | null): FormData {\n if (!submitter) return new FormData(form);\n\n try {\n return new FormData(form, submitter);\n } catch {\n const formData = new FormData(form);\n if (!submitter.disabled && submitter.name) {\n formData.append(submitter.name, submitter.value);\n }\n return formData;\n }\n}\n\ninterface FormProps extends FormHTMLAttributes<HTMLFormElement> {\n /** Target URL for GET forms, or server action for POST forms */\n action: string | ((formData: FormData) => void | Promise<void>);\n /** Replace instead of push in history (default: false) */\n replace?: boolean;\n /** Scroll to top after navigation (default: true) */\n scroll?: boolean;\n}\n\nconst Form = forwardRef(function Form(props: FormProps, ref: ForwardedRef<HTMLFormElement>) {\n const { action, replace = false, scroll = true, onSubmit, ...rest } = props;\n\n // If action is a function (server action), pass it directly to React\n if (typeof action === \"function\") {\n return <form ref={ref} action={action as any} onSubmit={onSubmit as any} {...rest} />;\n }\n\n // Block dangerous action URLs. Render <form> without action attribute\n // so it submits to the current page (safe default).\n if (process.env.NODE_ENV !== \"production\") {\n checkFormActionUrl(action, \"action\");\n }\n\n if (!isSafeAction(action)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(`<Form> blocked unsafe action: ${action}`);\n }\n return <form ref={ref} onSubmit={onSubmit as any} {...rest} />;\n }\n\n async function handleSubmit(e: any) {\n // Call user's onSubmit first\n if (onSubmit) {\n (onSubmit as any)(e);\n if (e.defaultPrevented) return;\n }\n\n const submitter = getSubmitter(e.nativeEvent);\n if (submitter && hasUnsupportedSubmitterAttributes(submitter)) {\n return;\n }\n\n // Only intercept GET forms for client-side navigation\n const method = getEffectiveMethod(submitter, rest.method);\n if (method !== \"GET\") return;\n\n const effectiveAction = getEffectiveAction(submitter, action as string);\n if (process.env.NODE_ENV !== \"production\" && submitter?.getAttribute(\"formaction\") !== null) {\n checkFormActionUrl(effectiveAction, \"formAction\");\n }\n if (!isSafeAction(effectiveAction)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(`<Form> blocked unsafe action: ${effectiveAction}`);\n }\n e.preventDefault();\n return;\n }\n\n e.preventDefault();\n const url = createFormSubmitDestinationUrl(effectiveAction, e.currentTarget, submitter);\n\n // Navigate client-side\n if (typeof window.__VINEXT_RSC_NAVIGATE__ === \"function\") {\n // App Router: RSC navigation. Await so scroll happens after new content renders.\n if (replace) {\n window.history.replaceState(null, \"\", url);\n } else {\n window.history.pushState(null, \"\", url);\n }\n await window.__VINEXT_RSC_NAVIGATE__(url);\n } else {\n // Pages Router: use router or fallback\n if (replace) {\n window.history.replaceState({}, \"\", url);\n } else {\n window.history.pushState({}, \"\", url);\n }\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }\n\n if (scroll) {\n window.scrollTo(0, 0);\n }\n }\n\n return <form ref={ref} action={action} onSubmit={handleSubmit} {...rest} />;\n});\n\nexport default Form;\n"]}
@@ -10,7 +10,12 @@
10
10
  interface HeadersContext {
11
11
  headers: Headers;
12
12
  cookies: Map<string, string>;
13
+ accessError?: Error;
14
+ mutableCookies?: RequestCookies;
15
+ readonlyCookies?: RequestCookies;
16
+ readonlyHeaders?: Headers;
13
17
  }
18
+ export type HeadersAccessPhase = "render" | "action" | "route-handler";
14
19
  /**
15
20
  * Dynamic usage flag — set when a component calls connection(), cookies(),
16
21
  * headers(), or noStore() during rendering. When true, ISR caching is
@@ -34,6 +39,7 @@ export declare function throwIfInsideCacheScope(apiName: string): void;
34
39
  * Called by the server after rendering to decide on caching.
35
40
  */
36
41
  export declare function consumeDynamicUsage(): boolean;
42
+ export declare function setHeadersAccessPhase(phase: HeadersAccessPhase): HeadersAccessPhase;
37
43
  /**
38
44
  * Set the headers/cookies context for the current RSC render.
39
45
  * Called by the framework's RSC entry before rendering each request.
@@ -98,12 +104,12 @@ export declare function headersContextFromRequest(request: Request): HeadersCont
98
104
  * Returns a Promise in Next.js 15+ style (but resolves synchronously since
99
105
  * the context is already available).
100
106
  */
101
- export declare function headers(): Promise<Headers>;
107
+ export declare function headers(): Promise<Headers> & Headers;
102
108
  /**
103
109
  * Cookie jar from the incoming request.
104
110
  * Returns a ReadonlyRequestCookies-like object.
105
111
  */
106
- export declare function cookies(): Promise<RequestCookies>;
112
+ export declare function cookies(): Promise<RequestCookies> & RequestCookies;
107
113
  /** Accumulated Set-Cookie headers from cookies().set() / .delete() calls */
108
114
  /**
109
115
  * Get and clear all pending Set-Cookie headers generated by cookies().set()/delete().
@@ -135,7 +141,9 @@ declare class RequestCookies {
135
141
  name: string;
136
142
  value: string;
137
143
  } | undefined;
138
- getAll(): Array<{
144
+ getAll(nameOrOptions?: string | {
145
+ name: string;
146
+ }): Array<{
139
147
  name: string;
140
148
  value: string;
141
149
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../src/shims/headers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../src/shims/headers.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import { AsyncLocalStorage } from "node:async_hooks";
11
11
  import { buildRequestHeadersFromMiddlewareResponse } from "../server/middleware-request-headers.js";
12
+ import { parseCookieHeader } from "./internal/parse-cookie-header.js";
12
13
  // NOTE:
13
14
  // - This shim can be loaded under multiple module specifiers in Vite's
14
15
  // multi-environment setup (RSC/SSR). Store the AsyncLocalStorage on
@@ -26,6 +27,7 @@ const _fallbackState = (_g[_FALLBACK_KEY] ??= {
26
27
  dynamicUsageDetected: false,
27
28
  pendingSetCookies: [],
28
29
  draftModeCookieHeader: null,
30
+ phase: "render",
29
31
  });
30
32
  function _getState() {
31
33
  const state = _als.getStore();
@@ -92,6 +94,18 @@ export function consumeDynamicUsage() {
92
94
  state.dynamicUsageDetected = false;
93
95
  return used;
94
96
  }
97
+ function _setStatePhase(state, phase) {
98
+ const previous = state.phase;
99
+ state.phase = phase;
100
+ return previous;
101
+ }
102
+ function _areCookiesMutableInCurrentPhase() {
103
+ const phase = _getState().phase;
104
+ return phase === "action" || phase === "route-handler";
105
+ }
106
+ export function setHeadersAccessPhase(phase) {
107
+ return _setStatePhase(_getState(), phase);
108
+ }
95
109
  /**
96
110
  * Set the headers/cookies context for the current RSC render.
97
111
  * Called by the framework's RSC entry before rendering each request.
@@ -120,12 +134,14 @@ export function setHeadersContext(ctx) {
120
134
  existing.dynamicUsageDetected = false;
121
135
  existing.pendingSetCookies = [];
122
136
  existing.draftModeCookieHeader = null;
137
+ existing.phase = "render";
123
138
  }
124
139
  else {
125
140
  _fallbackState.headersContext = ctx;
126
141
  _fallbackState.dynamicUsageDetected = false;
127
142
  _fallbackState.pendingSetCookies = [];
128
143
  _fallbackState.draftModeCookieHeader = null;
144
+ _fallbackState.phase = "render";
129
145
  }
130
146
  return;
131
147
  }
@@ -134,9 +150,11 @@ export function setHeadersContext(ctx) {
134
150
  const state = _als.getStore();
135
151
  if (state) {
136
152
  state.headersContext = null;
153
+ state.phase = "render";
137
154
  }
138
155
  else {
139
156
  _fallbackState.headersContext = null;
157
+ _fallbackState.phase = "render";
140
158
  }
141
159
  }
142
160
  /**
@@ -155,6 +173,7 @@ export function runWithHeadersContext(ctx, fn) {
155
173
  dynamicUsageDetected: false,
156
174
  pendingSetCookies: [],
157
175
  draftModeCookieHeader: null,
176
+ phase: "render",
158
177
  };
159
178
  return _als.run(state, fn);
160
179
  }
@@ -183,16 +202,126 @@ export function applyMiddlewareRequestHeaders(middlewareResponseHeaders) {
183
202
  // If middleware modified the cookie header, rebuild the cookies map.
184
203
  ctx.cookies.clear();
185
204
  if (nextCookieHeader !== null) {
186
- for (const part of nextCookieHeader.split(";")) {
187
- const [k, ...rest] = part.split("=");
188
- if (k) {
189
- ctx.cookies.set(k.trim(), rest.join("=").trim());
190
- }
205
+ const nextCookies = parseCookieHeader(nextCookieHeader);
206
+ for (const [name, value] of nextCookies) {
207
+ ctx.cookies.set(name, value);
191
208
  }
192
209
  }
193
210
  }
194
211
  /** Methods on `Headers` that mutate state. Hoisted to module scope — static. */
195
212
  const _HEADERS_MUTATING_METHODS = new Set(["set", "delete", "append"]);
213
+ class ReadonlyHeadersError extends Error {
214
+ constructor() {
215
+ super("Headers cannot be modified. Read more: https://nextjs.org/docs/app/api-reference/functions/headers");
216
+ }
217
+ static callable() {
218
+ throw new ReadonlyHeadersError();
219
+ }
220
+ }
221
+ class ReadonlyRequestCookiesError extends Error {
222
+ constructor() {
223
+ super("Cookies can only be modified in a Server Action or Route Handler. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#options");
224
+ }
225
+ static callable() {
226
+ throw new ReadonlyRequestCookiesError();
227
+ }
228
+ }
229
+ function _decorateRequestApiPromise(promise, target) {
230
+ return new Proxy(promise, {
231
+ get(promiseTarget, prop) {
232
+ if (prop in promiseTarget) {
233
+ const value = Reflect.get(promiseTarget, prop, promiseTarget);
234
+ return typeof value === "function" ? value.bind(promiseTarget) : value;
235
+ }
236
+ const value = Reflect.get(target, prop, target);
237
+ return typeof value === "function" ? value.bind(target) : value;
238
+ },
239
+ has(promiseTarget, prop) {
240
+ return prop in promiseTarget || prop in target;
241
+ },
242
+ ownKeys(promiseTarget) {
243
+ return Array.from(new Set([...Reflect.ownKeys(promiseTarget), ...Reflect.ownKeys(target)]));
244
+ },
245
+ getOwnPropertyDescriptor(promiseTarget, prop) {
246
+ return (Reflect.getOwnPropertyDescriptor(promiseTarget, prop) ??
247
+ Reflect.getOwnPropertyDescriptor(target, prop));
248
+ },
249
+ });
250
+ }
251
+ function _decorateRejectedRequestApiPromise(error) {
252
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
253
+ const promise = Promise.reject(normalizedError);
254
+ // Mark the rejection as handled so legacy sync access does not trigger
255
+ // spurious unhandled rejection noise before callers await/catch it.
256
+ promise.catch(() => { });
257
+ const throwingTarget = new Proxy({}, {
258
+ get(_target, prop) {
259
+ if (prop === "then" || prop === "catch" || prop === "finally") {
260
+ return undefined;
261
+ }
262
+ throw normalizedError;
263
+ },
264
+ });
265
+ return _decorateRequestApiPromise(promise, throwingTarget);
266
+ }
267
+ function _sealHeaders(headers) {
268
+ return new Proxy(headers, {
269
+ get(target, prop) {
270
+ if (typeof prop === "string" && _HEADERS_MUTATING_METHODS.has(prop)) {
271
+ throw new ReadonlyHeadersError();
272
+ }
273
+ const value = Reflect.get(target, prop, target);
274
+ return typeof value === "function" ? value.bind(target) : value;
275
+ },
276
+ });
277
+ }
278
+ function _wrapMutableCookies(cookies) {
279
+ return new Proxy(cookies, {
280
+ get(target, prop) {
281
+ if (prop === "set" || prop === "delete") {
282
+ return (...args) => {
283
+ if (!_areCookiesMutableInCurrentPhase()) {
284
+ throw new ReadonlyRequestCookiesError();
285
+ }
286
+ return Reflect.get(target, prop, target).apply(target, args);
287
+ };
288
+ }
289
+ const value = Reflect.get(target, prop, target);
290
+ return typeof value === "function" ? value.bind(target) : value;
291
+ },
292
+ });
293
+ }
294
+ function _sealCookies(cookies) {
295
+ return new Proxy(cookies, {
296
+ get(target, prop) {
297
+ if (prop === "set" || prop === "delete") {
298
+ throw new ReadonlyRequestCookiesError();
299
+ }
300
+ const value = Reflect.get(target, prop, target);
301
+ return typeof value === "function" ? value.bind(target) : value;
302
+ },
303
+ });
304
+ }
305
+ function _getMutableCookies(ctx) {
306
+ if (!ctx.mutableCookies) {
307
+ ctx.mutableCookies = _wrapMutableCookies(new RequestCookies(ctx.cookies));
308
+ }
309
+ return ctx.mutableCookies;
310
+ }
311
+ function _getReadonlyCookies(ctx) {
312
+ if (!ctx.readonlyCookies) {
313
+ // Keep a separate readonly wrapper so render-path reads avoid the
314
+ // mutable phase-checking proxy while still reflecting the shared cookie map.
315
+ ctx.readonlyCookies = _sealCookies(new RequestCookies(ctx.cookies));
316
+ }
317
+ return ctx.readonlyCookies;
318
+ }
319
+ function _getReadonlyHeaders(ctx) {
320
+ if (!ctx.readonlyHeaders) {
321
+ ctx.readonlyHeaders = _sealHeaders(ctx.headers);
322
+ }
323
+ return ctx.readonlyHeaders;
324
+ }
196
325
  /**
197
326
  * Create a HeadersContext from a standard Request object.
198
327
  *
@@ -250,15 +379,9 @@ export function headersContextFromRequest(request) {
250
379
  function getCookies() {
251
380
  if (_cookies)
252
381
  return _cookies;
253
- _cookies = new Map();
254
382
  // Read from the proxy so middleware-modified cookie headers are respected.
255
383
  const cookieHeader = headersProxy.get("cookie") || "";
256
- for (const part of cookieHeader.split(";")) {
257
- const [key, ...rest] = part.split("=");
258
- if (key) {
259
- _cookies.set(key.trim(), rest.join("=").trim());
260
- }
261
- }
384
+ _cookies = parseCookieHeader(cookieHeader);
262
385
  return _cookies;
263
386
  }
264
387
  // Expose cookies as a lazy getter that memoises on first access.
@@ -278,28 +401,48 @@ export function headersContextFromRequest(request) {
278
401
  * Returns a Promise in Next.js 15+ style (but resolves synchronously since
279
402
  * the context is already available).
280
403
  */
281
- export async function headers() {
282
- throwIfInsideCacheScope("headers()");
404
+ export function headers() {
405
+ try {
406
+ throwIfInsideCacheScope("headers()");
407
+ }
408
+ catch (error) {
409
+ return _decorateRejectedRequestApiPromise(error);
410
+ }
283
411
  const state = _getState();
284
412
  if (!state.headersContext) {
285
- throw new Error("headers() can only be called from a Server Component, Route Handler, " +
286
- "or Server Action. Make sure you're not calling it from a Client Component.");
413
+ return _decorateRejectedRequestApiPromise(new Error("headers() can only be called from a Server Component, Route Handler, " +
414
+ "or Server Action. Make sure you're not calling it from a Client Component."));
415
+ }
416
+ if (state.headersContext.accessError) {
417
+ return _decorateRejectedRequestApiPromise(state.headersContext.accessError);
287
418
  }
288
419
  markDynamicUsage();
289
- return state.headersContext.headers;
420
+ const readonlyHeaders = _getReadonlyHeaders(state.headersContext);
421
+ return _decorateRequestApiPromise(Promise.resolve(readonlyHeaders), readonlyHeaders);
290
422
  }
291
423
  /**
292
424
  * Cookie jar from the incoming request.
293
425
  * Returns a ReadonlyRequestCookies-like object.
294
426
  */
295
- export async function cookies() {
296
- throwIfInsideCacheScope("cookies()");
427
+ export function cookies() {
428
+ try {
429
+ throwIfInsideCacheScope("cookies()");
430
+ }
431
+ catch (error) {
432
+ return _decorateRejectedRequestApiPromise(error);
433
+ }
297
434
  const state = _getState();
298
435
  if (!state.headersContext) {
299
- throw new Error("cookies() can only be called from a Server Component, Route Handler, " + "or Server Action.");
436
+ return _decorateRejectedRequestApiPromise(new Error("cookies() can only be called from a Server Component, Route Handler, or Server Action."));
437
+ }
438
+ if (state.headersContext.accessError) {
439
+ return _decorateRejectedRequestApiPromise(state.headersContext.accessError);
300
440
  }
301
441
  markDynamicUsage();
302
- return new RequestCookies(state.headersContext.cookies);
442
+ const cookieStore = _areCookiesMutableInCurrentPhase()
443
+ ? _getMutableCookies(state.headersContext)
444
+ : _getReadonlyCookies(state.headersContext);
445
+ return _decorateRequestApiPromise(Promise.resolve(cookieStore), cookieStore);
303
446
  }
304
447
  // ---------------------------------------------------------------------------
305
448
  // Writable cookie accumulator for Route Handlers / Server Actions
@@ -350,8 +493,11 @@ export function getDraftModeCookieHeader() {
350
493
  */
351
494
  export async function draftMode() {
352
495
  throwIfInsideCacheScope("draftMode()");
353
- markDynamicUsage();
354
496
  const state = _getState();
497
+ if (state.headersContext?.accessError) {
498
+ throw state.headersContext.accessError;
499
+ }
500
+ markDynamicUsage();
355
501
  const secret = getDraftSecret();
356
502
  const isEnabled = state.headersContext
357
503
  ? state.headersContext.cookies.get(DRAFT_MODE_COOKIE) === secret
@@ -359,6 +505,9 @@ export async function draftMode() {
359
505
  return {
360
506
  isEnabled,
361
507
  enable() {
508
+ if (state.headersContext?.accessError) {
509
+ throw state.headersContext.accessError;
510
+ }
362
511
  if (state.headersContext) {
363
512
  state.headersContext.cookies.set(DRAFT_MODE_COOKIE, secret);
364
513
  }
@@ -366,6 +515,9 @@ export async function draftMode() {
366
515
  state.draftModeCookieHeader = `${DRAFT_MODE_COOKIE}=${secret}; Path=/; HttpOnly; SameSite=Lax${secure}`;
367
516
  },
368
517
  disable() {
518
+ if (state.headersContext?.accessError) {
519
+ throw state.headersContext.accessError;
520
+ }
369
521
  if (state.headersContext) {
370
522
  state.headersContext.cookies.delete(DRAFT_MODE_COOKIE);
371
523
  }
@@ -413,10 +565,13 @@ class RequestCookies {
413
565
  return undefined;
414
566
  return { name, value };
415
567
  }
416
- getAll() {
568
+ getAll(nameOrOptions) {
569
+ const name = typeof nameOrOptions === "string" ? nameOrOptions : nameOrOptions?.name;
417
570
  const result = [];
418
- for (const [name, value] of this._cookies) {
419
- result.push({ name, value });
571
+ for (const [cookieName, value] of this._cookies) {
572
+ if (name === undefined || cookieName === name) {
573
+ result.push({ name: cookieName, value });
574
+ }
420
575
  }
421
576
  return result;
422
577
  }