vinext 0.1.1 → 0.1.2
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 +2 -5
- package/dist/build/client-build-config.d.ts +7 -1
- package/dist/build/client-build-config.js +9 -1
- package/dist/check.js +4 -3
- package/dist/client/navigation-runtime.d.ts +3 -2
- package/dist/client/window-next.d.ts +6 -4
- package/dist/config/config-matchers.d.ts +11 -4
- package/dist/config/config-matchers.js +15 -2
- package/dist/config/next-config.d.ts +13 -0
- package/dist/config/next-config.js +2 -0
- package/dist/deploy.js +9 -2
- package/dist/entries/app-rsc-entry.js +7 -1
- package/dist/entries/pages-client-entry.js +1 -1
- package/dist/entries/pages-server-entry.js +7 -6
- package/dist/index.d.ts +0 -2
- package/dist/index.js +86 -78
- package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
- package/dist/plugins/dynamic-preload-metadata.js +415 -0
- package/dist/plugins/og-assets.js +2 -2
- package/dist/plugins/optimize-imports.d.ts +8 -4
- package/dist/plugins/optimize-imports.js +16 -12
- package/dist/plugins/sass.d.ts +53 -24
- package/dist/plugins/sass.js +249 -1
- package/dist/plugins/wasm-module-import.d.ts +15 -0
- package/dist/plugins/wasm-module-import.js +50 -0
- package/dist/routing/app-route-graph.d.ts +23 -1
- package/dist/routing/app-route-graph.js +47 -8
- package/dist/routing/file-matcher.js +1 -1
- package/dist/server/app-browser-entry.js +108 -213
- package/dist/server/app-browser-error.d.ts +4 -1
- package/dist/server/app-browser-error.js +7 -1
- package/dist/server/app-browser-history-controller.d.ts +104 -0
- package/dist/server/app-browser-history-controller.js +210 -0
- package/dist/server/app-browser-navigation-controller.d.ts +3 -2
- package/dist/server/app-browser-navigation-controller.js +10 -7
- package/dist/server/app-browser-rsc-redirect.d.ts +11 -2
- package/dist/server/app-browser-rsc-redirect.js +30 -8
- package/dist/server/app-browser-state.js +4 -7
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-fallback-renderer.d.ts +2 -1
- package/dist/server/app-fallback-renderer.js +3 -1
- package/dist/server/app-middleware.js +1 -0
- package/dist/server/app-optimistic-routing.js +22 -1
- package/dist/server/app-page-boundary-render.d.ts +2 -1
- package/dist/server/app-page-boundary-render.js +4 -2
- package/dist/server/app-page-cache.js +9 -7
- package/dist/server/app-page-dispatch.d.ts +8 -0
- package/dist/server/app-page-dispatch.js +18 -5
- package/dist/server/app-page-element-builder.d.ts +22 -2
- package/dist/server/app-page-element-builder.js +37 -8
- package/dist/server/app-page-execution.d.ts +1 -1
- package/dist/server/app-page-execution.js +32 -17
- package/dist/server/app-page-render.d.ts +1 -1
- package/dist/server/app-page-render.js +7 -14
- package/dist/server/app-page-request.d.ts +1 -0
- package/dist/server/app-page-request.js +3 -2
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +3 -1
- package/dist/server/app-page-route-wiring.js +8 -7
- package/dist/server/app-page-stream.d.ts +1 -6
- package/dist/server/app-page-stream.js +1 -4
- package/dist/server/app-route-handler-response.js +11 -10
- package/dist/server/app-route-handler-runtime.js +12 -1
- package/dist/server/app-rsc-handler.js +1 -1
- package/dist/server/app-rsc-response-finalizer.js +1 -1
- package/dist/server/app-server-action-execution.d.ts +11 -0
- package/dist/server/app-server-action-execution.js +5 -2
- package/dist/server/app-ssr-entry.js +2 -2
- package/dist/server/app-ssr-stream.js +9 -1
- package/dist/server/dev-lockfile.js +2 -1
- package/dist/server/dev-server.js +43 -12
- package/dist/server/headers.d.ts +8 -1
- package/dist/server/headers.js +8 -1
- package/dist/server/instrumentation-runtime.d.ts +6 -0
- package/dist/server/instrumentation-runtime.js +8 -0
- package/dist/server/isr-decision.d.ts +79 -0
- package/dist/server/isr-decision.js +70 -0
- package/dist/server/metadata-route-response.js +5 -3
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +11 -7
- package/dist/server/middleware.js +1 -0
- package/dist/server/navigation-planner.d.ts +62 -1
- package/dist/server/navigation-planner.js +188 -0
- package/dist/server/navigation-trace.d.ts +11 -1
- package/dist/server/navigation-trace.js +11 -1
- package/dist/server/normalize-path.d.ts +0 -8
- package/dist/server/normalize-path.js +3 -1
- package/dist/server/otel-tracer-extension.d.ts +45 -0
- package/dist/server/otel-tracer-extension.js +89 -0
- package/dist/server/pages-api-route.d.ts +14 -3
- package/dist/server/pages-api-route.js +6 -1
- package/dist/server/pages-asset-tags.d.ts +15 -4
- package/dist/server/pages-asset-tags.js +18 -12
- package/dist/server/pages-data-route.js +5 -1
- package/dist/server/pages-node-compat.d.ts +3 -11
- package/dist/server/pages-node-compat.js +174 -121
- package/dist/server/pages-page-data.d.ts +28 -0
- package/dist/server/pages-page-data.js +61 -17
- package/dist/server/pages-page-handler.d.ts +1 -0
- package/dist/server/pages-page-handler.js +22 -6
- package/dist/server/pages-page-response.d.ts +45 -1
- package/dist/server/pages-page-response.js +66 -5
- package/dist/server/pages-readiness.d.ts +1 -1
- package/dist/server/pages-request-pipeline.d.ts +15 -1
- package/dist/server/pages-request-pipeline.js +23 -2
- package/dist/server/prod-server.d.ts +39 -1
- package/dist/server/prod-server.js +98 -34
- package/dist/shims/cache-runtime.js +9 -2
- package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
- package/dist/shims/dynamic-preload-chunks.js +77 -0
- package/dist/shims/dynamic.d.ts +4 -0
- package/dist/shims/dynamic.js +4 -2
- package/dist/shims/error-boundary.d.ts +4 -4
- package/dist/shims/error.js +37 -11
- package/dist/shims/fetch-cache.d.ts +9 -1
- package/dist/shims/fetch-cache.js +11 -1
- package/dist/shims/head.js +6 -1
- package/dist/shims/headers.d.ts +16 -2
- package/dist/shims/headers.js +37 -1
- package/dist/shims/image-config.js +7 -1
- package/dist/shims/internal/app-route-detection.d.ts +6 -3
- package/dist/shims/internal/app-route-detection.js +10 -6
- package/dist/shims/internal/app-router-context.d.ts +5 -0
- package/dist/shims/metadata.d.ts +6 -2
- package/dist/shims/metadata.js +32 -14
- package/dist/shims/navigation.d.ts +7 -16
- package/dist/shims/navigation.js +33 -16
- package/dist/shims/router.js +28 -1
- package/dist/shims/script-nonce-context.d.ts +1 -1
- package/dist/shims/script-nonce-context.js +11 -3
- package/dist/shims/server.d.ts +17 -1
- package/dist/shims/server.js +31 -6
- package/dist/shims/slot.js +1 -1
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/typegen.js +1 -0
- package/dist/utils/client-build-manifest.js +15 -5
- package/dist/utils/client-runtime-metadata.d.ts +45 -0
- package/dist/utils/client-runtime-metadata.js +63 -0
- package/dist/utils/hash.d.ts +17 -1
- package/dist/utils/hash.js +36 -1
- package/dist/utils/lazy-chunks.d.ts +27 -1
- package/dist/utils/lazy-chunks.js +65 -1
- package/dist/utils/manifest-paths.d.ts +20 -2
- package/dist/utils/manifest-paths.js +38 -3
- package/dist/utils/path.d.ts +2 -1
- package/dist/utils/path.js +5 -1
- package/package.json +2 -2
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useScriptNonce } from "./script-nonce-context.js";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import * as ReactDOM from "react-dom";
|
|
5
|
+
//#region src/shims/dynamic-preload-chunks.tsx
|
|
6
|
+
/**
|
|
7
|
+
* Preload links for rendered next/dynamic() boundaries.
|
|
8
|
+
*
|
|
9
|
+
* This MUST be a "use client" component. next/dynamic() can be called from
|
|
10
|
+
* either a Server Component or a Client Component. If this rendered in the
|
|
11
|
+
* environment of the call site, a Server-Component call site would render it in
|
|
12
|
+
* the RSC environment, where the script-nonce React context is unavailable
|
|
13
|
+
* (createContext is not callable in react-server), so emitted preload links
|
|
14
|
+
* would drop the request CSP nonce — a CSP violation under
|
|
15
|
+
* `script-src 'nonce-…' 'strict-dynamic'`.
|
|
16
|
+
*
|
|
17
|
+
* Marking it "use client" forces it into the SSR pass (where vinext installs
|
|
18
|
+
* the ScriptNonceProvider via withScriptNonce()), so the nonce is available
|
|
19
|
+
* regardless of whether the dynamic() call site is a Server or Client
|
|
20
|
+
* Component. This mirrors Next.js's <PreloadChunks> ('use client') and vinext's
|
|
21
|
+
* own next/script shim.
|
|
22
|
+
*
|
|
23
|
+
* Deliberate divergence from Next.js: for CSS we render
|
|
24
|
+
* `<link rel="stylesheet">` WITHOUT `as="style"`. Next.js emits `as="style"`,
|
|
25
|
+
* but per the HTML spec `as` is only meaningful on `rel="preload"`/`modulepreload`
|
|
26
|
+
* — on `rel="stylesheet"` it is ignored by browsers and is semantically wrong.
|
|
27
|
+
* React keys stylesheet resources on href + precedence, not `as`, so omitting it
|
|
28
|
+
* is safe. This is an intentional, documented difference, not a parity bug.
|
|
29
|
+
*/
|
|
30
|
+
function dynamicPreloadHref(file) {
|
|
31
|
+
if (file.startsWith("/") || file.startsWith("http://") || file.startsWith("https://") || file.startsWith("//")) return file;
|
|
32
|
+
return `/${file}`;
|
|
33
|
+
}
|
|
34
|
+
function resolveDynamicPreloadFiles(moduleIds) {
|
|
35
|
+
if (!moduleIds || moduleIds.length === 0) return [];
|
|
36
|
+
const preloadMap = globalThis.__VINEXT_DYNAMIC_PRELOADS__;
|
|
37
|
+
if (!preloadMap) return [];
|
|
38
|
+
const files = [];
|
|
39
|
+
const seen = /* @__PURE__ */ new Set();
|
|
40
|
+
for (const moduleId of moduleIds) for (const file of preloadMap[moduleId] ?? []) {
|
|
41
|
+
if (seen.has(file)) continue;
|
|
42
|
+
seen.add(file);
|
|
43
|
+
files.push(file);
|
|
44
|
+
}
|
|
45
|
+
return files;
|
|
46
|
+
}
|
|
47
|
+
function DynamicPreloadChunks(props) {
|
|
48
|
+
const nonce = useScriptNonce();
|
|
49
|
+
if (typeof window !== "undefined") return null;
|
|
50
|
+
const files = resolveDynamicPreloadFiles(props.moduleIds);
|
|
51
|
+
if (files.length === 0) return null;
|
|
52
|
+
const stylesheets = [];
|
|
53
|
+
for (const file of files) {
|
|
54
|
+
const href = dynamicPreloadHref(file);
|
|
55
|
+
if (href.endsWith(".css")) {
|
|
56
|
+
stylesheets.push(React.createElement("link", {
|
|
57
|
+
key: href,
|
|
58
|
+
rel: "stylesheet",
|
|
59
|
+
href,
|
|
60
|
+
nonce,
|
|
61
|
+
precedence: "dynamic"
|
|
62
|
+
}));
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (href.endsWith(".js") && typeof ReactDOM.preload === "function") {
|
|
66
|
+
const preloadOptions = {
|
|
67
|
+
as: "script",
|
|
68
|
+
fetchPriority: "low",
|
|
69
|
+
nonce
|
|
70
|
+
};
|
|
71
|
+
ReactDOM.preload(href, preloadOptions);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return stylesheets.length > 0 ? React.createElement(React.Fragment, null, ...stylesheets) : null;
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
77
|
+
export { DynamicPreloadChunks };
|
package/dist/shims/dynamic.d.ts
CHANGED
|
@@ -16,6 +16,10 @@ type LoaderFn<P> = () => LoaderComponent<P>;
|
|
|
16
16
|
type DynamicOptions<P> = {
|
|
17
17
|
loading?: ComponentType<DynamicLoadingProps>;
|
|
18
18
|
loader?: Loader<P>;
|
|
19
|
+
loadableGenerated?: {
|
|
20
|
+
modules?: readonly string[];
|
|
21
|
+
};
|
|
22
|
+
modules?: readonly string[];
|
|
19
23
|
ssr?: boolean;
|
|
20
24
|
};
|
|
21
25
|
type Loader<P> = LoaderFn<P> | LoaderComponent<P>;
|
package/dist/shims/dynamic.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DynamicPreloadChunks } from "./dynamic-preload-chunks.js";
|
|
1
2
|
import React from "react";
|
|
2
3
|
//#region src/shims/dynamic.ts
|
|
3
4
|
/**
|
|
@@ -121,8 +122,9 @@ function flushPreloads() {
|
|
|
121
122
|
return Promise.all(pending);
|
|
122
123
|
}
|
|
123
124
|
function dynamic(dynamicInput, options) {
|
|
124
|
-
const { loader: dynamicLoader, loading: LoadingComponent, ssr = true } = normalizeDynamicOptions(dynamicInput, options);
|
|
125
|
+
const { loader: dynamicLoader, loadableGenerated, loading: LoadingComponent, modules, ssr = true } = normalizeDynamicOptions(dynamicInput, options);
|
|
125
126
|
const loader = dynamicLoader ? normalizeLoader(dynamicLoader) : () => Promise.resolve(() => null);
|
|
127
|
+
const preloadModuleIds = loadableGenerated?.modules ?? modules;
|
|
126
128
|
if (!ssr) {
|
|
127
129
|
if (isServer) {
|
|
128
130
|
const SSRFalse = (_props) => LoadingComponent ? React.createElement(LoadingComponent, createDynamicLoadingProps({ pastDelay: false })) : null;
|
|
@@ -174,7 +176,7 @@ function dynamic(dynamicInput, options) {
|
|
|
174
176
|
resetKey: 0
|
|
175
177
|
}, lazyElement);
|
|
176
178
|
}
|
|
177
|
-
return React.createElement(React.Suspense, { fallback }, content);
|
|
179
|
+
return React.createElement(React.Fragment, null, React.createElement(DynamicPreloadChunks, { moduleIds: preloadModuleIds }), React.createElement(React.Suspense, { fallback }, content));
|
|
178
180
|
};
|
|
179
181
|
ServerDynamic.displayName = "DynamicServer";
|
|
180
182
|
return ServerDynamic;
|
|
@@ -31,7 +31,7 @@ declare class RedirectErrorBoundary extends React.Component<{
|
|
|
31
31
|
children?: React.ReactNode;
|
|
32
32
|
});
|
|
33
33
|
static getDerivedStateFromError(error: unknown): RedirectBoundaryState;
|
|
34
|
-
render(): string | number | bigint | boolean |
|
|
34
|
+
render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
|
|
35
35
|
}
|
|
36
36
|
declare function RedirectBoundary({
|
|
37
37
|
children
|
|
@@ -51,7 +51,7 @@ declare class ErrorBoundaryInner extends React.Component<ErrorBoundaryInnerProps
|
|
|
51
51
|
componentDidMount(): void;
|
|
52
52
|
componentWillUnmount(): void;
|
|
53
53
|
reset: () => void;
|
|
54
|
-
render(): string | number | bigint | boolean |
|
|
54
|
+
render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
|
|
55
55
|
}
|
|
56
56
|
declare function ErrorBoundary({
|
|
57
57
|
fallback,
|
|
@@ -99,7 +99,7 @@ declare class ForbiddenBoundaryInner extends React.Component<ForbiddenBoundaryIn
|
|
|
99
99
|
constructor(props: ForbiddenBoundaryInnerProps);
|
|
100
100
|
static getDerivedStateFromProps(props: ForbiddenBoundaryInnerProps, state: ForbiddenBoundaryState): ForbiddenBoundaryState | null;
|
|
101
101
|
static getDerivedStateFromError(error: unknown): Partial<ForbiddenBoundaryState>;
|
|
102
|
-
render(): string | number | bigint | boolean |
|
|
102
|
+
render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
|
|
103
103
|
}
|
|
104
104
|
declare function ForbiddenBoundary({
|
|
105
105
|
fallback,
|
|
@@ -123,7 +123,7 @@ declare class UnauthorizedBoundaryInner extends React.Component<UnauthorizedBoun
|
|
|
123
123
|
constructor(props: UnauthorizedBoundaryInnerProps);
|
|
124
124
|
static getDerivedStateFromProps(props: UnauthorizedBoundaryInnerProps, state: UnauthorizedBoundaryState): UnauthorizedBoundaryState | null;
|
|
125
125
|
static getDerivedStateFromError(error: unknown): Partial<UnauthorizedBoundaryState>;
|
|
126
|
-
render(): string | number | bigint | boolean |
|
|
126
|
+
render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
|
|
127
127
|
}
|
|
128
128
|
declare function UnauthorizedBoundary({
|
|
129
129
|
fallback,
|
package/dist/shims/error.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { AppRouterContext } from "./internal/app-router-context.js";
|
|
1
2
|
import { RouterContext } from "./internal/router-context.js";
|
|
2
|
-
import {
|
|
3
|
+
import { isNextRouterError, usePathname } from "./navigation.js";
|
|
3
4
|
import React from "react";
|
|
4
5
|
//#region src/shims/error.tsx
|
|
5
6
|
/**
|
|
@@ -39,33 +40,53 @@ function ErrorComponent({ statusCode, title }) {
|
|
|
39
40
|
margin: 0
|
|
40
41
|
} }, displayTitle + "."))));
|
|
41
42
|
}
|
|
43
|
+
const _CatchErrorAppRouterContext = AppRouterContext ?? React.createContext(null);
|
|
42
44
|
var _CatchError = class extends React.Component {
|
|
43
|
-
static contextType =
|
|
45
|
+
static contextType = _CatchErrorAppRouterContext;
|
|
44
46
|
static displayName = "unstable_catchError(Next.CatchError)";
|
|
45
|
-
|
|
47
|
+
constructor(props) {
|
|
48
|
+
super(props);
|
|
49
|
+
this.state = {
|
|
50
|
+
error: null,
|
|
51
|
+
previousPathname: props.pathname
|
|
52
|
+
};
|
|
53
|
+
}
|
|
46
54
|
static getDerivedStateFromError(thrownValue) {
|
|
47
55
|
if (isNextRouterError(thrownValue)) throw thrownValue;
|
|
48
56
|
return { error: { thrownValue } };
|
|
49
57
|
}
|
|
58
|
+
static getDerivedStateFromProps(props, state) {
|
|
59
|
+
if (props.pathname !== state.previousPathname && state.error) return {
|
|
60
|
+
error: null,
|
|
61
|
+
previousPathname: props.pathname
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
error: state.error,
|
|
65
|
+
previousPathname: props.pathname
|
|
66
|
+
};
|
|
67
|
+
}
|
|
50
68
|
reset = () => {
|
|
51
69
|
this.setState({ error: null });
|
|
52
70
|
};
|
|
53
71
|
unstable_retry = () => {
|
|
54
|
-
if (this.
|
|
55
|
-
if (typeof window === "undefined") throw new Error("`unstable_retry()` can only be used on the client. Call it from a user interaction handler inside the error fallback.");
|
|
72
|
+
if (this.props.isPagesRouter) throw new Error("`unstable_retry()` can only be used in the App Router. Use `reset()` in the Pages Router.");
|
|
56
73
|
React.startTransition(() => {
|
|
57
|
-
|
|
74
|
+
this.context?.refresh();
|
|
58
75
|
this.reset();
|
|
59
76
|
});
|
|
60
77
|
};
|
|
61
78
|
render() {
|
|
62
79
|
if (this.state.error) {
|
|
80
|
+
const Fallback = this.props.fallback;
|
|
63
81
|
const errorInfo = {
|
|
64
82
|
error: this.state.error.thrownValue,
|
|
65
83
|
reset: this.reset,
|
|
66
84
|
unstable_retry: this.unstable_retry
|
|
67
85
|
};
|
|
68
|
-
return
|
|
86
|
+
return React.createElement(Fallback, {
|
|
87
|
+
props: this.props.props,
|
|
88
|
+
errorInfo
|
|
89
|
+
});
|
|
69
90
|
}
|
|
70
91
|
return this.props.children;
|
|
71
92
|
}
|
|
@@ -79,13 +100,18 @@ var _CatchError = class extends React.Component {
|
|
|
79
100
|
* https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/catch-error.tsx
|
|
80
101
|
*/
|
|
81
102
|
function unstable_catchError(fallback) {
|
|
82
|
-
const
|
|
103
|
+
const Fallback = ({ props, errorInfo }) => fallback(props, errorInfo);
|
|
104
|
+
Fallback.displayName = fallback.name || "CatchErrorFallback";
|
|
83
105
|
function CatchErrorBoundary(allProps) {
|
|
84
106
|
const { children, ...rest } = allProps;
|
|
107
|
+
const pathname = usePathname();
|
|
108
|
+
const isPagesRouter = React.useContext(RouterContext) !== null;
|
|
85
109
|
const forwardedProps = rest;
|
|
86
|
-
return React.createElement(
|
|
87
|
-
fallback,
|
|
88
|
-
|
|
110
|
+
return React.createElement(_CatchError, {
|
|
111
|
+
fallback: Fallback,
|
|
112
|
+
isPagesRouter,
|
|
113
|
+
pathname,
|
|
114
|
+
props: forwardedProps
|
|
89
115
|
}, children);
|
|
90
116
|
}
|
|
91
117
|
CatchErrorBoundary.displayName = `unstable_catchError(${fallback.name || "CatchErrorFallback"})`;
|
|
@@ -75,6 +75,14 @@ declare function addCollectedRequestTags(tags: readonly string[]): void;
|
|
|
75
75
|
* affected route, without permanently coupling a shared fetch entry to one path.
|
|
76
76
|
*/
|
|
77
77
|
declare function setCurrentFetchSoftTags(tags: string[]): void;
|
|
78
|
+
/**
|
|
79
|
+
* Read the path-derived soft tags for the current render.
|
|
80
|
+
*
|
|
81
|
+
* Used by the "use cache" runtime to pass soft tags to the cache handler
|
|
82
|
+
* so that `revalidatePath()` invalidates "use cache" entries during the
|
|
83
|
+
* affected route's next request, even when the entry carries no hard tags.
|
|
84
|
+
*/
|
|
85
|
+
declare function getCurrentFetchSoftTags(): string[];
|
|
78
86
|
declare function setCurrentFetchCacheMode(mode: FetchCacheMode | null): void;
|
|
79
87
|
/**
|
|
80
88
|
* Install the patched fetch and reset per-request tag state.
|
|
@@ -123,4 +131,4 @@ declare function ensureFetchPatch(): void;
|
|
|
123
131
|
*/
|
|
124
132
|
declare function getOriginalFetch(): typeof globalThis.fetch;
|
|
125
133
|
//#endregion
|
|
126
|
-
export { FetchCacheMode, FetchCacheState, _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, withFetchCache };
|
|
134
|
+
export { FetchCacheMode, FetchCacheState, _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, withFetchCache };
|
|
@@ -369,6 +369,16 @@ function addCollectedRequestTags(tags) {
|
|
|
369
369
|
function setCurrentFetchSoftTags(tags) {
|
|
370
370
|
_getState().currentFetchSoftTags = [...tags];
|
|
371
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* Read the path-derived soft tags for the current render.
|
|
374
|
+
*
|
|
375
|
+
* Used by the "use cache" runtime to pass soft tags to the cache handler
|
|
376
|
+
* so that `revalidatePath()` invalidates "use cache" entries during the
|
|
377
|
+
* affected route's next request, even when the entry carries no hard tags.
|
|
378
|
+
*/
|
|
379
|
+
function getCurrentFetchSoftTags() {
|
|
380
|
+
return _getState().currentFetchSoftTags;
|
|
381
|
+
}
|
|
372
382
|
function setCurrentFetchCacheMode(mode) {
|
|
373
383
|
_getState().currentFetchCacheMode = mode;
|
|
374
384
|
}
|
|
@@ -728,4 +738,4 @@ function getOriginalFetch() {
|
|
|
728
738
|
return originalFetch;
|
|
729
739
|
}
|
|
730
740
|
//#endregion
|
|
731
|
-
export { _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, withFetchCache };
|
|
741
|
+
export { _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, withFetchCache };
|
package/dist/shims/head.js
CHANGED
|
@@ -104,6 +104,10 @@ const SELF_CLOSING_HEAD_TAGS = new Set([
|
|
|
104
104
|
]);
|
|
105
105
|
/** Tags whose content is raw text — closing-tag sequences must be escaped during SSR. */
|
|
106
106
|
const RAW_CONTENT_TAGS = new Set(["script", "style"]);
|
|
107
|
+
const INLINE_CLOSE_TAG_RES = {
|
|
108
|
+
script: /<\/(script)/gi,
|
|
109
|
+
style: /<\/(style)/gi
|
|
110
|
+
};
|
|
107
111
|
function warnDisallowedHeadTag(tag) {
|
|
108
112
|
if (process.env.NODE_ENV !== "production") console.warn(`[vinext] <Head> ignoring disallowed tag <${tag}>. Only ${ALLOWED_HEAD_TAGS_LIST} are allowed.`);
|
|
109
113
|
}
|
|
@@ -247,7 +251,8 @@ function escapeAttr(s) {
|
|
|
247
251
|
* context but prevents the HTML parser from seeing a closing tag.
|
|
248
252
|
*/
|
|
249
253
|
function escapeInlineContent(content, tag) {
|
|
250
|
-
const pattern =
|
|
254
|
+
const pattern = INLINE_CLOSE_TAG_RES[tag];
|
|
255
|
+
if (!pattern) return content;
|
|
251
256
|
return content.replace(pattern, "<\\/$1");
|
|
252
257
|
}
|
|
253
258
|
function getDangerouslySetInnerHTML(value) {
|
package/dist/shims/headers.d.ts
CHANGED
|
@@ -18,12 +18,24 @@ type HeadersAccessPhase = "render" | "action" | "route-handler";
|
|
|
18
18
|
type VinextHeadersShimState = {
|
|
19
19
|
headersContext: HeadersContext | null;
|
|
20
20
|
dynamicUsageDetected: boolean;
|
|
21
|
-
renderRequestApiUsage: Set<RenderRequestApiKind>;
|
|
21
|
+
renderRequestApiUsage: Set<RenderRequestApiKind>;
|
|
22
|
+
connectionProbe: ConnectionProbeState | null; /** Error recorded by throwIfInsideCacheScope for dev diagnostics, persists even if caught by user code. */
|
|
22
23
|
invalidDynamicUsageError: unknown;
|
|
23
24
|
pendingSetCookies: string[];
|
|
24
25
|
draftModeCookieHeader: string | null;
|
|
25
26
|
phase: HeadersAccessPhase;
|
|
26
27
|
};
|
|
28
|
+
type ConnectionProbeState = {
|
|
29
|
+
interrupted: boolean;
|
|
30
|
+
interrupt: () => void;
|
|
31
|
+
pending: Promise<never>;
|
|
32
|
+
};
|
|
33
|
+
type ConnectionProbeResult<T> = {
|
|
34
|
+
completed: true;
|
|
35
|
+
result: T;
|
|
36
|
+
} | {
|
|
37
|
+
completed: false;
|
|
38
|
+
};
|
|
27
39
|
/**
|
|
28
40
|
* Dynamic usage flag — set when a component calls connection(), cookies(),
|
|
29
41
|
* headers(), or noStore() during rendering. When true, ISR caching is
|
|
@@ -35,6 +47,8 @@ type VinextHeadersShimState = {
|
|
|
35
47
|
*/
|
|
36
48
|
declare function markDynamicUsage(): void;
|
|
37
49
|
declare function markRenderRequestApiUsage(kind: RenderRequestApiKind): void;
|
|
50
|
+
declare function runWithConnectionProbe<T>(fn: () => T | Promise<T>): Promise<ConnectionProbeResult<T>>;
|
|
51
|
+
declare function suspendConnectionProbe(): Promise<never> | null;
|
|
38
52
|
declare function peekRenderRequestApiUsage(): RenderRequestApiKind[];
|
|
39
53
|
declare function consumeRenderRequestApiUsage(): RenderRequestApiKind[];
|
|
40
54
|
/**
|
|
@@ -236,4 +250,4 @@ declare class RequestCookies {
|
|
|
236
250
|
toString(): string;
|
|
237
251
|
}
|
|
238
252
|
//#endregion
|
|
239
|
-
export { HeadersAccessPhase, HeadersContext, type RequestCookies, VinextHeadersShimState, applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithHeadersContext, setHeadersAccessPhase, setHeadersContext, throwIfInsideCacheScope };
|
|
253
|
+
export { HeadersAccessPhase, HeadersContext, type RequestCookies, VinextHeadersShimState, applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithConnectionProbe, runWithHeadersContext, setHeadersAccessPhase, setHeadersContext, suspendConnectionProbe, throwIfInsideCacheScope };
|
package/dist/shims/headers.js
CHANGED
|
@@ -21,6 +21,7 @@ const _fallbackState = _g[_FALLBACK_KEY] ??= {
|
|
|
21
21
|
headersContext: null,
|
|
22
22
|
dynamicUsageDetected: false,
|
|
23
23
|
renderRequestApiUsage: /* @__PURE__ */ new Set(),
|
|
24
|
+
connectionProbe: null,
|
|
24
25
|
invalidDynamicUsageError: null,
|
|
25
26
|
pendingSetCookies: [],
|
|
26
27
|
draftModeCookieHeader: null,
|
|
@@ -115,6 +116,39 @@ function markDynamicUsage() {
|
|
|
115
116
|
function markRenderRequestApiUsage(kind) {
|
|
116
117
|
_getState().renderRequestApiUsage.add(kind);
|
|
117
118
|
}
|
|
119
|
+
async function runWithConnectionProbe(fn) {
|
|
120
|
+
const state = _getState();
|
|
121
|
+
const previousProbe = state.connectionProbe;
|
|
122
|
+
let interruptProbe = () => {};
|
|
123
|
+
const interrupted = new Promise((resolve) => {
|
|
124
|
+
interruptProbe = () => resolve({ completed: false });
|
|
125
|
+
});
|
|
126
|
+
const probe = {
|
|
127
|
+
interrupted: false,
|
|
128
|
+
interrupt() {
|
|
129
|
+
if (probe.interrupted) return;
|
|
130
|
+
probe.interrupted = true;
|
|
131
|
+
interruptProbe();
|
|
132
|
+
},
|
|
133
|
+
pending: new Promise(() => {})
|
|
134
|
+
};
|
|
135
|
+
state.connectionProbe = probe;
|
|
136
|
+
try {
|
|
137
|
+
const completed = Promise.resolve().then(fn).then((result) => ({
|
|
138
|
+
completed: true,
|
|
139
|
+
result
|
|
140
|
+
}));
|
|
141
|
+
return await Promise.race([completed, interrupted]);
|
|
142
|
+
} finally {
|
|
143
|
+
state.connectionProbe = previousProbe;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function suspendConnectionProbe() {
|
|
147
|
+
const probe = _getState().connectionProbe;
|
|
148
|
+
if (!probe) return null;
|
|
149
|
+
probe.interrupt();
|
|
150
|
+
return probe.pending;
|
|
151
|
+
}
|
|
118
152
|
function peekRenderRequestApiUsage() {
|
|
119
153
|
return [..._getState().renderRequestApiUsage].sort();
|
|
120
154
|
}
|
|
@@ -260,6 +294,7 @@ function runWithHeadersContext(ctx, fn) {
|
|
|
260
294
|
uCtx.headersContext = ctx;
|
|
261
295
|
uCtx.dynamicUsageDetected = false;
|
|
262
296
|
uCtx.renderRequestApiUsage = /* @__PURE__ */ new Set();
|
|
297
|
+
uCtx.connectionProbe = null;
|
|
263
298
|
uCtx.pendingSetCookies = [];
|
|
264
299
|
uCtx.draftModeCookieHeader = null;
|
|
265
300
|
uCtx.phase = "render";
|
|
@@ -268,6 +303,7 @@ function runWithHeadersContext(ctx, fn) {
|
|
|
268
303
|
headersContext: ctx,
|
|
269
304
|
dynamicUsageDetected: false,
|
|
270
305
|
renderRequestApiUsage: /* @__PURE__ */ new Set(),
|
|
306
|
+
connectionProbe: null,
|
|
271
307
|
invalidDynamicUsageError: null,
|
|
272
308
|
pendingSetCookies: [],
|
|
273
309
|
draftModeCookieHeader: null,
|
|
@@ -690,4 +726,4 @@ var RequestCookies = class {
|
|
|
690
726
|
}
|
|
691
727
|
};
|
|
692
728
|
//#endregion
|
|
693
|
-
export { applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithHeadersContext, setHeadersAccessPhase, setHeadersContext, throwIfInsideCacheScope };
|
|
729
|
+
export { applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithConnectionProbe, runWithHeadersContext, setHeadersAccessPhase, setHeadersContext, suspendConnectionProbe, throwIfInsideCacheScope };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import ipaddr from "ipaddr.js";
|
|
2
2
|
//#region src/shims/image-config.ts
|
|
3
|
+
const globRegexCache = /* @__PURE__ */ new Map();
|
|
3
4
|
/**
|
|
4
5
|
* Convert a glob pattern (with `*` and `**`) to a RegExp.
|
|
5
6
|
*
|
|
@@ -14,6 +15,9 @@ import ipaddr from "ipaddr.js";
|
|
|
14
15
|
* Literal characters are escaped for regex safety.
|
|
15
16
|
*/
|
|
16
17
|
function globToRegex(pattern, separator) {
|
|
18
|
+
const key = `${separator}\0${pattern}`;
|
|
19
|
+
const cached = globRegexCache.get(key);
|
|
20
|
+
if (cached !== void 0) return cached;
|
|
17
21
|
let regexStr = "^";
|
|
18
22
|
const doubleStar = separator === "." ? ".+" : ".*";
|
|
19
23
|
const singleStar = separator === "." ? "[^.]+" : "[^/]+";
|
|
@@ -27,7 +31,9 @@ function globToRegex(pattern, separator) {
|
|
|
27
31
|
}
|
|
28
32
|
}
|
|
29
33
|
regexStr += "$";
|
|
30
|
-
|
|
34
|
+
const re = new RegExp(regexStr);
|
|
35
|
+
globRegexCache.set(key, re);
|
|
36
|
+
return re;
|
|
31
37
|
}
|
|
32
38
|
/**
|
|
33
39
|
* Check whether a URL matches a single remote pattern.
|
|
@@ -27,9 +27,12 @@ declare function getPagesRouterComponentsMap(): PagesRouterComponentsMap;
|
|
|
27
27
|
* Pages Router map when the href matches an App Router route. No-op when the
|
|
28
28
|
* manifest is absent, the URL is external, or no app route matches.
|
|
29
29
|
*
|
|
30
|
-
* `pathname` is the basePath-stripped path —
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* `pathname` is the basePath-stripped, trailing-slash-stripped path —
|
|
31
|
+
* matching Next.js's `removeTrailingSlash(removeBasePath(pathname))` key used
|
|
32
|
+
* at read time (router.ts:1442). Stripping here ensures the write and read
|
|
33
|
+
* keys agree regardless of whether the caller normalised trailing slashes
|
|
34
|
+
* first (e.g. `link.tsx` normalises to match `trailingSlash` config before
|
|
35
|
+
* calling, while `router.prefetch()` passes the raw user-supplied URL).
|
|
33
36
|
*/
|
|
34
37
|
declare function markAppRouteDetectedOnPrefetch(href: string, basePath: string): void;
|
|
35
38
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { stripBasePath } from "../../utils/base-path.js";
|
|
1
|
+
import { removeTrailingSlash, stripBasePath } from "../../utils/base-path.js";
|
|
2
2
|
import { createRouteTrieCache, matchRouteWithTrie } from "../../routing/route-matching.js";
|
|
3
3
|
//#region src/shims/internal/app-route-detection.ts
|
|
4
4
|
const appRouteTrieCache = createRouteTrieCache();
|
|
@@ -52,15 +52,19 @@ function matchesAppRoute(href, basePath) {
|
|
|
52
52
|
* Pages Router map when the href matches an App Router route. No-op when the
|
|
53
53
|
* manifest is absent, the URL is external, or no app route matches.
|
|
54
54
|
*
|
|
55
|
-
* `pathname` is the basePath-stripped path —
|
|
56
|
-
*
|
|
57
|
-
*
|
|
55
|
+
* `pathname` is the basePath-stripped, trailing-slash-stripped path —
|
|
56
|
+
* matching Next.js's `removeTrailingSlash(removeBasePath(pathname))` key used
|
|
57
|
+
* at read time (router.ts:1442). Stripping here ensures the write and read
|
|
58
|
+
* keys agree regardless of whether the caller normalised trailing slashes
|
|
59
|
+
* first (e.g. `link.tsx` normalises to match `trailingSlash` config before
|
|
60
|
+
* calling, while `router.prefetch()` passes the raw user-supplied URL).
|
|
58
61
|
*/
|
|
59
62
|
function markAppRouteDetectedOnPrefetch(href, basePath) {
|
|
60
63
|
if (typeof window === "undefined") return;
|
|
61
64
|
if (!matchesAppRoute(href, basePath)) return;
|
|
62
|
-
const
|
|
63
|
-
if (
|
|
65
|
+
const rawPathname = resolveSameOriginPathname(href, basePath);
|
|
66
|
+
if (rawPathname === null) return;
|
|
67
|
+
const pathname = removeTrailingSlash(rawPathname);
|
|
64
68
|
getPagesRouterComponentsMap()[pathname] = { __appRouter: true };
|
|
65
69
|
}
|
|
66
70
|
//#endregion
|
|
@@ -16,6 +16,11 @@ type AppRouterInstance = {
|
|
|
16
16
|
push(href: string, options?: NavigateOptions): void;
|
|
17
17
|
replace(href: string, options?: NavigateOptions): void;
|
|
18
18
|
prefetch(href: string, options?: PrefetchOptions): void;
|
|
19
|
+
/**
|
|
20
|
+
* Perform an experimental gesture transition navigation.
|
|
21
|
+
* Only available when experimental.gestureTransition is enabled.
|
|
22
|
+
*/
|
|
23
|
+
experimental_gesturePush?(href: string, options?: NavigateOptions): void;
|
|
19
24
|
};
|
|
20
25
|
declare const AppRouterContext: React$1.Context<AppRouterInstance | null> | null;
|
|
21
26
|
declare const GlobalLayoutRouterContext: React$1.Context<unknown> | null;
|
package/dist/shims/metadata.d.ts
CHANGED
|
@@ -271,11 +271,15 @@ declare function resolveModuleMetadata(mod: Record<string, unknown>, params?: Re
|
|
|
271
271
|
type MetadataHeadProps = {
|
|
272
272
|
metadata: Metadata;
|
|
273
273
|
pathname?: string;
|
|
274
|
+
trailingSlash?: boolean;
|
|
274
275
|
};
|
|
275
|
-
declare function renderMetadataToHtml(metadata: Metadata, pathname?: string
|
|
276
|
+
declare function renderMetadataToHtml(metadata: Metadata, pathname?: string, options?: {
|
|
277
|
+
trailingSlash?: boolean;
|
|
278
|
+
}): string;
|
|
276
279
|
declare function MetadataHead({
|
|
277
280
|
metadata,
|
|
278
|
-
pathname
|
|
281
|
+
pathname,
|
|
282
|
+
trailingSlash
|
|
279
283
|
}: MetadataHeadProps): React.JSX.Element;
|
|
280
284
|
//#endregion
|
|
281
285
|
export { DEFAULT_VIEWPORT, Metadata, MetadataHead, MetadataMergeEntry, Viewport, ViewportHead, mergeMetadata, mergeMetadataEntries, mergeViewport, postProcessMetadata, renderMetadataToHtml, resolveModuleMetadata, resolveModuleViewport };
|
package/dist/shims/metadata.js
CHANGED
|
@@ -287,18 +287,35 @@ function formatResolvedMetadataUrl(url) {
|
|
|
287
287
|
if (url.pathname === "/" && url.search === "" && url.hash === "") return url.origin;
|
|
288
288
|
return url.href;
|
|
289
289
|
}
|
|
290
|
-
|
|
290
|
+
const TRAILING_SLASH_FILE_REGEX = /^(?:\/((?!\.well-known(?:\/.*)?)((?:[^/]+\/)*)([^/]+\.\w+)))(\/?|$)/i;
|
|
291
|
+
function resolveMetadataUrl(url, metadataBase, trailingSlash) {
|
|
291
292
|
const value = stringifyUrl(url);
|
|
292
|
-
if (
|
|
293
|
+
if (!metadataBase) return value;
|
|
293
294
|
try {
|
|
294
|
-
|
|
295
|
+
const isAbsolute = isAbsoluteOrProtocolRelativeUrl(value);
|
|
296
|
+
const composed = isAbsolute ? new URL(value, metadataBase) : new URL(joinMetadataPath(metadataBase.pathname, value), metadataBase);
|
|
297
|
+
if (isAbsolute && composed.origin !== metadataBase.origin) return value;
|
|
298
|
+
if (trailingSlash === true && composed.search === "") {
|
|
299
|
+
if (composed.pathname !== "/" && !composed.pathname.endsWith("/") && !TRAILING_SLASH_FILE_REGEX.test(composed.pathname)) composed.pathname += "/";
|
|
300
|
+
}
|
|
301
|
+
const result = formatResolvedMetadataUrl(composed);
|
|
302
|
+
if (trailingSlash === true && result === metadataBase.origin) return `${metadataBase.origin}/`;
|
|
303
|
+
return result;
|
|
295
304
|
} catch {
|
|
296
305
|
return value;
|
|
297
306
|
}
|
|
298
307
|
}
|
|
299
|
-
function resolveCanonicalUrl(url, metadataBase, pathname) {
|
|
300
|
-
if (url instanceof URL) return resolveMetadataUrl(url, metadataBase);
|
|
301
|
-
return resolveMetadataUrl(resolveRelativeMetadataUrl(url, pathname), metadataBase);
|
|
308
|
+
function resolveCanonicalUrl(url, metadataBase, pathname, trailingSlash) {
|
|
309
|
+
if (url instanceof URL) return resolveMetadataUrl(url, metadataBase, trailingSlash);
|
|
310
|
+
return resolveMetadataUrl(resolveRelativeMetadataUrl(url, pathname), metadataBase, trailingSlash);
|
|
311
|
+
}
|
|
312
|
+
function resolveAlternateUrl(url, metadataBase, pathname, trailingSlash) {
|
|
313
|
+
if (url instanceof URL) {
|
|
314
|
+
const resolvedUrl = new URL(pathname, url);
|
|
315
|
+
url.searchParams.forEach((value, key) => resolvedUrl.searchParams.set(key, value));
|
|
316
|
+
return resolveMetadataUrl(resolvedUrl, metadataBase, trailingSlash);
|
|
317
|
+
}
|
|
318
|
+
return resolveCanonicalUrl(url, metadataBase, pathname, trailingSlash);
|
|
302
319
|
}
|
|
303
320
|
function isSocialImageDescriptor(value) {
|
|
304
321
|
return typeof value === "object" && !(value instanceof URL);
|
|
@@ -359,13 +376,14 @@ function renderMetadataElementToHtml(node) {
|
|
|
359
376
|
default: return "";
|
|
360
377
|
}
|
|
361
378
|
}
|
|
362
|
-
function renderMetadataToHtml(metadata, pathname = "/") {
|
|
379
|
+
function renderMetadataToHtml(metadata, pathname = "/", options) {
|
|
363
380
|
return renderMetadataElementToHtml(MetadataHead({
|
|
364
381
|
metadata,
|
|
365
|
-
pathname
|
|
382
|
+
pathname,
|
|
383
|
+
trailingSlash: options?.trailingSlash
|
|
366
384
|
}));
|
|
367
385
|
}
|
|
368
|
-
function MetadataHead({ metadata, pathname = "/" }) {
|
|
386
|
+
function MetadataHead({ metadata, pathname = "/", trailingSlash }) {
|
|
369
387
|
const elements = [];
|
|
370
388
|
let key = 0;
|
|
371
389
|
const base = metadata.metadataBase;
|
|
@@ -474,7 +492,7 @@ function MetadataHead({ metadata, pathname = "/" }) {
|
|
|
474
492
|
}, key++));
|
|
475
493
|
if (og.url) elements.push(/* @__PURE__ */ jsx("meta", {
|
|
476
494
|
property: "og:url",
|
|
477
|
-
content:
|
|
495
|
+
content: resolveCanonicalUrl(og.url, base, pathname, trailingSlash)
|
|
478
496
|
}, key++));
|
|
479
497
|
if (og.siteName) elements.push(/* @__PURE__ */ jsx("meta", {
|
|
480
498
|
property: "og:site_name",
|
|
@@ -691,22 +709,22 @@ function MetadataHead({ metadata, pathname = "/" }) {
|
|
|
691
709
|
const alt = metadata.alternates;
|
|
692
710
|
if (alt.canonical) elements.push(/* @__PURE__ */ jsx("link", {
|
|
693
711
|
rel: "canonical",
|
|
694
|
-
href: resolveCanonicalUrl(alt.canonical, base, pathname)
|
|
712
|
+
href: resolveCanonicalUrl(alt.canonical, base, pathname, trailingSlash)
|
|
695
713
|
}, key++));
|
|
696
714
|
if (alt.languages) for (const [lang, href] of Object.entries(alt.languages)) elements.push(/* @__PURE__ */ jsx("link", {
|
|
697
715
|
rel: "alternate",
|
|
698
716
|
hrefLang: lang,
|
|
699
|
-
href:
|
|
717
|
+
href: resolveAlternateUrl(href, base, pathname, trailingSlash)
|
|
700
718
|
}, key++));
|
|
701
719
|
if (alt.media) for (const [media, href] of Object.entries(alt.media)) elements.push(/* @__PURE__ */ jsx("link", {
|
|
702
720
|
rel: "alternate",
|
|
703
721
|
media,
|
|
704
|
-
href:
|
|
722
|
+
href: resolveAlternateUrl(href, base, pathname, trailingSlash)
|
|
705
723
|
}, key++));
|
|
706
724
|
if (alt.types) for (const [type, href] of Object.entries(alt.types)) elements.push(/* @__PURE__ */ jsx("link", {
|
|
707
725
|
rel: "alternate",
|
|
708
726
|
type,
|
|
709
|
-
href:
|
|
727
|
+
href: resolveAlternateUrl(href, base, pathname, trailingSlash)
|
|
710
728
|
}, key++));
|
|
711
729
|
}
|
|
712
730
|
if (metadata.verification) {
|