vinext 1.0.0-beta.2 → 1.0.0-beta.4
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.
- package/README.md +6 -9
- package/dist/build/client-build-config.js +7 -1
- package/dist/build/precompress.js +1 -1
- package/dist/build/prerender.d.ts +2 -1
- package/dist/build/prerender.js +12 -2
- package/dist/check.js +4 -0
- package/dist/cli-args.d.ts +2 -1
- package/dist/cli-args.js +10 -0
- package/dist/cli.js +14 -8
- package/dist/client/navigation-runtime.d.ts +6 -0
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/config-matchers.js +4 -1
- package/dist/config/dotenv.d.ts +3 -4
- package/dist/config/dotenv.js +30 -22
- package/dist/config/next-config.d.ts +16 -5
- package/dist/config/next-config.js +7 -0
- package/dist/entries/app-browser-entry.d.ts +4 -10
- package/dist/entries/app-browser-entry.js +20 -4
- package/dist/entries/app-rsc-entry.js +21 -3
- package/dist/entries/app-rsc-manifest.js +19 -0
- package/dist/entries/pages-client-entry.js +0 -1
- package/dist/entries/pages-server-entry.js +13 -3
- package/dist/index.js +122 -49
- package/dist/init-cloudflare.d.ts +3 -1
- package/dist/init-cloudflare.js +59 -5
- package/dist/plugins/client-reference-dedup.js +7 -5
- package/dist/plugins/extensionless-dynamic-import.js +23 -18
- package/dist/plugins/ignore-dynamic-requests.js +3 -1
- package/dist/plugins/import-meta-url.js +17 -6
- package/dist/plugins/require-context.js +20 -15
- package/dist/plugins/sass.js +3 -4
- package/dist/plugins/transform-cache.d.ts +19 -0
- package/dist/plugins/transform-cache.js +36 -0
- package/dist/routing/app-route-graph.d.ts +14 -6
- package/dist/routing/app-route-graph.js +106 -16
- package/dist/server/api-handler.d.ts +2 -0
- package/dist/server/api-handler.js +7 -6
- package/dist/server/app-bfcache-identity.js +28 -2
- package/dist/server/app-browser-entry.js +175 -75
- package/dist/server/app-browser-navigation-controller.d.ts +23 -21
- package/dist/server/app-browser-navigation-controller.js +30 -5
- package/dist/server/app-browser-prefetch-response.d.ts +9 -0
- package/dist/server/app-browser-prefetch-response.js +32 -0
- package/dist/server/app-browser-state.d.ts +8 -3
- package/dist/server/app-browser-state.js +9 -3
- package/dist/server/app-page-cache-finalizer.js +1 -1
- package/dist/server/app-page-cache.d.ts +1 -1
- package/dist/server/app-page-cache.js +16 -2
- package/dist/server/app-page-dispatch.d.ts +9 -1
- package/dist/server/app-page-dispatch.js +37 -8
- package/dist/server/app-page-element-builder.d.ts +4 -1
- package/dist/server/app-page-element-builder.js +34 -7
- package/dist/server/app-page-head.d.ts +3 -3
- package/dist/server/app-page-head.js +58 -13
- package/dist/server/app-page-http-access-fallback-metadata.d.ts +2 -2
- package/dist/server/app-page-http-access-fallback-metadata.js +9 -1
- package/dist/server/app-page-probe.d.ts +4 -0
- package/dist/server/app-page-probe.js +6 -2
- package/dist/server/app-page-render.d.ts +1 -1
- package/dist/server/app-page-render.js +13 -3
- package/dist/server/app-page-request.d.ts +3 -1
- package/dist/server/app-page-request.js +4 -13
- package/dist/server/app-page-response.d.ts +2 -0
- package/dist/server/app-page-response.js +7 -2
- package/dist/server/app-page-route-wiring.d.ts +10 -2
- package/dist/server/app-page-route-wiring.js +269 -59
- package/dist/server/app-pages-bridge.d.ts +2 -1
- package/dist/server/app-pages-bridge.js +3 -1
- package/dist/server/app-route-handler-cache.js +4 -0
- package/dist/server/app-route-handler-dispatch.js +9 -3
- package/dist/server/app-route-handler-response.js +1 -1
- package/dist/server/app-route-module-loader.d.ts +6 -0
- package/dist/server/app-route-module-loader.js +3 -0
- package/dist/server/app-router-entry.js +6 -3
- package/dist/server/app-rsc-cache-busting.d.ts +7 -0
- package/dist/server/app-rsc-cache-busting.js +6 -0
- package/dist/server/app-rsc-errors.js +10 -0
- package/dist/server/app-rsc-handler.d.ts +2 -0
- package/dist/server/app-rsc-handler.js +30 -13
- package/dist/server/app-rsc-render-mode.d.ts +3 -2
- package/dist/server/app-rsc-render-mode.js +4 -1
- package/dist/server/app-rsc-request-normalization.js +65 -4
- package/dist/server/app-rsc-route-matching.d.ts +9 -0
- package/dist/server/app-rsc-route-matching.js +6 -0
- package/dist/server/app-server-action-execution.d.ts +1 -1
- package/dist/server/app-ssr-entry.js +4 -4
- package/dist/server/app-visited-response-cache.d.ts +6 -1
- package/dist/server/app-visited-response-cache.js +49 -1
- package/dist/server/cache-control.d.ts +2 -2
- package/dist/server/cache-control.js +2 -1
- package/dist/server/dev-server.d.ts +3 -1
- package/dist/server/dev-server.js +204 -348
- package/dist/server/edge-api-runtime.d.ts +10 -1
- package/dist/server/edge-api-runtime.js +29 -1
- package/dist/server/headers.d.ts +4 -2
- package/dist/server/headers.js +6 -3
- package/dist/server/isr-cache.d.ts +10 -33
- package/dist/server/isr-cache.js +33 -43
- package/dist/server/isr-decision.d.ts +2 -2
- package/dist/server/pages-api-route.d.ts +4 -0
- package/dist/server/pages-api-route.js +6 -3
- package/dist/server/pages-asset-tags.d.ts +1 -0
- package/dist/server/pages-asset-tags.js +6 -4
- package/dist/server/pages-dev-hydration.js +0 -1
- package/dist/server/pages-document-asset-props.d.ts +26 -0
- package/dist/server/pages-document-asset-props.js +69 -0
- package/dist/server/pages-get-initial-props.d.ts +1 -1
- package/dist/server/pages-get-initial-props.js +1 -4
- package/dist/server/pages-i18n.js +64 -16
- package/dist/server/pages-node-compat.d.ts +2 -0
- package/dist/server/pages-node-compat.js +10 -6
- package/dist/server/pages-page-data.d.ts +61 -9
- package/dist/server/pages-page-data.js +334 -74
- package/dist/server/pages-page-handler.d.ts +6 -1
- package/dist/server/pages-page-handler.js +119 -20
- package/dist/server/pages-page-response.d.ts +7 -3
- package/dist/server/pages-page-response.js +41 -33
- package/dist/server/pages-request-pipeline.d.ts +7 -0
- package/dist/server/pages-request-pipeline.js +5 -1
- package/dist/server/pages-revalidate.d.ts +1 -1
- package/dist/server/pages-revalidate.js +54 -8
- package/dist/server/pages-router-entry.d.ts +1 -0
- package/dist/server/pages-router-entry.js +10 -4
- package/dist/server/prerender-manifest.d.ts +1 -0
- package/dist/server/prod-server.d.ts +2 -1
- package/dist/server/prod-server.js +38 -13
- package/dist/server/revalidation-host.d.ts +11 -0
- package/dist/server/revalidation-host.js +19 -0
- package/dist/server/seed-cache.js +1 -1
- package/dist/server/worker-revalidation-context.d.ts +13 -0
- package/dist/server/worker-revalidation-context.js +30 -0
- package/dist/shims/app-router-scroll-state.d.ts +2 -1
- package/dist/shims/app-router-scroll-state.js +7 -2
- package/dist/shims/cache-handler.d.ts +1 -1
- package/dist/shims/cache-handler.js +10 -7
- package/dist/shims/cache-runtime.d.ts +6 -0
- package/dist/shims/cache-runtime.js +4 -1
- package/dist/shims/cache.js +1 -1
- package/dist/shims/document.js +15 -2
- package/dist/shims/error.js +1 -1
- package/dist/shims/fetch-cache.js +1 -1
- package/dist/shims/font-google-base.js +17 -8
- package/dist/shims/font-local.js +41 -10
- package/dist/shims/hash-scroll.d.ts +1 -1
- package/dist/shims/hash-scroll.js +2 -1
- package/dist/shims/headers.d.ts +10 -13
- package/dist/shims/headers.js +85 -36
- package/dist/shims/internal/cookie-serialize.d.ts +10 -9
- package/dist/shims/internal/cookie-serialize.js +9 -8
- package/dist/shims/internal/interpolate-as.d.ts +15 -1
- package/dist/shims/internal/interpolate-as.js +27 -2
- package/dist/shims/link.d.ts +2 -0
- package/dist/shims/link.js +77 -24
- package/dist/shims/metadata.d.ts +18 -34
- package/dist/shims/metadata.js +98 -56
- package/dist/shims/navigation.d.ts +18 -2
- package/dist/shims/navigation.js +70 -21
- package/dist/shims/request-context.d.ts +6 -2
- package/dist/shims/router.js +18 -7
- package/dist/shims/script.js +1 -1
- package/dist/shims/server.d.ts +7 -6
- package/dist/shims/server.js +156 -57
- package/dist/shims/slot.d.ts +2 -1
- package/dist/shims/slot.js +6 -2
- package/dist/shims/streamed-icons.d.ts +9 -0
- package/dist/shims/streamed-icons.js +33 -0
- package/dist/shims/unified-request-context.d.ts +21 -2
- package/dist/shims/unified-request-context.js +82 -1
- package/dist/utils/cache-control-metadata.d.ts +2 -1
- package/dist/utils/cache-control-metadata.js +5 -1
- package/dist/utils/html-limited-bots.js +1 -1
- package/dist/utils/protocol-headers.d.ts +7 -1
- package/dist/utils/protocol-headers.js +7 -1
- package/package.json +1 -1
package/dist/shims/font-local.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { fnv1a64 } from "../utils/hash.js";
|
|
1
2
|
import { escapeCSSString, formatFontClassRule, getFontMimeType, resolveSingleFaceStyle, sanitizeCSSVarName, sanitizeFallback, sanitizeFontDescriptorValue } from "./font-utils.js";
|
|
2
3
|
//#region src/shims/font-local.ts
|
|
3
4
|
/**
|
|
@@ -31,8 +32,15 @@ function sanitizeInternalFontFamily(name) {
|
|
|
31
32
|
if (typeof name !== "string" || name.length === 0) return void 0;
|
|
32
33
|
if (/^[$_a-zA-Z][$_a-zA-Z0-9]*$/.test(name)) return name;
|
|
33
34
|
}
|
|
34
|
-
|
|
35
|
-
const
|
|
35
|
+
const _INJECTED_FONTS_KEY = Symbol.for("vinext.fontLocal.injectedFonts");
|
|
36
|
+
const _INJECTED_CLASS_RULES_KEY = Symbol.for("vinext.fontLocal.injectedClassRules");
|
|
37
|
+
const _INJECTED_VARIABLE_RULES_KEY = Symbol.for("vinext.fontLocal.injectedVariableRules");
|
|
38
|
+
const _INJECTED_ROOT_VARIABLES_KEY = Symbol.for("vinext.fontLocal.injectedRootVariables");
|
|
39
|
+
const _SSR_FONT_STYLES_KEY = Symbol.for("vinext.fontLocal.ssrFontStyles");
|
|
40
|
+
const _SSR_FONT_PRELOADS_KEY = Symbol.for("vinext.fontLocal.ssrFontPreloads");
|
|
41
|
+
const _SSR_FONT_PRELOAD_HREFS_KEY = Symbol.for("vinext.fontLocal.ssrFontPreloadHrefs");
|
|
42
|
+
const _g = globalThis;
|
|
43
|
+
const injectedFonts = _g[_INJECTED_FONTS_KEY] ??= /* @__PURE__ */ new Set();
|
|
36
44
|
function generateFontFaceCSS(family, options, sources) {
|
|
37
45
|
const display = options.display ?? "swap";
|
|
38
46
|
const rules = [];
|
|
@@ -55,9 +63,9 @@ function generateFontFaceCSS(family, options, sources) {
|
|
|
55
63
|
}
|
|
56
64
|
return rules.join("\n");
|
|
57
65
|
}
|
|
58
|
-
const ssrFontStyles = [];
|
|
59
|
-
const ssrFontPreloads = [];
|
|
60
|
-
const ssrFontPreloadHrefs = /* @__PURE__ */ new Set();
|
|
66
|
+
const ssrFontStyles = _g[_SSR_FONT_STYLES_KEY] ??= [];
|
|
67
|
+
const ssrFontPreloads = _g[_SSR_FONT_PRELOADS_KEY] ??= [];
|
|
68
|
+
const ssrFontPreloadHrefs = _g[_SSR_FONT_PRELOAD_HREFS_KEY] ??= /* @__PURE__ */ new Set();
|
|
61
69
|
/**
|
|
62
70
|
* Get collected SSR font styles (used by the renderer).
|
|
63
71
|
* Note: We don't clear the arrays because fonts are loaded at module import
|
|
@@ -87,7 +95,7 @@ function injectFontFaceCSS(css, id) {
|
|
|
87
95
|
document.head.appendChild(style);
|
|
88
96
|
}
|
|
89
97
|
/** Track which className CSS rules have been injected. */
|
|
90
|
-
const injectedClassRules = /* @__PURE__ */ new Set();
|
|
98
|
+
const injectedClassRules = _g[_INJECTED_CLASS_RULES_KEY] ??= /* @__PURE__ */ new Set();
|
|
91
99
|
/**
|
|
92
100
|
* Inject a CSS rule that maps a className to the exported font style.
|
|
93
101
|
*
|
|
@@ -110,9 +118,9 @@ function injectClassNameRule(className, fontStyle) {
|
|
|
110
118
|
document.head.appendChild(style);
|
|
111
119
|
}
|
|
112
120
|
/** Track which variable class CSS rules have been injected. */
|
|
113
|
-
const injectedVariableRules = /* @__PURE__ */ new Set();
|
|
121
|
+
const injectedVariableRules = _g[_INJECTED_VARIABLE_RULES_KEY] ??= /* @__PURE__ */ new Set();
|
|
114
122
|
/** Track which :root CSS variable rules have been injected. */
|
|
115
|
-
const injectedRootVariables = /* @__PURE__ */ new Set();
|
|
123
|
+
const injectedRootVariables = _g[_INJECTED_ROOT_VARIABLES_KEY] ??= /* @__PURE__ */ new Set();
|
|
116
124
|
/**
|
|
117
125
|
* Inject a CSS rule that sets a CSS variable on an element.
|
|
118
126
|
* This is what makes `<html className={font.variable}>` set the CSS variable
|
|
@@ -151,6 +159,28 @@ function normalizeSources(options) {
|
|
|
151
159
|
return [options.src];
|
|
152
160
|
}
|
|
153
161
|
/**
|
|
162
|
+
* Derive a stable class identity from the inputs that affect the generated
|
|
163
|
+
* font CSS. Next.js hashes the generated font CSS for the same reason: class
|
|
164
|
+
* names must match across the RSC, SSR, and browser module graphs regardless
|
|
165
|
+
* of which graph evaluates a font call first.
|
|
166
|
+
*/
|
|
167
|
+
function createLocalFontIdentity(options, sources, internalFamily) {
|
|
168
|
+
return fnv1a64(JSON.stringify([
|
|
169
|
+
internalFamily ?? "",
|
|
170
|
+
sources.map((source) => [
|
|
171
|
+
source.path,
|
|
172
|
+
source.weight ?? "",
|
|
173
|
+
source.style ?? ""
|
|
174
|
+
]),
|
|
175
|
+
options.display ?? "swap",
|
|
176
|
+
options.weight ?? "",
|
|
177
|
+
options.style ?? "",
|
|
178
|
+
options.fallback ?? ["sans-serif"],
|
|
179
|
+
options.variable ?? "",
|
|
180
|
+
options.declarations?.map((declaration) => [declaration.prop, declaration.value]) ?? []
|
|
181
|
+
]));
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
154
184
|
* Collect font source URLs for preload link generation.
|
|
155
185
|
* Only collects on the server (SSR). Deduplicates by href using a Set for O(1) lookups.
|
|
156
186
|
*/
|
|
@@ -168,10 +198,11 @@ function collectFontPreloads(sources) {
|
|
|
168
198
|
}
|
|
169
199
|
}
|
|
170
200
|
function localFont(options) {
|
|
171
|
-
const id = classCounter++;
|
|
172
201
|
const sources = normalizeSources(options);
|
|
202
|
+
const internalFamily = sanitizeInternalFontFamily(options._vinext?.font?.family);
|
|
203
|
+
const id = createLocalFontIdentity(options, sources, internalFamily);
|
|
173
204
|
const singleSource = sources.length === 1 ? sources[0] : void 0;
|
|
174
|
-
const family =
|
|
205
|
+
const family = internalFamily ?? `__local_font_${id}`;
|
|
175
206
|
const className = `__font_local_${id}`;
|
|
176
207
|
const fontFamily = `'${family}', ${(options.fallback ?? ["sans-serif"]).map(sanitizeFallback).join(", ")}`;
|
|
177
208
|
const cssVarName = options.variable ? sanitizeCSSVarName(options.variable) : void 0;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/shims/hash-scroll.d.ts
|
|
2
2
|
declare function decodeHashFragment(fragment: string): string;
|
|
3
3
|
declare function scrollToHashTarget(hash: string): void;
|
|
4
|
-
declare function scrollToHashTargetOnNextFrame(hash: string): void;
|
|
4
|
+
declare function scrollToHashTargetOnNextFrame(hash: string, shouldScroll?: () => boolean): void;
|
|
5
5
|
declare function retryScrollTo(x: number, y: number, opts?: {
|
|
6
6
|
minFrames?: number;
|
|
7
7
|
shouldContinue?: () => boolean;
|
|
@@ -24,8 +24,9 @@ function scrollToHashTarget(hash) {
|
|
|
24
24
|
}
|
|
25
25
|
window.scrollTo(0, 0);
|
|
26
26
|
}
|
|
27
|
-
function scrollToHashTargetOnNextFrame(hash) {
|
|
27
|
+
function scrollToHashTargetOnNextFrame(hash, shouldScroll) {
|
|
28
28
|
requestAnimationFrame(() => {
|
|
29
|
+
if (shouldScroll && !shouldScroll()) return;
|
|
29
30
|
scrollToHashTarget(hash);
|
|
30
31
|
});
|
|
31
32
|
}
|
package/dist/shims/headers.d.ts
CHANGED
|
@@ -222,19 +222,16 @@ type DraftModeResult = {
|
|
|
222
222
|
* (`getDraftModeProviderForCacheScope` + `trackDynamicDraftMode`).
|
|
223
223
|
*/
|
|
224
224
|
declare function draftMode(): Promise<DraftModeResult>;
|
|
225
|
+
declare const APPLY_RESPONSE_COOKIE: unique symbol;
|
|
226
|
+
declare const SYNCHRONIZE_REQUEST_COOKIES: unique symbol;
|
|
225
227
|
declare class RequestCookies {
|
|
226
228
|
private _cookies;
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
value: string;
|
|
231
|
-
} | undefined;
|
|
229
|
+
private _responseCookies;
|
|
230
|
+
constructor(cookies: Map<string, string>, mutable?: boolean);
|
|
231
|
+
get(name: string): ResponseCookie | undefined;
|
|
232
232
|
getAll(nameOrOptions?: string | {
|
|
233
233
|
name: string;
|
|
234
|
-
}):
|
|
235
|
-
name: string;
|
|
236
|
-
value: string;
|
|
237
|
-
}>;
|
|
234
|
+
}): ResponseCookie[];
|
|
238
235
|
has(name: string): boolean;
|
|
239
236
|
/**
|
|
240
237
|
* Set a cookie. In Route Handlers and Server Actions, this produces
|
|
@@ -248,11 +245,11 @@ declare class RequestCookies {
|
|
|
248
245
|
delete(name: string): this;
|
|
249
246
|
delete(options: Omit<ResponseCookie, "value" | "expires">): this;
|
|
250
247
|
get size(): number;
|
|
251
|
-
[Symbol.iterator](): MapIterator<[string,
|
|
252
|
-
name: string;
|
|
253
|
-
value: string;
|
|
254
|
-
}]>;
|
|
248
|
+
[Symbol.iterator](): MapIterator<[string, ResponseCookie]>;
|
|
255
249
|
toString(): string;
|
|
250
|
+
private _ensureResponseCookies;
|
|
251
|
+
[APPLY_RESPONSE_COOKIE](cookie: ResponseCookie): void;
|
|
252
|
+
[SYNCHRONIZE_REQUEST_COOKIES](): void;
|
|
256
253
|
}
|
|
257
254
|
//#endregion
|
|
258
255
|
export { HeadersAccessPhase, HeadersContext, type RequestCookies, VinextHeadersShimState, applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getActiveDraftModeState, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeEnabled, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithConnectionProbe, runWithHeadersContext, runWithIsolatedDynamicUsage, setHeadersAccessPhase, setHeadersContext, suspendConnectionProbe, throwIfInsideCacheScope, throwIfStaticGenerationAccessError };
|
package/dist/shims/headers.js
CHANGED
|
@@ -3,7 +3,7 @@ import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation }
|
|
|
3
3
|
import { MIDDLEWARE_SET_COOKIE_HEADER } from "../utils/protocol-headers.js";
|
|
4
4
|
import { FLIGHT_HEADERS, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER } from "../server/headers.js";
|
|
5
5
|
import { buildRequestHeadersFromMiddlewareResponse } from "../utils/middleware-request-headers.js";
|
|
6
|
-
import { serializeSetCookie,
|
|
6
|
+
import { serializeSetCookie, validateCookieName } from "./internal/cookie-serialize.js";
|
|
7
7
|
import { parseEdgeRequestCookieHeader } from "../utils/parse-cookie.js";
|
|
8
8
|
import { createPprFallbackShellSuspensePromise } from "./ppr-fallback-shell.js";
|
|
9
9
|
//#region src/shims/headers.ts
|
|
@@ -29,7 +29,6 @@ const _fallbackState = _g[_FALLBACK_KEY] ??= {
|
|
|
29
29
|
draftModeCookieHeader: null,
|
|
30
30
|
phase: "render"
|
|
31
31
|
};
|
|
32
|
-
const EXPIRED_COOKIE_DATE = (/* @__PURE__ */ new Date(0)).toUTCString();
|
|
33
32
|
function splitMiddlewareSetCookieHeader(value) {
|
|
34
33
|
const cookies = [];
|
|
35
34
|
let start = 0;
|
|
@@ -320,6 +319,7 @@ function peekDynamicUsage() {
|
|
|
320
319
|
}
|
|
321
320
|
function _setStatePhase(state, phase) {
|
|
322
321
|
const previous = state.phase;
|
|
322
|
+
if (previous === "action" && phase === "render") state.headersContext?.mutableCookies?.[SYNCHRONIZE_REQUEST_COOKIES]();
|
|
323
323
|
state.phase = phase;
|
|
324
324
|
return previous;
|
|
325
325
|
}
|
|
@@ -534,7 +534,7 @@ function _sealCookies(cookies) {
|
|
|
534
534
|
} });
|
|
535
535
|
}
|
|
536
536
|
function _getMutableCookies(ctx) {
|
|
537
|
-
if (!ctx.mutableCookies) ctx.mutableCookies = _wrapMutableCookies(new RequestCookies(ctx.cookies));
|
|
537
|
+
if (!ctx.mutableCookies) ctx.mutableCookies = _wrapMutableCookies(new RequestCookies(ctx.cookies, true));
|
|
538
538
|
return ctx.mutableCookies;
|
|
539
539
|
}
|
|
540
540
|
function _getReadonlyCookies(ctx) {
|
|
@@ -653,7 +653,6 @@ function getAndClearPendingCookies() {
|
|
|
653
653
|
return cookies;
|
|
654
654
|
}
|
|
655
655
|
const DRAFT_MODE_COOKIE = "__prerender_bypass";
|
|
656
|
-
const DRAFT_MODE_EXPIRED_DATE = (/* @__PURE__ */ new Date(0)).toUTCString();
|
|
657
656
|
/**
|
|
658
657
|
* Get any Set-Cookie header generated by draftMode().enable()/disable().
|
|
659
658
|
* Called by the framework after rendering to attach the header to the response.
|
|
@@ -705,10 +704,6 @@ function getActiveDraftModeState() {
|
|
|
705
704
|
function isDraftModeEnabled() {
|
|
706
705
|
return getActiveDraftModeState() ?? false;
|
|
707
706
|
}
|
|
708
|
-
function draftModeCookieAttributes() {
|
|
709
|
-
if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") return "Path=/; HttpOnly; SameSite=Lax";
|
|
710
|
-
return "Path=/; HttpOnly; SameSite=None; Secure";
|
|
711
|
-
}
|
|
712
707
|
function createDraftModeScopeError(expression) {
|
|
713
708
|
return /* @__PURE__ */ new Error(`${expression} can only be called from a Server Component, Route Handler, or Server Action.`);
|
|
714
709
|
}
|
|
@@ -746,26 +741,38 @@ async function draftMode() {
|
|
|
746
741
|
throwIfInsideCacheScope("draftMode().enable()");
|
|
747
742
|
const activeContext = requireActiveDraftModeContext(state, context, "draftMode().enable()");
|
|
748
743
|
markDynamicUsage();
|
|
744
|
+
const cookie = createDraftModeCookie(secret);
|
|
745
|
+
const serialized = serializeMutableCookie(cookie);
|
|
746
|
+
_getMutableCookies(activeContext)[APPLY_RESPONSE_COOKIE](cookie);
|
|
749
747
|
activeContext.draftModeEnabled = true;
|
|
750
|
-
|
|
751
|
-
state.draftModeCookieHeader = `${DRAFT_MODE_COOKIE}=${secret}; ${draftModeCookieAttributes()}`;
|
|
748
|
+
state.draftModeCookieHeader = serialized;
|
|
752
749
|
},
|
|
753
750
|
disable() {
|
|
754
751
|
throwIfInsideCacheScope("draftMode().disable()");
|
|
755
752
|
const activeContext = requireActiveDraftModeContext(state, context, "draftMode().disable()");
|
|
756
753
|
markDynamicUsage();
|
|
754
|
+
const cookie = createDraftModeCookie("", /* @__PURE__ */ new Date(0));
|
|
755
|
+
const serialized = serializeMutableCookie(cookie);
|
|
756
|
+
_getMutableCookies(activeContext)[APPLY_RESPONSE_COOKIE](cookie);
|
|
757
757
|
activeContext.draftModeEnabled = false;
|
|
758
|
-
|
|
759
|
-
state.draftModeCookieHeader = `${DRAFT_MODE_COOKIE}=; ${draftModeCookieAttributes()}; Expires=${DRAFT_MODE_EXPIRED_DATE}`;
|
|
758
|
+
state.draftModeCookieHeader = serialized;
|
|
760
759
|
}
|
|
761
760
|
};
|
|
762
761
|
}
|
|
762
|
+
const APPLY_RESPONSE_COOKIE = Symbol("vinext.apply-response-cookie");
|
|
763
|
+
const SYNCHRONIZE_REQUEST_COOKIES = Symbol("vinext.synchronize-request-cookies");
|
|
763
764
|
var RequestCookies = class {
|
|
764
765
|
_cookies;
|
|
765
|
-
|
|
766
|
+
_responseCookies;
|
|
767
|
+
constructor(cookies, mutable = false) {
|
|
766
768
|
this._cookies = cookies;
|
|
769
|
+
this._responseCookies = mutable ? new Map(Array.from(cookies, ([name, value]) => [name, normalizeMutableCookie({
|
|
770
|
+
name,
|
|
771
|
+
value
|
|
772
|
+
})])) : null;
|
|
767
773
|
}
|
|
768
774
|
get(name) {
|
|
775
|
+
if (this._responseCookies) return this._responseCookies.get(name);
|
|
769
776
|
const value = this._cookies.get(name);
|
|
770
777
|
if (value === void 0) return void 0;
|
|
771
778
|
return {
|
|
@@ -775,6 +782,10 @@ var RequestCookies = class {
|
|
|
775
782
|
}
|
|
776
783
|
getAll(nameOrOptions) {
|
|
777
784
|
const name = typeof nameOrOptions === "string" ? nameOrOptions : nameOrOptions?.name;
|
|
785
|
+
if (this._responseCookies) {
|
|
786
|
+
const responseCookies = [...this._responseCookies.values()];
|
|
787
|
+
return name === void 0 ? responseCookies : responseCookies.filter((cookie) => cookie.name === name);
|
|
788
|
+
}
|
|
778
789
|
const result = [];
|
|
779
790
|
for (const [cookieName, value] of this._cookies) if (name === void 0 || cookieName === name) result.push({
|
|
780
791
|
name: cookieName,
|
|
@@ -783,7 +794,7 @@ var RequestCookies = class {
|
|
|
783
794
|
return result;
|
|
784
795
|
}
|
|
785
796
|
has(name) {
|
|
786
|
-
return this._cookies.has(name);
|
|
797
|
+
return this._responseCookies?.has(name) ?? this._cookies.has(name);
|
|
787
798
|
}
|
|
788
799
|
set(nameOrOptions, value, options) {
|
|
789
800
|
let cookieName;
|
|
@@ -799,43 +810,81 @@ var RequestCookies = class {
|
|
|
799
810
|
opts = nameOrOptions;
|
|
800
811
|
}
|
|
801
812
|
validateCookieName(cookieName);
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
...opts
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
813
|
+
const responseCookie = normalizeMutableCookie({
|
|
814
|
+
name: cookieName,
|
|
815
|
+
value: cookieValue,
|
|
816
|
+
...opts
|
|
817
|
+
});
|
|
818
|
+
const serialized = serializeMutableCookie(responseCookie);
|
|
819
|
+
this[APPLY_RESPONSE_COOKIE](responseCookie);
|
|
820
|
+
_getState().pendingSetCookies.push(serialized);
|
|
809
821
|
return this;
|
|
810
822
|
}
|
|
811
823
|
delete(nameOrOptions) {
|
|
812
824
|
const name = typeof nameOrOptions === "string" ? nameOrOptions : nameOrOptions.name;
|
|
813
|
-
const path = typeof nameOrOptions === "string" ? "/" : nameOrOptions.path ?? "/";
|
|
814
|
-
const domain = typeof nameOrOptions === "string" ? void 0 : nameOrOptions.domain;
|
|
815
825
|
validateCookieName(name);
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
826
|
+
const responseCookie = normalizeMutableCookie({
|
|
827
|
+
...typeof nameOrOptions === "string" ? void 0 : nameOrOptions,
|
|
828
|
+
name,
|
|
829
|
+
value: "",
|
|
830
|
+
expires: /* @__PURE__ */ new Date(0)
|
|
831
|
+
});
|
|
832
|
+
const serialized = serializeMutableCookie(responseCookie);
|
|
833
|
+
this[APPLY_RESPONSE_COOKIE](responseCookie);
|
|
834
|
+
_getState().pendingSetCookies.push(serialized);
|
|
823
835
|
return this;
|
|
824
836
|
}
|
|
825
837
|
get size() {
|
|
826
|
-
return this._cookies.size;
|
|
838
|
+
return this._responseCookies?.size ?? this._cookies.size;
|
|
827
839
|
}
|
|
828
840
|
[Symbol.iterator]() {
|
|
829
|
-
return new Map(
|
|
830
|
-
name,
|
|
831
|
-
value
|
|
832
|
-
}])).entries();
|
|
841
|
+
return new Map(this.getAll().map((cookie) => [cookie.name, cookie])).entries();
|
|
833
842
|
}
|
|
834
843
|
toString() {
|
|
844
|
+
if (this._responseCookies) return [...this._responseCookies.values()].map(serializeMutableCookie).join("; ");
|
|
835
845
|
const parts = [];
|
|
836
|
-
for (const [name, value] of this._cookies) parts.push(`${name}=${value}`);
|
|
846
|
+
for (const [name, value] of this._cookies) parts.push(`${name}=${encodeURIComponent(value)}`);
|
|
837
847
|
return parts.join("; ");
|
|
838
848
|
}
|
|
849
|
+
_ensureResponseCookies() {
|
|
850
|
+
if (!this._responseCookies) this._responseCookies = new Map(Array.from(this._cookies, ([name, value]) => [name, normalizeMutableCookie({
|
|
851
|
+
name,
|
|
852
|
+
value
|
|
853
|
+
})]));
|
|
854
|
+
return this._responseCookies;
|
|
855
|
+
}
|
|
856
|
+
[APPLY_RESPONSE_COOKIE](cookie) {
|
|
857
|
+
this._ensureResponseCookies().set(cookie.name, cookie);
|
|
858
|
+
}
|
|
859
|
+
[SYNCHRONIZE_REQUEST_COOKIES]() {
|
|
860
|
+
this._cookies.clear();
|
|
861
|
+
for (const cookie of this._ensureResponseCookies().values()) this._cookies.set(cookie.name, cookie.value);
|
|
862
|
+
}
|
|
839
863
|
};
|
|
864
|
+
function createDraftModeCookie(value, expires) {
|
|
865
|
+
const isDevelopment = typeof process !== "undefined" && process.env?.NODE_ENV === "development";
|
|
866
|
+
return normalizeMutableCookie({
|
|
867
|
+
name: DRAFT_MODE_COOKIE,
|
|
868
|
+
value,
|
|
869
|
+
...expires === void 0 ? {} : { expires },
|
|
870
|
+
httpOnly: true,
|
|
871
|
+
sameSite: isDevelopment ? "lax" : "none",
|
|
872
|
+
secure: !isDevelopment,
|
|
873
|
+
path: "/"
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
function normalizeMutableCookie(cookie) {
|
|
877
|
+
const normalized = { ...cookie };
|
|
878
|
+
if (typeof normalized.expires === "number") normalized.expires = new Date(normalized.expires);
|
|
879
|
+
if (normalized.maxAge) normalized.expires = new Date(Date.now() + normalized.maxAge * 1e3);
|
|
880
|
+
if (normalized.path == null) normalized.path = "/";
|
|
881
|
+
return normalized;
|
|
882
|
+
}
|
|
883
|
+
function serializeMutableCookie(cookie) {
|
|
884
|
+
return serializeSetCookie(cookie.name, cookie.value, {
|
|
885
|
+
...cookie,
|
|
886
|
+
expires: typeof cookie.expires === "number" ? new Date(cookie.expires) : cookie.expires
|
|
887
|
+
});
|
|
888
|
+
}
|
|
840
889
|
//#endregion
|
|
841
890
|
export { applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getActiveDraftModeState, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeEnabled, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithConnectionProbe, runWithHeadersContext, runWithIsolatedDynamicUsage, setHeadersAccessPhase, setHeadersContext, suspendConnectionProbe, throwIfInsideCacheScope, throwIfStaticGenerationAccessError };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
//#region src/shims/internal/cookie-serialize.d.ts
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Set-Cookie serialization for the mutable next/headers shim.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* `ResponseCookies` in server.ts deliberately uses the exact
|
|
6
|
+
* @edge-runtime/cookies serialization order and casing instead. It also has to
|
|
7
|
+
* preserve the absence of a default path when parsing an existing Set-Cookie
|
|
8
|
+
* header, while this helper always defaults new mutable cookies to `Path=/`.
|
|
9
9
|
*
|
|
10
10
|
* Note: this is a value-encoding helper for response cookies only. The
|
|
11
11
|
* request `Cookie:` header serialization in `RequestCookies._serialize`
|
|
@@ -20,7 +20,7 @@ type SerializeSetCookieOptions = {
|
|
|
20
20
|
expires?: Date;
|
|
21
21
|
httpOnly?: boolean;
|
|
22
22
|
secure?: boolean;
|
|
23
|
-
sameSite?: "Strict" | "Lax" | "None";
|
|
23
|
+
sameSite?: true | false | "strict" | "lax" | "none" | "Strict" | "Lax" | "None";
|
|
24
24
|
partitioned?: boolean;
|
|
25
25
|
priority?: "low" | "medium" | "high";
|
|
26
26
|
};
|
|
@@ -36,12 +36,13 @@ declare function validateCookieAttributeValue(value: string, attributeName: stri
|
|
|
36
36
|
* - Encodes the value with `encodeURIComponent`.
|
|
37
37
|
* - Defaults `Path` to `/` (matching @edge-runtime/cookies and Next.js).
|
|
38
38
|
* - Validates path/domain to reject control characters and semicolons.
|
|
39
|
-
* - Emits attributes in the order
|
|
40
|
-
*
|
|
39
|
+
* - Emits attributes in the same order and casing as Next.js's compiled
|
|
40
|
+
* `@edge-runtime/cookies` serializer: Path, Expires, Max-Age, Domain,
|
|
41
|
+
* Secure, HttpOnly, SameSite, Partitioned, Priority.
|
|
41
42
|
*
|
|
42
43
|
* The caller is responsible for validating the cookie name (typically before
|
|
43
44
|
* mutating any internal state) via `validateCookieName`.
|
|
44
45
|
*/
|
|
45
|
-
declare function serializeSetCookie(name: string, value: string, options?: SerializeSetCookieOptions): string;
|
|
46
|
+
declare function serializeSetCookie(name: string, value: string | null | undefined, options?: SerializeSetCookieOptions): string;
|
|
46
47
|
//#endregion
|
|
47
48
|
export { serializeSetCookie, validateCookieAttributeValue, validateCookieName };
|
|
@@ -23,28 +23,29 @@ function validateCookieAttributeValue(value, attributeName) {
|
|
|
23
23
|
* - Encodes the value with `encodeURIComponent`.
|
|
24
24
|
* - Defaults `Path` to `/` (matching @edge-runtime/cookies and Next.js).
|
|
25
25
|
* - Validates path/domain to reject control characters and semicolons.
|
|
26
|
-
* - Emits attributes in the order
|
|
27
|
-
*
|
|
26
|
+
* - Emits attributes in the same order and casing as Next.js's compiled
|
|
27
|
+
* `@edge-runtime/cookies` serializer: Path, Expires, Max-Age, Domain,
|
|
28
|
+
* Secure, HttpOnly, SameSite, Partitioned, Priority.
|
|
28
29
|
*
|
|
29
30
|
* The caller is responsible for validating the cookie name (typically before
|
|
30
31
|
* mutating any internal state) via `validateCookieName`.
|
|
31
32
|
*/
|
|
32
33
|
function serializeSetCookie(name, value, options) {
|
|
33
|
-
const parts = [`${name}=${encodeURIComponent(value)}`];
|
|
34
|
+
const parts = [`${name}=${encodeURIComponent(value ?? "")}`];
|
|
34
35
|
const path = options?.path ?? "/";
|
|
35
36
|
validateCookieAttributeValue(path, "Path");
|
|
36
|
-
parts.push(`Path=${path}`);
|
|
37
|
+
if (path) parts.push(`Path=${path}`);
|
|
38
|
+
if (options?.expires) parts.push(`Expires=${options.expires.toUTCString()}`);
|
|
39
|
+
if (options?.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
|
|
37
40
|
if (options?.domain) {
|
|
38
41
|
validateCookieAttributeValue(options.domain, "Domain");
|
|
39
42
|
parts.push(`Domain=${options.domain}`);
|
|
40
43
|
}
|
|
41
|
-
if (options?.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
|
|
42
|
-
if (options?.expires) parts.push(`Expires=${options.expires.toUTCString()}`);
|
|
43
|
-
if (options?.httpOnly) parts.push("HttpOnly");
|
|
44
44
|
if (options?.secure) parts.push("Secure");
|
|
45
|
+
if (options?.httpOnly) parts.push("HttpOnly");
|
|
45
46
|
if (options?.sameSite) parts.push(`SameSite=${options.sameSite}`);
|
|
46
47
|
if (options?.partitioned) parts.push("Partitioned");
|
|
47
|
-
if (options?.priority) parts.push(`Priority=${options.priority
|
|
48
|
+
if (options?.priority) parts.push(`Priority=${options.priority}`);
|
|
48
49
|
return parts.join("; ");
|
|
49
50
|
}
|
|
50
51
|
//#endregion
|
|
@@ -14,6 +14,10 @@ type DynamicRouteHrefProjection = {
|
|
|
14
14
|
query: ParsedUrlQuery;
|
|
15
15
|
routePathname: string;
|
|
16
16
|
};
|
|
17
|
+
type DynamicRouteHrefResolution = {
|
|
18
|
+
/** Route-pattern URL passed to the Pages Router. */href: string; /** Interpolated URL rendered in the anchor and displayed in the browser. */
|
|
19
|
+
as: string;
|
|
20
|
+
};
|
|
17
21
|
/**
|
|
18
22
|
* Resolve a bracket-pattern route href against its displayed href. Query
|
|
19
23
|
* values can be supplied directly (object-form hrefs) or parsed from the route
|
|
@@ -21,5 +25,15 @@ type DynamicRouteHrefProjection = {
|
|
|
21
25
|
* query delimiter.
|
|
22
26
|
*/
|
|
23
27
|
declare function interpolateDynamicRouteHref(routeHref: string, asHref: string, queryInput?: UrlQuery): DynamicRouteHrefProjection | null;
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the two URLs that Next.js' Pages Router derives from a dynamic
|
|
30
|
+
* href: the original route-pattern URL used to load the page and the
|
|
31
|
+
* interpolated browser URL. Dynamic params are consumed from the latter's
|
|
32
|
+
* query string while unrelated query values and the hash are retained.
|
|
33
|
+
*
|
|
34
|
+
* Mirrors `resolveHref(router, href, true)` from Next.js:
|
|
35
|
+
* packages/next/src/client/resolve-href.ts.
|
|
36
|
+
*/
|
|
37
|
+
declare function resolveDynamicRouteHref(routeHref: string): DynamicRouteHrefResolution | null;
|
|
24
38
|
//#endregion
|
|
25
|
-
export { DynamicRouteHrefProjection, interpolateDynamicRouteHref };
|
|
39
|
+
export { DynamicRouteHrefProjection, DynamicRouteHrefResolution, interpolateDynamicRouteHref, resolveDynamicRouteHref };
|
|
@@ -176,11 +176,11 @@ function interpolateAs(route, asPathname, query) {
|
|
|
176
176
|
* query delimiter.
|
|
177
177
|
*/
|
|
178
178
|
function interpolateDynamicRouteHref(routeHref, asHref, queryInput) {
|
|
179
|
-
if (!routeHref.includes("[")) return null;
|
|
180
179
|
const hashIndex = routeHref.indexOf("#");
|
|
181
180
|
const queryIndex = routeHref.indexOf("?");
|
|
182
181
|
const pathEnd = [hashIndex, queryIndex].filter((index) => index !== -1).reduce((earliest, index) => Math.min(earliest, index), routeHref.length);
|
|
183
182
|
const routePathname = routeHref.slice(0, pathEnd);
|
|
183
|
+
if (!routePathname.includes("[")) return null;
|
|
184
184
|
const trailing = routeHref.slice(pathEnd);
|
|
185
185
|
const asPathname = asHref.split(/[?#]/, 1)[0];
|
|
186
186
|
const query = queryInput ? normalizeQuery(queryInput) : parseRouteHrefQuery(routeHref, queryIndex, hashIndex);
|
|
@@ -192,5 +192,30 @@ function interpolateDynamicRouteHref(routeHref, asHref, queryInput) {
|
|
|
192
192
|
routePathname
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Resolve the two URLs that Next.js' Pages Router derives from a dynamic
|
|
197
|
+
* href: the original route-pattern URL used to load the page and the
|
|
198
|
+
* interpolated browser URL. Dynamic params are consumed from the latter's
|
|
199
|
+
* query string while unrelated query values and the hash are retained.
|
|
200
|
+
*
|
|
201
|
+
* Mirrors `resolveHref(router, href, true)` from Next.js:
|
|
202
|
+
* packages/next/src/client/resolve-href.ts.
|
|
203
|
+
*/
|
|
204
|
+
function resolveDynamicRouteHref(routeHref) {
|
|
205
|
+
const projection = interpolateDynamicRouteHref(routeHref, routeHref);
|
|
206
|
+
if (!projection?.href) return null;
|
|
207
|
+
const hashIndex = projection.href.indexOf("#");
|
|
208
|
+
const hash = hashIndex === -1 ? "" : projection.href.slice(hashIndex);
|
|
209
|
+
const hrefWithoutHash = hashIndex === -1 ? projection.href : projection.href.slice(0, hashIndex);
|
|
210
|
+
const queryIndex = hrefWithoutHash.indexOf("?");
|
|
211
|
+
const pathname = queryIndex === -1 ? hrefWithoutHash : hrefWithoutHash.slice(0, queryIndex);
|
|
212
|
+
const searchParams = new URLSearchParams(queryIndex === -1 ? "" : hrefWithoutHash.slice(queryIndex + 1));
|
|
213
|
+
for (const param of projection.params) searchParams.delete(param);
|
|
214
|
+
const search = searchParams.toString();
|
|
215
|
+
return {
|
|
216
|
+
href: routeHref,
|
|
217
|
+
as: `${pathname}${search ? `?${search}` : ""}${hash}`
|
|
218
|
+
};
|
|
219
|
+
}
|
|
195
220
|
//#endregion
|
|
196
|
-
export { interpolateDynamicRouteHref };
|
|
221
|
+
export { interpolateDynamicRouteHref, resolveDynamicRouteHref };
|
package/dist/shims/link.d.ts
CHANGED
|
@@ -56,6 +56,8 @@ declare function resolveLinkPrefetchMode(prefetchProp: LinkProps["prefetch"], is
|
|
|
56
56
|
declare function canAutoPrefetchFullAppRoute(href: string): boolean;
|
|
57
57
|
declare function resolveAutoAppRoutePrefetch(href: string): {
|
|
58
58
|
cacheForNavigation: boolean;
|
|
59
|
+
fallbackTtl: "dynamic" | "static";
|
|
60
|
+
minimumTtlMs: number | undefined;
|
|
59
61
|
prefetchShellFirst: boolean;
|
|
60
62
|
shouldPrefetch: boolean;
|
|
61
63
|
};
|