cloudflare-next-intl 0.9.54 → 0.9.56
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/dist/src/client/components/client_provider.js +6 -3
- package/dist/src/client/components/client_provider_static.js +4 -2
- package/dist/src/client/components/use_lazy_wrapping_provider.d.ts +12 -0
- package/dist/src/client/components/use_lazy_wrapping_provider.js +34 -0
- package/dist/src/firebase_auth/server/mint_server_app_check_token.d.ts +3 -0
- package/dist/src/firebase_auth/server/mint_server_app_check_token.js +28 -3
- package/dist/src/server/components/helper_script.js +67 -18
- package/dist/src/types/types.d.ts +1 -0
- package/package.json +1 -1
|
@@ -3,13 +3,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { setLocaleCache, setMessageForLocaleCache } from "../../general/cache_variables.js";
|
|
4
4
|
import { createContext, useMemo } from "react";
|
|
5
5
|
import dynamic from "next/dynamic.js";
|
|
6
|
+
import useLazyWrappingProvider from "./use_lazy_wrapping_provider.js";
|
|
6
7
|
import config from "@intl-config";
|
|
7
8
|
import installConsoleErrorOverride from "../../error_handling/install_console_error_override.js";
|
|
8
9
|
import installGlobalErrorOverride from "../../error_handling/install_global_error_override.js";
|
|
9
10
|
export const LocaleContext = createContext(undefined);
|
|
10
|
-
const
|
|
11
|
+
const loadAuthUserProvider = () => import("../../firebase_auth/client/auth_user_provider.js");
|
|
11
12
|
const AutoFirebasePerformanceEvents = dynamic(() => import("../../firebase_auth/client/components/auto_firebase_performance_events.js"));
|
|
12
|
-
const
|
|
13
|
+
const loadCookieConsentProvider = () => import("../../cookie_consent/client/cookie_consent_provider.js");
|
|
13
14
|
const CookieConsentAnalytics = dynamic(() => import("../../cookie_consent/client/components/cookie_consent_analytics.js"));
|
|
14
15
|
const AutoAnalyticsEvents = dynamic(() => import("../../cookie_consent/client/components/auto_analytics_events.js"));
|
|
15
16
|
const CookieConsentDialog = dynamic(() => import("../../cookie_consent/client/components/cookie_consent_dialog.js"));
|
|
@@ -19,12 +20,14 @@ export default function LocationzationClientProvider({ language, messages, initi
|
|
|
19
20
|
setMessageForLocaleCache(language, messages);
|
|
20
21
|
installConsoleErrorOverride(config, true);
|
|
21
22
|
installGlobalErrorOverride(config);
|
|
23
|
+
const { Provider: AuthUserProvider } = useLazyWrappingProvider(loadAuthUserProvider);
|
|
24
|
+
const { Provider: CookieConsentProvider, isReady: cookieConsentReady } = useLazyWrappingProvider(loadCookieConsentProvider);
|
|
22
25
|
let providedChildren = children;
|
|
23
26
|
if (config.firebaseAuth && !skipAuthProvider) {
|
|
24
27
|
providedChildren = _jsxs(AuthUserProvider, { initialUser: initialAuthUser, children: [children, config.firebaseAuth.performance !== false && _jsx(AutoFirebasePerformanceEvents, {})] });
|
|
25
28
|
}
|
|
26
29
|
if (config.cookieConsent) {
|
|
27
|
-
providedChildren = _jsxs(CookieConsentProvider, { requiresConsent: requiresConsent, children: [providedChildren, analyticsConfig && _jsx(CookieConsentAnalytics, { config: analyticsConfig }), analyticsConfig && (analyticsConfig.googleAnalyticsId || analyticsConfig.googleAdsId) && _jsx(AutoAnalyticsEvents, { config: autoAnalyticsEventsConfig }), autoWireDialogs && _jsx(CookieConsentDialog, { ...dialogProps }), autoWireDialogs && _jsx(PrivacyPolicyUpdateDialog, { ...updateDialogProps })] });
|
|
30
|
+
providedChildren = _jsxs(CookieConsentProvider, { requiresConsent: requiresConsent, children: [providedChildren, cookieConsentReady && analyticsConfig && _jsx(CookieConsentAnalytics, { config: analyticsConfig }), cookieConsentReady && analyticsConfig && (analyticsConfig.googleAnalyticsId || analyticsConfig.googleAdsId) && _jsx(AutoAnalyticsEvents, { config: autoAnalyticsEventsConfig }), cookieConsentReady && autoWireDialogs && _jsx(CookieConsentDialog, { ...dialogProps }), cookieConsentReady && autoWireDialogs && _jsx(PrivacyPolicyUpdateDialog, { ...updateDialogProps })] });
|
|
28
31
|
}
|
|
29
32
|
const contextValue = useMemo(() => ({ language, messages }), [language, messages]);
|
|
30
33
|
return _jsx(LocaleContext.Provider, { value: contextValue, children: providedChildren });
|
|
@@ -3,11 +3,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { setLocaleCache, setMessageForLocaleCache } from "../../general/cache_variables.js";
|
|
4
4
|
import { createContext, useMemo } from "react";
|
|
5
5
|
import dynamic from "next/dynamic.js";
|
|
6
|
+
import useLazyWrappingProvider from "./use_lazy_wrapping_provider.js";
|
|
6
7
|
import config from "@intl-config";
|
|
7
8
|
import installConsoleErrorOverride from "../../error_handling/install_console_error_override.js";
|
|
8
9
|
import installGlobalErrorOverride from "../../error_handling/install_global_error_override.js";
|
|
9
10
|
export const LocaleContext = createContext(undefined);
|
|
10
|
-
const
|
|
11
|
+
const loadCookieConsentProvider = () => import("../../cookie_consent/client/cookie_consent_provider.js");
|
|
11
12
|
const CookieConsentAnalytics = dynamic(() => import("../../cookie_consent/client/components/cookie_consent_analytics.js"));
|
|
12
13
|
const AutoAnalyticsEvents = dynamic(() => import("../../cookie_consent/client/components/auto_analytics_events.js"));
|
|
13
14
|
const CookieConsentDialog = dynamic(() => import("../../cookie_consent/client/components/cookie_consent_dialog.js"));
|
|
@@ -17,9 +18,10 @@ export default function LocationzationClientProvider({ language, messages, analy
|
|
|
17
18
|
setMessageForLocaleCache(language, messages);
|
|
18
19
|
installConsoleErrorOverride(config, true);
|
|
19
20
|
installGlobalErrorOverride(config);
|
|
21
|
+
const { Provider: CookieConsentProvider, isReady: cookieConsentReady } = useLazyWrappingProvider(loadCookieConsentProvider);
|
|
20
22
|
let providedChildren = children;
|
|
21
23
|
if (config.cookieConsent) {
|
|
22
|
-
providedChildren = _jsxs(CookieConsentProvider, { requiresConsent: requiresConsent, children: [providedChildren, analyticsConfig && _jsx(CookieConsentAnalytics, { config: analyticsConfig }), analyticsConfig && (analyticsConfig.googleAnalyticsId || analyticsConfig.googleAdsId) && _jsx(AutoAnalyticsEvents, { config: autoAnalyticsEventsConfig }), autoWireDialogs && _jsx(CookieConsentDialog, { ...dialogProps }), autoWireDialogs && _jsx(PrivacyPolicyUpdateDialog, { ...updateDialogProps })] });
|
|
24
|
+
providedChildren = _jsxs(CookieConsentProvider, { requiresConsent: requiresConsent, children: [providedChildren, cookieConsentReady && analyticsConfig && _jsx(CookieConsentAnalytics, { config: analyticsConfig }), cookieConsentReady && analyticsConfig && (analyticsConfig.googleAnalyticsId || analyticsConfig.googleAdsId) && _jsx(AutoAnalyticsEvents, { config: autoAnalyticsEventsConfig }), cookieConsentReady && autoWireDialogs && _jsx(CookieConsentDialog, { ...dialogProps }), cookieConsentReady && autoWireDialogs && _jsx(PrivacyPolicyUpdateDialog, { ...updateDialogProps })] });
|
|
23
25
|
}
|
|
24
26
|
const contextValue = useMemo(() => ({ language, messages }), [language, messages]);
|
|
25
27
|
return _jsx(LocaleContext.Provider, { value: contextValue, children: providedChildren });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ComponentType } from "react";
|
|
2
|
+
type ModuleLoader<P> = () => Promise<{
|
|
3
|
+
default: ComponentType<P>;
|
|
4
|
+
}>;
|
|
5
|
+
export interface LazyWrappingProviderResult<P extends Record<string, unknown>> {
|
|
6
|
+
Provider: ComponentType<P & {
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
}>;
|
|
9
|
+
isReady: boolean;
|
|
10
|
+
}
|
|
11
|
+
export default function useLazyWrappingProvider<P extends Record<string, unknown>>(loader: ModuleLoader<P>): LazyWrappingProviderResult<P>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
const settledCache = new Map();
|
|
5
|
+
export default function useLazyWrappingProvider(loader) {
|
|
6
|
+
const opaqueLoader = loader;
|
|
7
|
+
const resolvedRef = useRef(settledCache.get(opaqueLoader) ?? null);
|
|
8
|
+
const [isReady, setIsReady] = useState(resolvedRef.current !== null);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (resolvedRef.current)
|
|
11
|
+
return;
|
|
12
|
+
let cancelled = false;
|
|
13
|
+
loader().then((mod) => {
|
|
14
|
+
if (cancelled)
|
|
15
|
+
return;
|
|
16
|
+
settledCache.set(opaqueLoader, mod.default);
|
|
17
|
+
resolvedRef.current = mod.default;
|
|
18
|
+
setIsReady(true);
|
|
19
|
+
});
|
|
20
|
+
return () => {
|
|
21
|
+
cancelled = true;
|
|
22
|
+
};
|
|
23
|
+
}, []);
|
|
24
|
+
const wrapperRef = useRef(null);
|
|
25
|
+
if (!wrapperRef.current) {
|
|
26
|
+
wrapperRef.current = function LazyWrappingProvider({ children, ...props }) {
|
|
27
|
+
const Resolved = resolvedRef.current;
|
|
28
|
+
if (!Resolved)
|
|
29
|
+
return children;
|
|
30
|
+
return _jsx(Resolved, { ...props, children: children });
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return { Provider: wrapperRef.current, isReady };
|
|
34
|
+
}
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
import type { FirebaseAppCheckConfig } from '../../types/types.js';
|
|
2
|
+
export declare const missingCredentialsReportState: {
|
|
3
|
+
reported: boolean;
|
|
4
|
+
};
|
|
2
5
|
export default function mintServerAppCheckToken(projectId: string, apiKey: string, appCheck: FirebaseAppCheckConfig | undefined): Promise<string | undefined>;
|
|
@@ -3,12 +3,37 @@ import reportError from '../../error_handling/report_error.js';
|
|
|
3
3
|
import signCustomTokenRemote from './sign_custom_token_remote.js';
|
|
4
4
|
const APP_CHECK_CUSTOM_TOKEN_AUDIENCE = 'https://firebaseappcheck.googleapis.com/google.firebase.appcheck.v1.TokenExchangeService';
|
|
5
5
|
const CUSTOM_TOKEN_LIFETIME = '5m';
|
|
6
|
+
export const missingCredentialsReportState = { reported: false };
|
|
7
|
+
async function reportMissingCredentials(appCheck, hasOauthTriple) {
|
|
8
|
+
if (appCheck.reportMissingServerCredentials === false)
|
|
9
|
+
return;
|
|
10
|
+
if (missingCredentialsReportState.reported)
|
|
11
|
+
return;
|
|
12
|
+
missingCredentialsReportState.reported = true;
|
|
13
|
+
const missing = [];
|
|
14
|
+
if (!appCheck.clientEmail)
|
|
15
|
+
missing.push('clientEmail');
|
|
16
|
+
if (!appCheck.appId)
|
|
17
|
+
missing.push('appId');
|
|
18
|
+
if (!appCheck.privateKey && !hasOauthTriple) {
|
|
19
|
+
missing.push('privateKey (or the full oauthClientId/oauthClientSecret/oauthRefreshToken triple)');
|
|
20
|
+
}
|
|
21
|
+
await reportError(config, {
|
|
22
|
+
error: new Error(`firebaseAuth.appCheck is configured but cannot mint an App Check token server-side — missing: ${missing.join(', ')}. `
|
|
23
|
+
+ 'Signed-in users will render as signed-out on any cold navigation that arrives before the client writes the App Check cookie. '
|
|
24
|
+
+ 'Set the missing service-account values, or pass `appCheck.reportMissingServerCredentials: false` to silence this.'),
|
|
25
|
+
classOrMethodName: 'mintServerAppCheckToken',
|
|
26
|
+
dedupKey: 'mintServerAppCheckToken:missing-server-credentials',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
6
29
|
export default async function mintServerAppCheckToken(projectId, apiKey, appCheck) {
|
|
7
|
-
if (!appCheck
|
|
30
|
+
if (!appCheck)
|
|
8
31
|
return undefined;
|
|
9
|
-
const hasOauthTriple = appCheck.oauthClientId && appCheck.oauthClientSecret && appCheck.oauthRefreshToken;
|
|
10
|
-
if (!appCheck.privateKey && !hasOauthTriple)
|
|
32
|
+
const hasOauthTriple = Boolean(appCheck.oauthClientId && appCheck.oauthClientSecret && appCheck.oauthRefreshToken);
|
|
33
|
+
if (!appCheck.clientEmail || !appCheck.appId || (!appCheck.privateKey && !hasOauthTriple)) {
|
|
34
|
+
await reportMissingCredentials(appCheck, hasOauthTriple);
|
|
11
35
|
return undefined;
|
|
36
|
+
}
|
|
12
37
|
try {
|
|
13
38
|
const claims = {
|
|
14
39
|
iss: appCheck.clientEmail,
|
|
@@ -19,9 +19,16 @@ export default function HelperScript() {
|
|
|
19
19
|
var key = 'stale-deploy-recovery-reloaded';
|
|
20
20
|
var timeKey = 'stale-deploy-recovery-time';
|
|
21
21
|
var countKey = 'stale-deploy-recovery-count';
|
|
22
|
-
var maxAttempts =
|
|
22
|
+
var maxAttempts = 3;
|
|
23
23
|
var throttleMs = 15000;
|
|
24
24
|
var attemptedThisLoad = false;
|
|
25
|
+
var retryScheduled = false;
|
|
26
|
+
// Set by the resource-error listener: the first same-origin
|
|
27
|
+
// chunk that failed. Reloading is pointless until that URL
|
|
28
|
+
// answers with real JavaScript again, so it doubles as the
|
|
29
|
+
// health probe below.
|
|
30
|
+
var probeUrl = null;
|
|
31
|
+
var maxProbes = 4;
|
|
25
32
|
function isStale(msg) {
|
|
26
33
|
if (msg === undefined || msg === null) return true;
|
|
27
34
|
msg = String(msg).toLowerCase();
|
|
@@ -30,6 +37,49 @@ export default function HelperScript() {
|
|
|
30
37
|
}
|
|
31
38
|
return false;
|
|
32
39
|
}
|
|
40
|
+
function showOverlay() {
|
|
41
|
+
try {
|
|
42
|
+
if (document.documentElement) {
|
|
43
|
+
document.documentElement.style.backgroundColor = '#ffffff';
|
|
44
|
+
}
|
|
45
|
+
if (document.body) {
|
|
46
|
+
document.body.style.backgroundColor = '#ffffff';
|
|
47
|
+
document.body.innerHTML = ${JSON.stringify(reloadHtml)};
|
|
48
|
+
}
|
|
49
|
+
} catch (e) {}
|
|
50
|
+
}
|
|
51
|
+
function doReload() {
|
|
52
|
+
try {
|
|
53
|
+
var u = new URL(window.location.href);
|
|
54
|
+
u.searchParams.set('_stale_reload', String(Date.now()));
|
|
55
|
+
window.location.replace(u.toString());
|
|
56
|
+
} catch (e) {
|
|
57
|
+
try { window.location.reload(); } catch (e2) {}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// A deploy swaps the Worker version colo by colo, so for a few
|
|
61
|
+
// seconds the document can come from the new version while a
|
|
62
|
+
// chunk request still lands on the old one, which answers with
|
|
63
|
+
// a plain-text 404 body instead of JavaScript. Reloading inside
|
|
64
|
+
// that window just reproduces the error, so poll the failed
|
|
65
|
+
// chunk with a cache-busted request until it is real
|
|
66
|
+
// JavaScript, then reload once. Give up after maxProbes and
|
|
67
|
+
// reload anyway rather than hanging on the overlay.
|
|
68
|
+
function probeThenReload(attempt) {
|
|
69
|
+
if (!probeUrl || typeof fetch !== 'function') return doReload();
|
|
70
|
+
var url = probeUrl + (probeUrl.indexOf('?') > -1 ? '&' : '?') + '_r=' + Date.now();
|
|
71
|
+
fetch(url, { cache: 'reload', credentials: 'omit' }).then(function(r) {
|
|
72
|
+
var ct = (r.headers.get('content-type') || '').toLowerCase();
|
|
73
|
+
if (!r.ok || ct.indexOf('javascript') === -1) throw new Error('unhealthy: ' + r.status + ' ' + ct);
|
|
74
|
+
doReload();
|
|
75
|
+
}).catch(function(err) {
|
|
76
|
+
if (attempt >= maxProbes) {
|
|
77
|
+
console.warn('[StaleDeploy early-catch] Asset still unhealthy after', attempt + 1, 'probes - reloading anyway:', String(err));
|
|
78
|
+
return doReload();
|
|
79
|
+
}
|
|
80
|
+
setTimeout(function() { probeThenReload(attempt + 1); }, 500 * Math.pow(2, attempt));
|
|
81
|
+
});
|
|
82
|
+
}
|
|
33
83
|
function recover(msg, source) {
|
|
34
84
|
if (attemptedThisLoad) return;
|
|
35
85
|
try {
|
|
@@ -55,30 +105,28 @@ export default function HelperScript() {
|
|
|
55
105
|
console.warn('[StaleDeploy early-catch] Skipping reload, attempts exhausted for buildId:', buildId, attempts);
|
|
56
106
|
return;
|
|
57
107
|
}
|
|
108
|
+
// A reload that lands inside the same throttle window
|
|
109
|
+
// means the previous recovery did not help: the assets
|
|
110
|
+
// are momentarily unreadable at the edge rather than
|
|
111
|
+
// stale. Waiting out the window and retrying lets the
|
|
112
|
+
// page heal itself instead of stranding the visitor on
|
|
113
|
+
// the error UI.
|
|
58
114
|
if (sameBuild && throttled) {
|
|
59
|
-
|
|
115
|
+
if (retryScheduled) return;
|
|
116
|
+
retryScheduled = true;
|
|
117
|
+
var wait = throttleMs - (Date.now() - last);
|
|
118
|
+
if (!(wait > 0)) wait = 0;
|
|
119
|
+
console.warn('[StaleDeploy early-catch] Throttled for buildId:', buildId, '- retrying in', wait, 'ms');
|
|
120
|
+
showOverlay();
|
|
121
|
+
setTimeout(function() { retryScheduled = false; recover(msg, source); }, wait + 250);
|
|
60
122
|
return;
|
|
61
123
|
}
|
|
62
124
|
attemptedThisLoad = true;
|
|
63
125
|
sessionStorage.setItem(key, buildId);
|
|
64
126
|
sessionStorage.setItem(countKey, String(attempts + 1));
|
|
65
127
|
sessionStorage.setItem(timeKey, String(Date.now()));
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
document.documentElement.style.backgroundColor = '#ffffff';
|
|
69
|
-
}
|
|
70
|
-
if (document.body) {
|
|
71
|
-
document.body.style.backgroundColor = '#ffffff';
|
|
72
|
-
document.body.innerHTML = ${JSON.stringify(reloadHtml)};
|
|
73
|
-
}
|
|
74
|
-
} catch (e) {}
|
|
75
|
-
try {
|
|
76
|
-
var u = new URL(window.location.href);
|
|
77
|
-
u.searchParams.set('_stale_reload', String(Date.now()));
|
|
78
|
-
window.location.replace(u.toString());
|
|
79
|
-
} catch (e) {
|
|
80
|
-
window.location.reload();
|
|
81
|
-
}
|
|
128
|
+
showOverlay();
|
|
129
|
+
probeThenReload(0);
|
|
82
130
|
} catch (e) {
|
|
83
131
|
console.error('Stale Deploy Early Catch Script Error:', e);
|
|
84
132
|
}
|
|
@@ -102,6 +150,7 @@ export default function HelperScript() {
|
|
|
102
150
|
var sameOrigin = false;
|
|
103
151
|
try { sameOrigin = new URL(src, window.location.href).origin === window.location.origin; } catch (err2) { return; }
|
|
104
152
|
if (!sameOrigin) return;
|
|
153
|
+
if (!probeUrl) probeUrl = src;
|
|
105
154
|
recover('chunk resource failed to load: ' + src, 'resource-error');
|
|
106
155
|
} catch (err) {}
|
|
107
156
|
}, true);
|