cloudflare-next-intl 0.9.20 → 0.9.21
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.
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export declare function isRecentBuild(setAt: number | null, now: number, windowMs?: number): boolean;
|
|
2
|
-
export declare function shouldRecoverFromStaleDeploy(error: unknown, buildId: string, marker: string | null,
|
|
2
|
+
export declare function shouldRecoverFromStaleDeploy(error: unknown, buildId: string, marker: string | null, recentBuild?: boolean, reloadTime?: number | null, now?: number, throttleMs?: number): boolean;
|
|
3
|
+
export declare function performCacheBustReload(): void;
|
|
3
4
|
export default function useStaleDeployRecovery(error: unknown, onRecover?: () => Promise<unknown>, delayMs?: number): boolean;
|
|
@@ -3,9 +3,11 @@ import { useEffect, useState } from 'react';
|
|
|
3
3
|
import isStaleDeployError from './is_stale_deploy_error.js';
|
|
4
4
|
import clearClientCache from './clear_client_cache.js';
|
|
5
5
|
const RECOVERY_RELOAD_KEY = 'stale-deploy-recovery-reloaded';
|
|
6
|
+
const RECOVERY_TIME_KEY = 'stale-deploy-recovery-time';
|
|
6
7
|
const BUILD_ID_KEY = 'buildId';
|
|
7
8
|
const BUILD_ID_SET_AT_KEY = 'buildIdSetAt';
|
|
8
9
|
const RECENT_BUILD_WINDOW_MS = 60000;
|
|
10
|
+
const RELOAD_THROTTLE_MS = 15000;
|
|
9
11
|
function currentBuildId() {
|
|
10
12
|
try {
|
|
11
13
|
return localStorage.getItem(BUILD_ID_KEY) ?? 'unknown';
|
|
@@ -26,21 +28,41 @@ function buildIdSetAt() {
|
|
|
26
28
|
export function isRecentBuild(setAt, now, windowMs = RECENT_BUILD_WINDOW_MS) {
|
|
27
29
|
return setAt !== null && now - setAt < windowMs;
|
|
28
30
|
}
|
|
29
|
-
export function shouldRecoverFromStaleDeploy(error, buildId, marker,
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
export function shouldRecoverFromStaleDeploy(error, buildId, marker, recentBuild = false, reloadTime = null, now = Date.now(), throttleMs = RELOAD_THROTTLE_MS) {
|
|
32
|
+
if (!isStaleDeployError(error))
|
|
33
|
+
return false;
|
|
34
|
+
const isRecentlyReloaded = reloadTime !== null && now - reloadTime < throttleMs;
|
|
35
|
+
const isSameBuildMarker = marker !== null && marker !== '' && (buildId === 'unknown' || marker === buildId);
|
|
36
|
+
if (isSameBuildMarker && isRecentlyReloaded && !recentBuild) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
32
40
|
}
|
|
33
41
|
function canRecover(error) {
|
|
34
42
|
if (typeof window === 'undefined')
|
|
35
43
|
return false;
|
|
36
44
|
try {
|
|
37
|
-
|
|
45
|
+
const reloadTimeRaw = sessionStorage.getItem(RECOVERY_TIME_KEY);
|
|
46
|
+
const reloadTime = reloadTimeRaw ? Number(reloadTimeRaw) : null;
|
|
47
|
+
return shouldRecoverFromStaleDeploy(error, currentBuildId(), sessionStorage.getItem(RECOVERY_RELOAD_KEY), isRecentBuild(buildIdSetAt(), Date.now()), reloadTime, Date.now());
|
|
38
48
|
}
|
|
39
49
|
catch {
|
|
40
50
|
return false;
|
|
41
51
|
}
|
|
42
52
|
}
|
|
43
|
-
export
|
|
53
|
+
export function performCacheBustReload() {
|
|
54
|
+
if (typeof window === 'undefined')
|
|
55
|
+
return;
|
|
56
|
+
try {
|
|
57
|
+
const url = new URL(window.location.href);
|
|
58
|
+
url.searchParams.set('_stale_reload', String(Date.now()));
|
|
59
|
+
window.location.replace(url.toString());
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
window.location.reload();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export default function useStaleDeployRecovery(error, onRecover, delayMs = 1000) {
|
|
44
66
|
const [recovering] = useState(() => canRecover(error));
|
|
45
67
|
const [initialOnRecover] = useState(() => onRecover);
|
|
46
68
|
const [initialDelayMs] = useState(() => delayMs);
|
|
@@ -53,9 +75,10 @@ export default function useStaleDeployRecovery(error, onRecover, delayMs = 5000)
|
|
|
53
75
|
.finally(() => {
|
|
54
76
|
try {
|
|
55
77
|
sessionStorage.setItem(RECOVERY_RELOAD_KEY, buildId);
|
|
78
|
+
sessionStorage.setItem(RECOVERY_TIME_KEY, String(Date.now()));
|
|
56
79
|
}
|
|
57
80
|
catch { }
|
|
58
|
-
|
|
81
|
+
performCacheBustReload();
|
|
59
82
|
});
|
|
60
83
|
}, initialDelayMs);
|
|
61
84
|
return () => clearTimeout(timeout);
|
|
@@ -40,7 +40,13 @@ export default function HelperScript() {
|
|
|
40
40
|
if (sessionStorage.getItem(key) === buildId) return;
|
|
41
41
|
attemptedThisLoad = true;
|
|
42
42
|
sessionStorage.setItem(key, buildId);
|
|
43
|
-
|
|
43
|
+
try {
|
|
44
|
+
var u = new URL(window.location.href);
|
|
45
|
+
u.searchParams.set('_stale_reload', String(Date.now()));
|
|
46
|
+
window.location.replace(u.toString());
|
|
47
|
+
} catch (e) {
|
|
48
|
+
window.location.reload();
|
|
49
|
+
}
|
|
44
50
|
} catch (e) {
|
|
45
51
|
console.error('Stale Deploy Early Catch Script Error:', e);
|
|
46
52
|
}
|
|
@@ -107,7 +113,16 @@ export default function HelperScript() {
|
|
|
107
113
|
// 3. Handle Locale Redirect.
|
|
108
114
|
// The logic is clearer: redirect only if a non-default locale is set
|
|
109
115
|
// and the URL isn't already localized.
|
|
116
|
+
// Clean up stale reload query parameter if present
|
|
110
117
|
const { pathname, search, hash } = window.location;
|
|
118
|
+
if (search && search.indexOf('_stale_reload=') > -1) {
|
|
119
|
+
try {
|
|
120
|
+
const cleanUrl = new URL(window.location.href);
|
|
121
|
+
cleanUrl.searchParams.delete('_stale_reload');
|
|
122
|
+
window.history.replaceState(history.state, '', cleanUrl.pathname + cleanUrl.search + cleanUrl.hash);
|
|
123
|
+
} catch (e) {}
|
|
124
|
+
}
|
|
125
|
+
|
|
111
126
|
if (locale && locale !== '${config.defaultLocale}' && !pathname.startsWith(\`/\${locale}\`)) {
|
|
112
127
|
const newPath = \`/\${locale}\${pathname === '/' ? '' : pathname}\${search}\${hash}\`;
|
|
113
128
|
// Redirecting will stop further script execution on this page.
|
|
@@ -54,12 +54,13 @@ export async function getCountry(input, generate, headerNames) {
|
|
|
54
54
|
const names = headerNames
|
|
55
55
|
?? gen?.countryHeaderNames
|
|
56
56
|
?? defaultCountryHeaderNames;
|
|
57
|
+
const cookieName = gen?.countryCookieName ?? countryCookieKey;
|
|
57
58
|
if (input) {
|
|
58
59
|
if ('headers' in input && input.headers) {
|
|
59
60
|
const country = extractFromHeaderNames(input.headers, names);
|
|
60
61
|
if (country)
|
|
61
62
|
return country;
|
|
62
|
-
const cookieCountry = extractCookieHeader(input.headers,
|
|
63
|
+
const cookieCountry = extractCookieHeader(input.headers, cookieName);
|
|
63
64
|
if (cookieCountry)
|
|
64
65
|
return cookieCountry;
|
|
65
66
|
}
|
|
@@ -67,11 +68,11 @@ export async function getCountry(input, generate, headerNames) {
|
|
|
67
68
|
const country = extractFromHeaderNames(input, names);
|
|
68
69
|
if (country)
|
|
69
70
|
return country;
|
|
70
|
-
const cookieCountry = extractCookieHeader(input,
|
|
71
|
+
const cookieCountry = extractCookieHeader(input, cookieName);
|
|
71
72
|
if (cookieCountry)
|
|
72
73
|
return cookieCountry;
|
|
73
74
|
}
|
|
74
|
-
const cookieCountry = extractCookie(input.cookies,
|
|
75
|
+
const cookieCountry = extractCookie(input.cookies, cookieName);
|
|
75
76
|
if (cookieCountry) {
|
|
76
77
|
return cookieCountry;
|
|
77
78
|
}
|
|
@@ -86,7 +87,7 @@ export async function getCountry(input, generate, headerNames) {
|
|
|
86
87
|
const country = extractFromHeaderNames(h, names);
|
|
87
88
|
if (country)
|
|
88
89
|
return country;
|
|
89
|
-
const cookieCountry = extractCookieHeader(h,
|
|
90
|
+
const cookieCountry = extractCookieHeader(h, cookieName);
|
|
90
91
|
if (cookieCountry)
|
|
91
92
|
return cookieCountry;
|
|
92
93
|
}
|
|
@@ -95,7 +96,7 @@ export async function getCountry(input, generate, headerNames) {
|
|
|
95
96
|
try {
|
|
96
97
|
const { cookies } = await import('next/headers.js');
|
|
97
98
|
const c = await cookies();
|
|
98
|
-
const country = extractCookie(c,
|
|
99
|
+
const country = extractCookie(c, cookieName);
|
|
99
100
|
if (country)
|
|
100
101
|
return country;
|
|
101
102
|
}
|
|
@@ -129,12 +130,13 @@ export async function getTimezone(input, fallback, generate, headerNames) {
|
|
|
129
130
|
const names = headerNames
|
|
130
131
|
?? gen?.timezoneHeaderNames
|
|
131
132
|
?? defaultTimezoneHeaderNames;
|
|
133
|
+
const cookieName = gen?.timezoneCookieName ?? timezoneCookieKey;
|
|
132
134
|
if (input) {
|
|
133
135
|
if ('headers' in input && input.headers) {
|
|
134
136
|
const tz = extractFromHeaderNames(input.headers, names);
|
|
135
137
|
if (tz)
|
|
136
138
|
return tz;
|
|
137
|
-
const cookieTimezone = extractCookieHeader(input.headers,
|
|
139
|
+
const cookieTimezone = extractCookieHeader(input.headers, cookieName);
|
|
138
140
|
if (cookieTimezone)
|
|
139
141
|
return cookieTimezone;
|
|
140
142
|
}
|
|
@@ -142,11 +144,11 @@ export async function getTimezone(input, fallback, generate, headerNames) {
|
|
|
142
144
|
const tz = extractFromHeaderNames(input, names);
|
|
143
145
|
if (tz)
|
|
144
146
|
return tz;
|
|
145
|
-
const cookieTimezone = extractCookieHeader(input,
|
|
147
|
+
const cookieTimezone = extractCookieHeader(input, cookieName);
|
|
146
148
|
if (cookieTimezone)
|
|
147
149
|
return cookieTimezone;
|
|
148
150
|
}
|
|
149
|
-
const cookieTimezone = extractCookie(input.cookies,
|
|
151
|
+
const cookieTimezone = extractCookie(input.cookies, cookieName);
|
|
150
152
|
if (cookieTimezone) {
|
|
151
153
|
return cookieTimezone;
|
|
152
154
|
}
|
|
@@ -161,7 +163,7 @@ export async function getTimezone(input, fallback, generate, headerNames) {
|
|
|
161
163
|
const tz = extractFromHeaderNames(h, names);
|
|
162
164
|
if (tz)
|
|
163
165
|
return tz;
|
|
164
|
-
const cookieTimezone = extractCookieHeader(h,
|
|
166
|
+
const cookieTimezone = extractCookieHeader(h, cookieName);
|
|
165
167
|
if (cookieTimezone)
|
|
166
168
|
return cookieTimezone;
|
|
167
169
|
}
|
|
@@ -170,7 +172,7 @@ export async function getTimezone(input, fallback, generate, headerNames) {
|
|
|
170
172
|
try {
|
|
171
173
|
const { cookies } = await import('next/headers.js');
|
|
172
174
|
const c = await cookies();
|
|
173
|
-
const tz = extractCookie(c,
|
|
175
|
+
const tz = extractCookie(c, cookieName);
|
|
174
176
|
if (tz)
|
|
175
177
|
return tz;
|
|
176
178
|
}
|