vinext 1.4.0 → 1.4.1
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 +20 -20
- package/dist/build/prerender.js +3 -2
- package/dist/check.js +3 -6
- package/dist/client/dev-error-overlay-store.d.ts +1 -0
- package/dist/client/dev-error-overlay.d.ts +2 -0
- package/dist/client/dev-error-overlay.js +19 -3
- package/dist/config/config-matchers.js +2 -0
- package/dist/config/destination-params.d.ts +2 -1
- package/dist/config/destination-params.js +52 -2
- package/dist/config/next-config.d.ts +6 -0
- package/dist/config/next-config.js +18 -3
- package/dist/entries/app-rsc-entry.js +0 -1
- package/dist/entries/pages-server-entry.js +3 -1
- package/dist/index.js +29 -20
- package/dist/plugins/strip-server-exports.js +2 -1
- package/dist/server/api-handler.js +2 -1
- package/dist/server/app-browser-entry.js +7 -3
- package/dist/server/app-browser-rsc-redirect.js +3 -3
- package/dist/server/app-browser-server-action-client.js +2 -2
- package/dist/server/app-browser-visible-commit.js +2 -2
- package/dist/server/app-optimistic-routing.js +2 -3
- package/dist/server/app-page-boundary-render.js +5 -10
- package/dist/server/app-page-dispatch.d.ts +0 -1
- package/dist/server/app-page-dispatch.js +0 -1
- package/dist/server/app-page-element-builder.js +3 -3
- package/dist/server/app-page-execution.js +9 -6
- package/dist/server/app-page-render.d.ts +0 -1
- package/dist/server/app-page-render.js +14 -14
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.js +22 -5
- package/dist/server/app-page-stream.d.ts +10 -8
- package/dist/server/app-page-stream.js +2 -1
- package/dist/server/app-request-stage-independent-entry.js +1 -1
- package/dist/server/app-route-handler-execution.js +3 -2
- package/dist/server/app-route-handler-runtime.d.ts +1 -1
- package/dist/server/app-route-handler-runtime.js +11 -7
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +10 -10
- package/dist/server/app-rsc-cache-busting.js +27 -68
- package/dist/server/app-rsc-error-handler.js +1 -1
- package/dist/server/app-rsc-errors.js +4 -1
- package/dist/server/app-rsc-handler.js +53 -62
- package/dist/server/app-rsc-request-normalization.d.ts +10 -12
- package/dist/server/app-rsc-request-normalization.js +11 -14
- package/dist/server/app-rsc-response-stage.js +4 -12
- package/dist/server/app-server-action-execution.js +8 -4
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +13 -8
- package/dist/server/app-worker-stages.d.ts +12 -3
- package/dist/server/app-worker-stages.js +37 -4
- package/dist/server/bfcache-identity.d.ts +7 -0
- package/dist/server/bfcache-identity.js +10 -1
- package/dist/server/cacheability-manifest.js +1 -2
- package/dist/server/dev-origin-check.d.ts +2 -1
- package/dist/server/dev-origin-check.js +2 -1
- package/dist/server/dev-server.js +2 -1
- package/dist/server/image-optimization.d.ts +5 -0
- package/dist/server/image-optimization.js +6 -1
- package/dist/server/isr-cache.js +4 -1
- package/dist/server/metadata-route-response.js +1 -1
- package/dist/server/middleware-matcher.js +19 -6
- package/dist/server/middleware-runtime.js +6 -2
- package/dist/server/multi-stage.d.ts +7 -3
- package/dist/server/pages-node-compat.d.ts +1 -1
- package/dist/server/pages-node-compat.js +2 -0
- package/dist/server/pages-page-data.js +2 -1
- package/dist/server/pages-page-handler.js +17 -6
- package/dist/server/pages-page-response.d.ts +9 -0
- package/dist/server/pages-page-response.js +18 -4
- package/dist/server/pages-request-stage-entry.js +24 -4
- package/dist/server/pages-router-entry.js +3 -2
- package/dist/server/prod-server.d.ts +2 -2
- package/dist/server/prod-server.js +42 -8
- package/dist/server/request-error-log.d.ts +9 -0
- package/dist/server/request-error-log.js +13 -0
- package/dist/server/request-pipeline.d.ts +9 -4
- package/dist/server/request-pipeline.js +23 -15
- package/dist/server/rsc-completion-metadata.js +3 -0
- package/dist/server/static-file-cache.d.ts +9 -0
- package/dist/server/static-file-cache.js +13 -2
- package/dist/shims/cache-request-state.d.ts +6 -6
- package/dist/shims/cache-request-state.js +6 -36
- package/dist/shims/cache-runtime.d.ts +3 -1
- package/dist/shims/cache-runtime.js +77 -47
- package/dist/shims/cache.d.ts +10 -5
- package/dist/shims/cache.js +35 -22
- package/dist/shims/client-hook-error.d.ts +2 -0
- package/dist/shims/client-hook-error.js +16 -1
- package/dist/shims/fetch-cache.js +6 -2
- package/dist/shims/headers.d.ts +2 -1
- package/dist/shims/headers.js +5 -3
- package/dist/shims/internal/cache-context-accessor.d.ts +1 -1
- package/dist/shims/link.js +5 -10
- package/dist/shims/navigation.js +2 -3
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/slot.d.ts +6 -2
- package/dist/shims/slot.js +10 -3
- package/dist/shims/unified-request-context.d.ts +6 -0
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/cache-life-profiles.d.ts +33 -0
- package/dist/utils/cache-life-profiles.js +111 -0
- package/dist/utils/middleware-request-headers.d.ts +14 -3
- package/dist/utils/middleware-request-headers.js +54 -7
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CacheLifeConfig } from "../utils/cache-life-profiles.js";
|
|
1
2
|
import { NavigationContext } from "./navigation-context-state.js";
|
|
2
3
|
import "./navigation.js";
|
|
3
4
|
import { ExecutionContextLike } from "./request-context.js";
|
|
@@ -6,7 +7,7 @@ import { FetchCacheState } from "./fetch-cache-state.js";
|
|
|
6
7
|
import "./fetch-cache.js";
|
|
7
8
|
import { HeadersAccessPhase, VinextHeadersShimState } from "./internal/headers-state.js";
|
|
8
9
|
import { HeadersContext } from "./headers.js";
|
|
9
|
-
import {
|
|
10
|
+
import { CacheState } from "./cache-request-state.js";
|
|
10
11
|
import { RouterState, SSRContext } from "./router-state.js";
|
|
11
12
|
import { PrivateCacheState } from "./cache-runtime.js";
|
|
12
13
|
import { HeadState } from "./head-state.js";
|
package/dist/shims/slot.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ type MergeElementsOptions = {
|
|
|
40
40
|
clearAbsentSlots?: boolean;
|
|
41
41
|
preserveAbsentSlots?: boolean;
|
|
42
42
|
preserveElementIds?: readonly string[];
|
|
43
|
+
preserveElementSeedIds?: readonly string[];
|
|
43
44
|
preservePreviousSlotIds?: readonly string[];
|
|
44
45
|
};
|
|
45
46
|
export declare function updateBfcacheSlotEntryOrder(previousOrder: readonly string[], activeStateKey: string, maxEntries?: number): string[];
|
|
@@ -67,9 +68,12 @@ export declare function BfcacheSegmentBoundary({ children, id, stateKey }: {
|
|
|
67
68
|
* the parent's layout router, above the child's boundaries, so a page left for a
|
|
68
69
|
* sibling with its own layout keeps its state when navigating back.
|
|
69
70
|
*/
|
|
70
|
-
export declare function BfcacheChildrenBoundary({ children, id }: {
|
|
71
|
+
export declare function BfcacheChildrenBoundary({ children, id, stateKey }: {
|
|
71
72
|
children: React$1.ReactNode;
|
|
72
|
-
|
|
73
|
+
/** The child element whose identity keys the entries. */
|
|
74
|
+
id?: string;
|
|
75
|
+
/** A fixed key, for a segment level with no element of its own. */
|
|
76
|
+
stateKey?: string;
|
|
73
77
|
}): React$1.JSX.Element;
|
|
74
78
|
export declare function getNonCacheComponentsSegmentKey(id: string, activeStateKey: string): string | undefined;
|
|
75
79
|
export declare function resolveBfcacheSegmentStateKey(id: string, identityMap: Readonly<Record<string, string>>, bfcacheIdMap: Readonly<Record<string, string>> | null): string | undefined;
|
package/dist/shims/slot.js
CHANGED
|
@@ -213,21 +213,22 @@ function BfcacheSegmentBoundary({ children, id, stateKey }) {
|
|
|
213
213
|
* the parent's layout router, above the child's boundaries, so a page left for a
|
|
214
214
|
* sibling with its own layout keeps its state when navigating back.
|
|
215
215
|
*/
|
|
216
|
-
function BfcacheChildrenBoundary({ children, id }) {
|
|
216
|
+
function BfcacheChildrenBoundary({ children, id, stateKey }) {
|
|
217
217
|
if (!BfcacheIdMapContext || !BfcacheSegmentIdContext || !isCacheComponentsEnabled()) return /* @__PURE__ */ jsx(Fragment$1, { children });
|
|
218
218
|
return /* @__PURE__ */ jsx(BfcacheChildrenActivityBoundary, {
|
|
219
219
|
id,
|
|
220
220
|
IdMapContext: BfcacheIdMapContext,
|
|
221
221
|
SegmentContext: BfcacheSegmentIdContext,
|
|
222
|
+
stateKey,
|
|
222
223
|
children
|
|
223
224
|
});
|
|
224
225
|
}
|
|
225
|
-
function BfcacheChildrenActivityBoundary({ children, id, IdMapContext, SegmentContext }) {
|
|
226
|
+
function BfcacheChildrenActivityBoundary({ children, id, IdMapContext, SegmentContext, stateKey }) {
|
|
226
227
|
const elements = React$1.useContext(ElementsContext);
|
|
227
228
|
const identityMap = React$1.useContext(BfcacheIdentityMapContext);
|
|
228
229
|
const bfcacheIdMap = React$1.useContext(IdMapContext);
|
|
229
230
|
const segmentId = React$1.useContext(SegmentContext);
|
|
230
|
-
const activeStateKey = resolveBfcacheSegmentStateKey(id, identityMap, bfcacheIdMap);
|
|
231
|
+
const activeStateKey = stateKey ?? (id === void 0 ? void 0 : resolveBfcacheSegmentStateKey(id, identityMap, bfcacheIdMap));
|
|
231
232
|
if (segmentId === null || activeStateKey === void 0) return /* @__PURE__ */ jsx(Fragment$1, { children });
|
|
232
233
|
return /* @__PURE__ */ jsx(BfcacheActivitySlotBoundary, {
|
|
233
234
|
activeStateKey,
|
|
@@ -272,6 +273,7 @@ function mergeElements(prev, next, options = {}) {
|
|
|
272
273
|
const clearAbsentSlots = typeof options === "boolean" ? options : options.clearAbsentSlots ?? false;
|
|
273
274
|
const preserveAbsentSlots = typeof options === "boolean" ? !options : options.preserveAbsentSlots ?? true;
|
|
274
275
|
const preserveElementIds = typeof options === "boolean" ? [] : options.preserveElementIds ?? [];
|
|
276
|
+
const preserveElementSeedIds = typeof options === "boolean" ? [] : options.preserveElementSeedIds ?? [];
|
|
275
277
|
const preservePreviousSlotIds = typeof options === "boolean" ? [] : options.preservePreviousSlotIds ?? [];
|
|
276
278
|
const merged = { ...next };
|
|
277
279
|
const preservedIdentityIds = /* @__PURE__ */ new Set();
|
|
@@ -282,6 +284,11 @@ function mergeElements(prev, next, options = {}) {
|
|
|
282
284
|
preservedIdentityIds.add(id);
|
|
283
285
|
}
|
|
284
286
|
}
|
|
287
|
+
for (const id of preserveElementSeedIds) {
|
|
288
|
+
if (preservedIdentityIds.has(id) || !Object.hasOwn(prev, id)) continue;
|
|
289
|
+
const value = prev[id];
|
|
290
|
+
if (value !== void 0) merged[id] = value;
|
|
291
|
+
}
|
|
285
292
|
const slotKeys = new Set([...Object.keys(prev), ...Object.keys(next)].filter((key) => AppElementsWire.isSlotId(key) && !isNestedBfcacheSlotSegmentId(key)));
|
|
286
293
|
if (clearAbsentSlots) {
|
|
287
294
|
for (const key of slotKeys) if (!Object.hasOwn(next, key)) delete merged[key];
|
|
@@ -30,6 +30,12 @@ export type UnifiedRequestContext = {
|
|
|
30
30
|
requestCache: WeakMap<(...args: any[]) => any, unknown>;
|
|
31
31
|
/** Shared lifecycle state for work deferred until the response closes. */
|
|
32
32
|
afterContext: AfterRequestContext;
|
|
33
|
+
/**
|
|
34
|
+
* Draft-mode state of the headers context this request last cleared. The
|
|
35
|
+
* render can outlive its headers context (cleared once the response body
|
|
36
|
+
* closes), and so do after() callbacks; cache bypasses keep reading this.
|
|
37
|
+
*/
|
|
38
|
+
draftModeAtHeadersClear: boolean;
|
|
33
39
|
} & VinextHeadersShimState & I18nState & NavigationState & CacheState & PrivateCacheState & FetchCacheState & RouterState & HeadState & RootParamsState;
|
|
34
40
|
export type AfterRequestContext = {
|
|
35
41
|
callbacks: Array<() => unknown>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/utils/cache-life-profiles.d.ts
|
|
2
|
+
export type CacheLifeConfig = {
|
|
3
|
+
stale?: number;
|
|
4
|
+
revalidate?: number;
|
|
5
|
+
expire?: number;
|
|
6
|
+
};
|
|
7
|
+
/** Next.js's built-in profiles (`defaultConfig.cacheLife` in config-shared.ts). */
|
|
8
|
+
export declare const BUILT_IN_CACHE_LIFE_PROFILES: Readonly<Record<string, Readonly<CacheLifeConfig>>>;
|
|
9
|
+
/**
|
|
10
|
+
* Merge next.config `cacheLife` profiles over the built-ins, as Next.js does
|
|
11
|
+
* in `assignDefaultsAndValidate` (server/config.ts): a user profile replaces
|
|
12
|
+
* the built-in of the same name whole, and only `default` gets its missing
|
|
13
|
+
* fields filled: `stale` from `staleTimes.static`, `revalidate` from the
|
|
14
|
+
* built-in, `expire` from `expireTime`. That includes the built-in `default`,
|
|
15
|
+
* whose `stale` is unset in Next.js's defaults too. The other profiles keep
|
|
16
|
+
* their gaps, which the "use cache" store resolves from `default`.
|
|
17
|
+
*
|
|
18
|
+
* Next.js only schema-checks these profiles (fields must be numbers) and
|
|
19
|
+
* warns; `revalidate > expire` is checked for `cacheLife({...})` calls, not
|
|
20
|
+
* for config profiles.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveCacheLifeProfiles(userProfiles: unknown, defaults: {
|
|
23
|
+
expireTime: number;
|
|
24
|
+
staticStaleTime: number;
|
|
25
|
+
}, warn: (message: string) => void): Record<string, CacheLifeConfig>;
|
|
26
|
+
/** Serialize resolved profiles for the `__VINEXT_CACHE_LIFE_PROFILES` define. */
|
|
27
|
+
export declare function serializeCacheLifeProfiles(profiles: Record<string, CacheLifeConfig>): string;
|
|
28
|
+
/**
|
|
29
|
+
* Read the `__VINEXT_CACHE_LIFE_PROFILES` define. When absent, the profiles a
|
|
30
|
+
* next.config without `cacheLife` resolves to.
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseCacheLifeProfiles(serialized: string | undefined): Record<string, CacheLifeConfig>;
|
|
33
|
+
//#endregion
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { isUnknownRecord } from "./record.js";
|
|
2
|
+
//#region src/utils/cache-life-profiles.ts
|
|
3
|
+
/** Next.js's built-in profiles (`defaultConfig.cacheLife` in config-shared.ts). */
|
|
4
|
+
const BUILT_IN_CACHE_LIFE_PROFILES = {
|
|
5
|
+
default: {
|
|
6
|
+
revalidate: 900,
|
|
7
|
+
expire: 4294967294
|
|
8
|
+
},
|
|
9
|
+
seconds: {
|
|
10
|
+
stale: 30,
|
|
11
|
+
revalidate: 1,
|
|
12
|
+
expire: 60
|
|
13
|
+
},
|
|
14
|
+
minutes: {
|
|
15
|
+
stale: 300,
|
|
16
|
+
revalidate: 60,
|
|
17
|
+
expire: 3600
|
|
18
|
+
},
|
|
19
|
+
hours: {
|
|
20
|
+
stale: 300,
|
|
21
|
+
revalidate: 3600,
|
|
22
|
+
expire: 86400
|
|
23
|
+
},
|
|
24
|
+
days: {
|
|
25
|
+
stale: 300,
|
|
26
|
+
revalidate: 86400,
|
|
27
|
+
expire: 604800
|
|
28
|
+
},
|
|
29
|
+
weeks: {
|
|
30
|
+
stale: 300,
|
|
31
|
+
revalidate: 604800,
|
|
32
|
+
expire: 2592e3
|
|
33
|
+
},
|
|
34
|
+
max: {
|
|
35
|
+
stale: 300,
|
|
36
|
+
revalidate: 2592e3,
|
|
37
|
+
expire: 31536e3
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const CACHE_LIFE_FIELDS = [
|
|
41
|
+
"stale",
|
|
42
|
+
"revalidate",
|
|
43
|
+
"expire"
|
|
44
|
+
];
|
|
45
|
+
function copyBuiltInProfiles() {
|
|
46
|
+
const profiles = {};
|
|
47
|
+
for (const [name, profile] of Object.entries(BUILT_IN_CACHE_LIFE_PROFILES)) profiles[name] = { ...profile };
|
|
48
|
+
return profiles;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Merge next.config `cacheLife` profiles over the built-ins, as Next.js does
|
|
52
|
+
* in `assignDefaultsAndValidate` (server/config.ts): a user profile replaces
|
|
53
|
+
* the built-in of the same name whole, and only `default` gets its missing
|
|
54
|
+
* fields filled: `stale` from `staleTimes.static`, `revalidate` from the
|
|
55
|
+
* built-in, `expire` from `expireTime`. That includes the built-in `default`,
|
|
56
|
+
* whose `stale` is unset in Next.js's defaults too. The other profiles keep
|
|
57
|
+
* their gaps, which the "use cache" store resolves from `default`.
|
|
58
|
+
*
|
|
59
|
+
* Next.js only schema-checks these profiles (fields must be numbers) and
|
|
60
|
+
* warns; `revalidate > expire` is checked for `cacheLife({...})` calls, not
|
|
61
|
+
* for config profiles.
|
|
62
|
+
*/
|
|
63
|
+
function resolveCacheLifeProfiles(userProfiles, defaults, warn) {
|
|
64
|
+
const profiles = copyBuiltInProfiles();
|
|
65
|
+
for (const [name, rawProfile] of Object.entries(isUnknownRecord(userProfiles) ? userProfiles : {})) {
|
|
66
|
+
if (!isUnknownRecord(rawProfile)) {
|
|
67
|
+
warn(`[vinext] Invalid next.config option \`cacheLife.${name}\`: expected an object.`);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const profile = {};
|
|
71
|
+
for (const field of CACHE_LIFE_FIELDS) {
|
|
72
|
+
const value = rawProfile[field];
|
|
73
|
+
if (value === void 0) continue;
|
|
74
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
75
|
+
warn(`[vinext] Invalid next.config option \`cacheLife.${name}.${field}\`: expected a number of seconds.`);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
profile[field] = value;
|
|
79
|
+
}
|
|
80
|
+
profiles[name] = profile;
|
|
81
|
+
}
|
|
82
|
+
const defaultProfile = profiles.default;
|
|
83
|
+
defaultProfile.stale ??= defaults.staticStaleTime;
|
|
84
|
+
defaultProfile.revalidate ??= BUILT_IN_CACHE_LIFE_PROFILES.default.revalidate;
|
|
85
|
+
defaultProfile.expire ??= defaults.expireTime;
|
|
86
|
+
return profiles;
|
|
87
|
+
}
|
|
88
|
+
function encodeNonFiniteNumber(_key, value) {
|
|
89
|
+
return value === Infinity || value === -Infinity ? String(value) : value;
|
|
90
|
+
}
|
|
91
|
+
function decodeNonFiniteNumber(_key, value) {
|
|
92
|
+
return value === "Infinity" || value === "-Infinity" ? Number(value) : value;
|
|
93
|
+
}
|
|
94
|
+
/** Serialize resolved profiles for the `__VINEXT_CACHE_LIFE_PROFILES` define. */
|
|
95
|
+
function serializeCacheLifeProfiles(profiles) {
|
|
96
|
+
return JSON.stringify(profiles, encodeNonFiniteNumber);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Read the `__VINEXT_CACHE_LIFE_PROFILES` define. When absent, the profiles a
|
|
100
|
+
* next.config without `cacheLife` resolves to.
|
|
101
|
+
*/
|
|
102
|
+
function parseCacheLifeProfiles(serialized) {
|
|
103
|
+
if (!serialized) {
|
|
104
|
+
const profiles = copyBuiltInProfiles();
|
|
105
|
+
profiles.default.stale = 300;
|
|
106
|
+
return profiles;
|
|
107
|
+
}
|
|
108
|
+
return JSON.parse(serialized, decodeNonFiniteNumber);
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
export { BUILT_IN_CACHE_LIFE_PROFILES, parseCacheLifeProfiles, resolveCacheLifeProfiles, serializeCacheLifeProfiles };
|
|
@@ -7,7 +7,17 @@ type MiddlewareHeaderSource = Headers | Record<string, MiddlewareHeaderValue>;
|
|
|
7
7
|
* under their literal protocol-header names on both the request and response.
|
|
8
8
|
*/
|
|
9
9
|
export declare function getUnconsumedMiddlewareRequestHeaders(source: MiddlewareHeaderSource): Map<string, string>;
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* `baseHeaders` with only Next.js's generic merge of ordinary middleware
|
|
12
|
+
* response headers applied, without the request-header protocol.
|
|
13
|
+
*/
|
|
14
|
+
export declare function applyMiddlewareResponseHeadersToRequest(baseHeaders: Headers, middlewareHeaders: MiddlewareHeaderSource): Headers;
|
|
15
|
+
/**
|
|
16
|
+
* Whether middleware changed the headers seen by downstream application code
|
|
17
|
+
* through its request-header protocol. Ordinary response headers are copied to
|
|
18
|
+
* the request as well, but like a client's own headers they do not opt a
|
|
19
|
+
* render out of the shared response stage.
|
|
20
|
+
*/
|
|
11
21
|
export declare function hasMiddlewareRequestHeaderOverrides(source: MiddlewareHeaderSource | null): boolean;
|
|
12
22
|
export declare function encodeMiddlewareRequestHeaders(targetHeaders: Headers, requestHeaders: Headers): void;
|
|
13
23
|
/**
|
|
@@ -16,8 +26,9 @@ export declare function encodeMiddlewareRequestHeaders(targetHeaders: Headers, r
|
|
|
16
26
|
* middleware. Never re-add absent headers from the base request — that would
|
|
17
27
|
* resurrect credentials the app explicitly stripped before an external
|
|
18
28
|
* rewrite. Next.js treats the empty value emitted for `new Headers()` as no
|
|
19
|
-
* override. Any unconsumed `x-middleware-request-*` values
|
|
20
|
-
*
|
|
29
|
+
* override. Any unconsumed `x-middleware-request-*` values and every other
|
|
30
|
+
* truthy middleware response header are subsequently copied to the request
|
|
31
|
+
* under their literal names, replacing values the client sent.
|
|
21
32
|
*/
|
|
22
33
|
export declare function buildRequestHeadersFromMiddlewareResponse(baseHeaders: Headers, middlewareHeaders: MiddlewareHeaderSource): Headers | null;
|
|
23
34
|
export declare function shouldKeepMiddlewareHeader(key: string): boolean;
|
|
@@ -34,7 +34,52 @@ function getUnconsumedMiddlewareRequestHeaders(source) {
|
|
|
34
34
|
for (const [key, value] of getForwardedRequestHeaders(source)) if (value && !overriddenHeaders?.has(key)) unconsumedHeaders.set(`${MIDDLEWARE_REQUEST_HEADER_PREFIX}${key}`, value);
|
|
35
35
|
return unconsumedHeaders;
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
const UNMERGED_MIDDLEWARE_RESPONSE_HEADERS = /* @__PURE__ */ new Set([
|
|
38
|
+
"accept-encoding",
|
|
39
|
+
"connection",
|
|
40
|
+
"content-encoding",
|
|
41
|
+
"content-length",
|
|
42
|
+
"expect",
|
|
43
|
+
"keep-alive",
|
|
44
|
+
"keepalive",
|
|
45
|
+
"transfer-encoding"
|
|
46
|
+
]);
|
|
47
|
+
/**
|
|
48
|
+
* Return the truthy ordinary middleware response headers. Next.js's generic
|
|
49
|
+
* middleware-header merge writes each of them to the request too, so a value
|
|
50
|
+
* middleware sets replaces one the client sent under the same name. The
|
|
51
|
+
* `x-middleware-*` namespace carries vinext's middleware protocol and is
|
|
52
|
+
* handled separately.
|
|
53
|
+
*/
|
|
54
|
+
function getMergedMiddlewareResponseHeaders(source) {
|
|
55
|
+
const mergedHeaders = new Headers();
|
|
56
|
+
const entries = source instanceof Headers ? source : Object.entries(source).flatMap(([key, value]) => Array.isArray(value) ? value.map((item) => [key, item]) : [[key, value]]);
|
|
57
|
+
for (const [key, value] of entries) {
|
|
58
|
+
const lowerKey = key.toLowerCase();
|
|
59
|
+
if (value && !lowerKey.startsWith("x-middleware-") && !UNMERGED_MIDDLEWARE_RESPONSE_HEADERS.has(lowerKey)) mergedHeaders.append(lowerKey, value);
|
|
60
|
+
}
|
|
61
|
+
return mergedHeaders;
|
|
62
|
+
}
|
|
63
|
+
function applyMergedMiddlewareHeaders(targetHeaders, unconsumedHeaders, mergedHeaders) {
|
|
64
|
+
for (const [key, value] of unconsumedHeaders) targetHeaders.set(key, value);
|
|
65
|
+
for (const key of new Set(mergedHeaders.keys())) targetHeaders.delete(key);
|
|
66
|
+
for (const [key, value] of mergedHeaders) targetHeaders.append(key, value);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* `baseHeaders` with only Next.js's generic merge of ordinary middleware
|
|
70
|
+
* response headers applied, without the request-header protocol.
|
|
71
|
+
*/
|
|
72
|
+
function applyMiddlewareResponseHeadersToRequest(baseHeaders, middlewareHeaders) {
|
|
73
|
+
const nextHeaders = new Headers(baseHeaders);
|
|
74
|
+
applyMergedMiddlewareHeaders(nextHeaders, /* @__PURE__ */ new Map(), getMergedMiddlewareResponseHeaders(middlewareHeaders));
|
|
75
|
+
return nextHeaders;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Whether middleware changed the headers seen by downstream application code
|
|
79
|
+
* through its request-header protocol. Ordinary response headers are copied to
|
|
80
|
+
* the request as well, but like a client's own headers they do not opt a
|
|
81
|
+
* render out of the shared response stage.
|
|
82
|
+
*/
|
|
38
83
|
function hasMiddlewareRequestHeaderOverrides(source) {
|
|
39
84
|
if (!source) return false;
|
|
40
85
|
return Boolean(getMiddlewareHeaderValue(source, "x-middleware-override-headers")) || getUnconsumedMiddlewareRequestHeaders(source).size > 0;
|
|
@@ -50,17 +95,19 @@ function encodeMiddlewareRequestHeaders(targetHeaders, requestHeaders) {
|
|
|
50
95
|
* middleware. Never re-add absent headers from the base request — that would
|
|
51
96
|
* resurrect credentials the app explicitly stripped before an external
|
|
52
97
|
* rewrite. Next.js treats the empty value emitted for `new Headers()` as no
|
|
53
|
-
* override. Any unconsumed `x-middleware-request-*` values
|
|
54
|
-
*
|
|
98
|
+
* override. Any unconsumed `x-middleware-request-*` values and every other
|
|
99
|
+
* truthy middleware response header are subsequently copied to the request
|
|
100
|
+
* under their literal names, replacing values the client sent.
|
|
55
101
|
*/
|
|
56
102
|
function buildRequestHeadersFromMiddlewareResponse(baseHeaders, middlewareHeaders) {
|
|
57
103
|
const forwardedHeaders = getForwardedRequestHeaders(middlewareHeaders);
|
|
58
104
|
const unconsumedHeaders = getUnconsumedMiddlewareRequestHeaders(middlewareHeaders);
|
|
105
|
+
const mergedHeaders = getMergedMiddlewareResponseHeaders(middlewareHeaders);
|
|
59
106
|
const rawOverrideHeader = getMiddlewareHeaderValue(middlewareHeaders, MIDDLEWARE_OVERRIDE_HEADERS);
|
|
60
107
|
if (!rawOverrideHeader) {
|
|
61
|
-
if (unconsumedHeaders.size === 0) return null;
|
|
108
|
+
if (unconsumedHeaders.size === 0 && mergedHeaders.keys().next().done) return null;
|
|
62
109
|
const nextHeaders = new Headers(baseHeaders);
|
|
63
|
-
|
|
110
|
+
applyMergedMiddlewareHeaders(nextHeaders, unconsumedHeaders, mergedHeaders);
|
|
64
111
|
return nextHeaders;
|
|
65
112
|
}
|
|
66
113
|
const overrideHeaderNames = parseOverrideHeaderNames(rawOverrideHeader);
|
|
@@ -69,11 +116,11 @@ function buildRequestHeadersFromMiddlewareResponse(baseHeaders, middlewareHeader
|
|
|
69
116
|
const value = forwardedHeaders.get(key);
|
|
70
117
|
if (value !== void 0) nextHeaders.set(key, value);
|
|
71
118
|
}
|
|
72
|
-
|
|
119
|
+
applyMergedMiddlewareHeaders(nextHeaders, unconsumedHeaders, mergedHeaders);
|
|
73
120
|
return nextHeaders;
|
|
74
121
|
}
|
|
75
122
|
function shouldKeepMiddlewareHeader(key) {
|
|
76
123
|
return key === "x-middleware-override-headers" || key === "x-middleware-cache" || key === "x-middleware-set-cookie" || key.startsWith("x-middleware-request-");
|
|
77
124
|
}
|
|
78
125
|
//#endregion
|
|
79
|
-
export { buildRequestHeadersFromMiddlewareResponse, encodeMiddlewareRequestHeaders, getUnconsumedMiddlewareRequestHeaders, hasMiddlewareRequestHeaderOverrides, shouldKeepMiddlewareHeader };
|
|
126
|
+
export { applyMiddlewareResponseHeadersToRequest, buildRequestHeadersFromMiddlewareResponse, encodeMiddlewareRequestHeaders, getUnconsumedMiddlewareRequestHeaders, hasMiddlewareRequestHeaderOverrides, shouldKeepMiddlewareHeader };
|