vinext 1.0.0-beta.2 → 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.
- package/README.md +6 -9
- package/dist/build/client-build-config.js +7 -1
- package/dist/check.js +4 -0
- package/dist/config/config-matchers.js +4 -1
- package/dist/config/next-config.d.ts +12 -3
- package/dist/config/next-config.js +4 -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 +3 -0
- 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 +10 -3
- package/dist/index.js +112 -43
- package/dist/init-cloudflare.d.ts +3 -1
- package/dist/init-cloudflare.js +59 -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/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 +3 -3
- package/dist/server/app-browser-entry.js +103 -31
- package/dist/server/app-browser-navigation-controller.d.ts +23 -21
- package/dist/server/app-browser-navigation-controller.js +1 -1
- 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 +8 -0
- package/dist/server/app-page-dispatch.js +31 -6
- package/dist/server/app-page-element-builder.d.ts +2 -0
- package/dist/server/app-page-element-builder.js +33 -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-request.d.ts +3 -0
- package/dist/server/app-page-request.js +1 -1
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +7 -0
- package/dist/server/app-page-route-wiring.js +211 -49
- package/dist/server/app-pages-bridge.d.ts +1 -1
- package/dist/server/app-pages-bridge.js +2 -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-errors.js +10 -0
- package/dist/server/app-rsc-handler.js +21 -9
- 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-ssr-entry.js +4 -4
- 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 +145 -312
- package/dist/server/headers.d.ts +2 -2
- package/dist/server/headers.js +4 -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 +2 -0
- package/dist/server/pages-api-route.js +4 -1
- package/dist/server/pages-dev-hydration.js +0 -1
- 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 +7 -3
- 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 +5 -1
- package/dist/server/pages-page-handler.js +115 -19
- package/dist/server/pages-page-response.d.ts +5 -3
- package/dist/server/pages-page-response.js +23 -26
- 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/prod-server.d.ts +2 -1
- package/dist/server/prod-server.js +37 -13
- package/dist/server/revalidation-host.d.ts +11 -0
- package/dist/server/revalidation-host.js +19 -0
- package/dist/server/worker-revalidation-context.d.ts +13 -0
- package/dist/server/worker-revalidation-context.js +29 -0
- 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/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/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.js +18 -6
- package/dist/shims/metadata.d.ts +7 -17
- package/dist/shims/metadata.js +74 -24
- package/dist/shims/navigation.js +1 -1
- package/dist/shims/request-context.d.ts +4 -1
- 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/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/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.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
import { stripBasePath } from "../utils/base-path.js";
|
|
3
3
|
import { createRouteTrieCache, matchRouteWithTrie } from "../routing/route-matching.js";
|
|
4
4
|
import { isDangerousScheme, reportBlockedDangerousNavigation } from "./url-safety.js";
|
|
5
|
+
import { RouterContext } from "./internal/router-context.js";
|
|
5
6
|
import { addLocalePrefix, getDomainLocaleUrl } from "../utils/domain-locale.js";
|
|
6
7
|
import { getPagesMiddlewareDataHref, prefetchPagesData, resolvePagesDataNavigationTarget } from "./internal/pages-data-target.js";
|
|
7
8
|
import { markAppRouteDetectedOnPrefetch } from "./internal/app-route-detection.js";
|
|
8
9
|
import { isAbsoluteOrProtocolRelativeUrl, normalizePathTrailingSlash, toBrowserNavigationHref, toSameOriginAppPath, withBasePath } from "./url-utils.js";
|
|
9
10
|
import { appendSearchParamsToUrl, urlQueryToSearchParams } from "../utils/query.js";
|
|
10
|
-
import { interpolateDynamicRouteHref } from "./internal/interpolate-as.js";
|
|
11
|
+
import { interpolateDynamicRouteHref, resolveDynamicRouteHref } from "./internal/interpolate-as.js";
|
|
11
12
|
import { getCurrentBrowserLocale } from "./client-locale.js";
|
|
12
13
|
import { getCurrentRoutePathnameForWarning } from "./internal/route-pattern-for-warning.js";
|
|
13
14
|
import { isBotUserAgent } from "../utils/html-limited-bots.js";
|
|
@@ -258,7 +259,6 @@ function prefetchUrl(href, mode, priority = "low", pagesRouteHref, locale) {
|
|
|
258
259
|
const isOptimisticRouteShellPrefetch = !autoPrefetch.cacheForNavigation;
|
|
259
260
|
const hasSearchParams = new URL(fullHref, window.location.href).search !== "";
|
|
260
261
|
const isAutomaticSearchParamShell = mode === "auto" && isOptimisticRouteShellPrefetch && hasSearchParams;
|
|
261
|
-
if (isOptimisticRouteShellPrefetch && interceptionContext !== null) return;
|
|
262
262
|
const hasSearchAgnosticShell = isAutomaticSearchParamShell && hasSearchAgnosticPrefetchShellForRoute(await createRscRequestUrl(fullHref, new Headers()), interceptionContext, mountedSlotsHeader);
|
|
263
263
|
const headers = createRscRequestHeaders({
|
|
264
264
|
interceptionContext,
|
|
@@ -581,17 +581,29 @@ function resolveConcreteRouteHref(href, as) {
|
|
|
581
581
|
return interpolateDynamicRouteHref(typeof href === "string" ? href : resolveHref(href), as, typeof href === "string" || !href.query || typeof href.query === "string" ? void 0 : href.query)?.href || null;
|
|
582
582
|
}
|
|
583
583
|
const Link = forwardRef(function Link({ href, as, replace = false, prefetch: prefetchProp, scroll = true, shallow = false, children: childrenProp, onClick, onMouseEnter, onTouchStart, onNavigate, unstable_dynamicOnHover = false, legacyBehavior = false, passHref = false, transitionTypes: _transitionTypes, ...rest }, forwardedRef) {
|
|
584
|
+
const pagesRouter = useContext(RouterContext);
|
|
584
585
|
const asHref = as === void 0 ? void 0 : resolveHref(as);
|
|
586
|
+
const hrefStr = resolveHref(href);
|
|
585
587
|
const { locale, ...restWithoutLocale } = rest;
|
|
586
588
|
let children = childrenProp;
|
|
587
589
|
if (legacyBehavior && (typeof childrenProp === "string" || typeof childrenProp === "number")) children = React.createElement("a", null, childrenProp);
|
|
588
|
-
const
|
|
590
|
+
const hrefForImplicitInterpolation = isAbsoluteOrProtocolRelativeUrl(hrefStr) ? hrefStr.startsWith("//") ? null : toSameOriginAppPath(hrefStr, __basePath) : hrefStr;
|
|
591
|
+
const implicitDynamicRouteHref = HAS_PAGES_ROUTER && pagesRouter !== null && asHref === void 0 && hrefForImplicitInterpolation !== null ? resolveDynamicRouteHref(hrefForImplicitInterpolation) : null;
|
|
592
|
+
const dynamicRouteHref = implicitDynamicRouteHref ? {
|
|
593
|
+
...implicitDynamicRouteHref,
|
|
594
|
+
href: hrefStr
|
|
595
|
+
} : null;
|
|
596
|
+
const pagesAsHref = asHref ?? dynamicRouteHref?.as;
|
|
597
|
+
const unresolvedHref = pagesAsHref ?? hrefStr;
|
|
589
598
|
const rawResolvedHref = typeof unresolvedHref === "string" && unresolvedHref.startsWith("#") ? resolvePagesQueryOnlyHref(unresolvedHref) : unresolvedHref;
|
|
590
|
-
const
|
|
599
|
+
const concreteRouteHref = HAS_PAGES_ROUTER ? resolveConcreteRouteHref(dynamicRouteHref ? hrefForImplicitInterpolation ?? href : href, pagesAsHref) : null;
|
|
600
|
+
const routeHrefRaw = dynamicRouteHref?.href ?? concreteRouteHref ?? hrefStr;
|
|
601
|
+
const prefetchRouteHrefRaw = concreteRouteHref ?? routeHrefRaw;
|
|
602
|
+
const hasPagesHrefAsPair = HAS_PAGES_ROUTER && typeof pagesAsHref === "string" && typeof routeHrefRaw === "string" && pagesAsHref !== routeHrefRaw;
|
|
591
603
|
const resolvedHref = typeof rawResolvedHref === "string" ? warnAndNormalizeRepeatedSlashesInHref(rawResolvedHref) : rawResolvedHref;
|
|
592
604
|
const isDangerous = typeof resolvedHref === "string" && isDangerousScheme(resolvedHref);
|
|
593
605
|
const normalizedHref = normalizePathTrailingSlash(applyLocaleToHref(isDangerous ? "/" : resolvedHref, locale), __trailingSlash);
|
|
594
|
-
const normalizedRouteHref =
|
|
606
|
+
const normalizedRouteHref = hasPagesHrefAsPair ? normalizePathTrailingSlash(applyLocaleToHref(isDangerous ? "/" : prefetchRouteHrefRaw, locale), __trailingSlash) : normalizedHref;
|
|
595
607
|
const fullHref = normalizePathTrailingSlash(withBasePath(normalizedHref, __basePath), __trailingSlash);
|
|
596
608
|
const [pending, setPending] = useState(false);
|
|
597
609
|
const mountedRef = useRef(true);
|
|
@@ -713,7 +725,7 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
|
|
|
713
725
|
e.preventDefault();
|
|
714
726
|
const hasAppNavigationRuntime = Boolean(getNavigationRuntime()?.functions.navigate);
|
|
715
727
|
const pagesNavigateHref = HAS_PAGES_ROUTER && resolvedHref.startsWith("?") ? resolvePagesLinkNavigationHref(resolvedHref, locale) : navigateHref;
|
|
716
|
-
const pagesAsForLink =
|
|
728
|
+
const pagesAsForLink = hasPagesHrefAsPair ? pagesNavigateHref : void 0;
|
|
717
729
|
const pagesHrefForLink = pagesAsForLink === void 0 ? pagesNavigateHref : routeHrefRaw;
|
|
718
730
|
const absoluteFullHref = toBrowserNavigationHref(hasAppNavigationRuntime ? navigateHref : pagesNavigateHref, window.location.href, __basePath);
|
|
719
731
|
if (onNavigate) try {
|
package/dist/shims/metadata.d.ts
CHANGED
|
@@ -1,31 +1,21 @@
|
|
|
1
1
|
import { ThenableParamsObserver } from "./thenable-params.js";
|
|
2
2
|
import React from "react";
|
|
3
|
+
import { ResolvedViewport as ResolvedViewport$1, Viewport as Viewport$1 } from "@vinext/types/next/upstream/dist/lib/metadata/types/metadata-interface";
|
|
3
4
|
|
|
4
5
|
//#region src/shims/metadata.d.ts
|
|
5
|
-
type Viewport =
|
|
6
|
-
|
|
7
|
-
height?: string | number; /** Initial scale */
|
|
8
|
-
initialScale?: number; /** Minimum scale */
|
|
9
|
-
minimumScale?: number; /** Maximum scale */
|
|
10
|
-
maximumScale?: number; /** Whether user can scale */
|
|
11
|
-
userScalable?: boolean; /** Theme color — single color or array of { media, color } */
|
|
12
|
-
themeColor?: string | Array<{
|
|
13
|
-
media?: string;
|
|
14
|
-
color: string;
|
|
15
|
-
}>; /** Color scheme: 'light' | 'dark' | 'light dark' | 'normal' */
|
|
16
|
-
colorScheme?: string;
|
|
17
|
-
};
|
|
6
|
+
type Viewport = Viewport$1;
|
|
7
|
+
type ResolvedViewport = ResolvedViewport$1;
|
|
18
8
|
/**
|
|
19
9
|
* Resolve viewport config from a module. Handles both static `viewport` export
|
|
20
10
|
* and async `generateViewport()` function.
|
|
21
11
|
*/
|
|
22
|
-
declare function resolveModuleViewport(mod: Record<string, unknown>, params
|
|
12
|
+
declare function resolveModuleViewport(mod: Record<string, unknown>, params?: Record<string, string | string[]>, searchParams?: Record<string, string | string[]>, parent?: Promise<ResolvedViewport>, searchParamsObserver?: ThenableParamsObserver): Promise<Viewport | null>;
|
|
23
13
|
/**
|
|
24
14
|
* Merge viewport configs from multiple sources (layouts + page).
|
|
25
15
|
* Later entries override earlier ones.
|
|
26
16
|
*/
|
|
27
|
-
declare const DEFAULT_VIEWPORT:
|
|
28
|
-
declare function mergeViewport(viewportList: Viewport[]):
|
|
17
|
+
declare const DEFAULT_VIEWPORT: ResolvedViewport;
|
|
18
|
+
declare function mergeViewport(viewportList: readonly Viewport[]): ResolvedViewport;
|
|
29
19
|
/**
|
|
30
20
|
* React component that renders viewport meta tags into <head>.
|
|
31
21
|
*/
|
|
@@ -283,4 +273,4 @@ declare function MetadataHead({
|
|
|
283
273
|
trailingSlash
|
|
284
274
|
}: MetadataHeadProps): React.JSX.Element;
|
|
285
275
|
//#endregion
|
|
286
|
-
export { DEFAULT_VIEWPORT, Metadata, MetadataHead, MetadataMergeEntry, Viewport, ViewportHead, mergeMetadata, mergeMetadataEntries, mergeViewport, postProcessMetadata, renderMetadataToHtml, resolveModuleMetadata, resolveModuleViewport };
|
|
276
|
+
export { DEFAULT_VIEWPORT, Metadata, MetadataHead, MetadataMergeEntry, ResolvedViewport, Viewport, ViewportHead, mergeMetadata, mergeMetadataEntries, mergeViewport, postProcessMetadata, renderMetadataToHtml, resolveModuleMetadata, resolveModuleViewport };
|
package/dist/shims/metadata.js
CHANGED
|
@@ -9,18 +9,20 @@ import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
|
|
|
9
9
|
* Handles `export const metadata` and `export async function generateMetadata()`.
|
|
10
10
|
* Resolves metadata from layouts and pages (pages override layouts).
|
|
11
11
|
*/
|
|
12
|
+
const USE_CACHE_FUNCTION_SYMBOL = Symbol.for("vinext.useCacheFunction");
|
|
13
|
+
const USE_CACHE_ACCEPTS_SECOND_ARGUMENT_SYMBOL = Symbol.for("vinext.useCacheAcceptsSecondArgument");
|
|
12
14
|
/**
|
|
13
15
|
* Resolve viewport config from a module. Handles both static `viewport` export
|
|
14
16
|
* and async `generateViewport()` function.
|
|
15
17
|
*/
|
|
16
|
-
async function resolveModuleViewport(mod, params, searchParams, searchParamsObserver) {
|
|
18
|
+
async function resolveModuleViewport(mod, params = {}, searchParams, parent = Promise.resolve(mergeViewport([])), searchParamsObserver) {
|
|
17
19
|
if (typeof mod.generateViewport === "function") {
|
|
18
20
|
const asyncParams = makeThenableParams(params);
|
|
19
21
|
const props = searchParams === void 0 ? { params: asyncParams } : {
|
|
20
22
|
params: asyncParams,
|
|
21
23
|
searchParams: makeThenableParams(searchParams, searchParamsObserver)
|
|
22
24
|
};
|
|
23
|
-
return await mod.generateViewport(props);
|
|
25
|
+
return await mod.generateViewport(props, parent);
|
|
24
26
|
}
|
|
25
27
|
if (mod.viewport && typeof mod.viewport === "object") return mod.viewport;
|
|
26
28
|
return null;
|
|
@@ -31,47 +33,92 @@ async function resolveModuleViewport(mod, params, searchParams, searchParamsObse
|
|
|
31
33
|
*/
|
|
32
34
|
const DEFAULT_VIEWPORT = {
|
|
33
35
|
width: "device-width",
|
|
34
|
-
initialScale: 1
|
|
36
|
+
initialScale: 1,
|
|
37
|
+
themeColor: null,
|
|
38
|
+
colorScheme: null
|
|
35
39
|
};
|
|
36
40
|
function mergeViewport(viewportList) {
|
|
37
41
|
const merged = { ...DEFAULT_VIEWPORT };
|
|
38
|
-
for (const
|
|
42
|
+
for (const viewport of viewportList) for (const viewportKey in viewport) switch (viewportKey) {
|
|
43
|
+
case "themeColor":
|
|
44
|
+
merged.themeColor = resolveThemeColor(viewport.themeColor);
|
|
45
|
+
break;
|
|
46
|
+
case "colorScheme":
|
|
47
|
+
merged.colorScheme = viewport.colorScheme || null;
|
|
48
|
+
break;
|
|
49
|
+
case "width":
|
|
50
|
+
merged.width = viewport.width;
|
|
51
|
+
break;
|
|
52
|
+
case "height":
|
|
53
|
+
merged.height = viewport.height;
|
|
54
|
+
break;
|
|
55
|
+
case "initialScale":
|
|
56
|
+
merged.initialScale = viewport.initialScale;
|
|
57
|
+
break;
|
|
58
|
+
case "minimumScale":
|
|
59
|
+
merged.minimumScale = viewport.minimumScale;
|
|
60
|
+
break;
|
|
61
|
+
case "maximumScale":
|
|
62
|
+
merged.maximumScale = viewport.maximumScale;
|
|
63
|
+
break;
|
|
64
|
+
case "userScalable":
|
|
65
|
+
merged.userScalable = viewport.userScalable;
|
|
66
|
+
break;
|
|
67
|
+
case "viewportFit":
|
|
68
|
+
merged.viewportFit = viewport.viewportFit;
|
|
69
|
+
break;
|
|
70
|
+
case "interactiveWidget":
|
|
71
|
+
merged.interactiveWidget = viewport.interactiveWidget;
|
|
72
|
+
break;
|
|
73
|
+
default:
|
|
74
|
+
}
|
|
39
75
|
return merged;
|
|
40
76
|
}
|
|
77
|
+
const VIEWPORT_META_NAMES = {
|
|
78
|
+
width: "width",
|
|
79
|
+
height: "height",
|
|
80
|
+
initialScale: "initial-scale",
|
|
81
|
+
minimumScale: "minimum-scale",
|
|
82
|
+
maximumScale: "maximum-scale",
|
|
83
|
+
userScalable: "user-scalable",
|
|
84
|
+
viewportFit: "viewport-fit",
|
|
85
|
+
interactiveWidget: "interactive-widget"
|
|
86
|
+
};
|
|
41
87
|
/**
|
|
42
88
|
* React component that renders viewport meta tags into <head>.
|
|
43
89
|
*/
|
|
44
90
|
function ViewportHead({ viewport }) {
|
|
91
|
+
const resolvedViewport = mergeViewport([viewport]);
|
|
45
92
|
const elements = [];
|
|
46
93
|
let key = 0;
|
|
47
94
|
const parts = [];
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (viewport.userScalable !== void 0) parts.push(`user-scalable=${viewport.userScalable ? "yes" : "no"}`);
|
|
95
|
+
for (const key of Object.keys(VIEWPORT_META_NAMES)) {
|
|
96
|
+
const value = resolvedViewport[key];
|
|
97
|
+
if (value == null) continue;
|
|
98
|
+
parts.push(`${VIEWPORT_META_NAMES[key]}=${key === "userScalable" ? value ? "yes" : "no" : value}`);
|
|
99
|
+
}
|
|
54
100
|
if (parts.length > 0) elements.push(/* @__PURE__ */ jsx("meta", {
|
|
55
101
|
name: "viewport",
|
|
56
102
|
content: parts.join(", ")
|
|
57
103
|
}, key++));
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
name: "theme-color",
|
|
65
|
-
content: entry.color,
|
|
66
|
-
...entry.media ? { media: entry.media } : {}
|
|
67
|
-
}, key++));
|
|
68
|
-
}
|
|
69
|
-
if (viewport.colorScheme) elements.push(/* @__PURE__ */ jsx("meta", {
|
|
104
|
+
if (resolvedViewport.themeColor) for (const entry of resolvedViewport.themeColor) elements.push(/* @__PURE__ */ jsx("meta", {
|
|
105
|
+
name: "theme-color",
|
|
106
|
+
content: entry.color,
|
|
107
|
+
...entry.media ? { media: entry.media } : {}
|
|
108
|
+
}, key++));
|
|
109
|
+
if (resolvedViewport.colorScheme) elements.push(/* @__PURE__ */ jsx("meta", {
|
|
70
110
|
name: "color-scheme",
|
|
71
|
-
content:
|
|
111
|
+
content: resolvedViewport.colorScheme
|
|
72
112
|
}, key++));
|
|
73
113
|
return /* @__PURE__ */ jsx(Fragment$1, { children: elements });
|
|
74
114
|
}
|
|
115
|
+
function resolveThemeColor(themeColor) {
|
|
116
|
+
if (!themeColor) return null;
|
|
117
|
+
return (Array.isArray(themeColor) ? themeColor : [themeColor]).map((descriptor) => typeof descriptor === "string" ? { color: descriptor } : {
|
|
118
|
+
color: descriptor.color,
|
|
119
|
+
media: descriptor.media
|
|
120
|
+
});
|
|
121
|
+
}
|
|
75
122
|
/**
|
|
76
123
|
* Merge metadata from multiple sources (layouts + page).
|
|
77
124
|
*
|
|
@@ -219,12 +266,15 @@ function mergeMetadataEntries(entries) {
|
|
|
219
266
|
*/
|
|
220
267
|
async function resolveModuleMetadata(mod, params = {}, searchParams, parent = Promise.resolve({}), searchParamsObserver) {
|
|
221
268
|
if (typeof mod.generateMetadata === "function") {
|
|
269
|
+
const generateMetadata = mod.generateMetadata;
|
|
222
270
|
const asyncParams = makeThenableParams(params);
|
|
223
271
|
const props = searchParams === void 0 ? { params: asyncParams } : {
|
|
224
272
|
params: asyncParams,
|
|
225
273
|
searchParams: makeThenableParams(searchParams, searchParamsObserver)
|
|
226
274
|
};
|
|
227
|
-
|
|
275
|
+
const isUseCacheFunction = Reflect.get(generateMetadata, USE_CACHE_FUNCTION_SYMBOL) === true;
|
|
276
|
+
const acceptsSecondArgument = Reflect.get(generateMetadata, USE_CACHE_ACCEPTS_SECOND_ARGUMENT_SYMBOL);
|
|
277
|
+
return await (!isUseCacheFunction || (typeof acceptsSecondArgument === "boolean" ? acceptsSecondArgument : generateMetadata.length >= 2) ? generateMetadata(props, parent) : generateMetadata(props));
|
|
228
278
|
}
|
|
229
279
|
if (mod.metadata && typeof mod.metadata === "object") return mod.metadata;
|
|
230
280
|
return null;
|