cloudflare-next-intl 0.7.2 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/src/firebase_auth/client/auth_actions.d.ts +4 -4
- package/dist/src/firebase_auth/client/auth_actions.js +4 -4
- package/dist/src/firebase_auth/client/auth_user_provider.d.ts +2 -2
- package/dist/src/firebase_auth/client/auth_user_provider.js +2 -2
- package/dist/src/firebase_auth/middleware/update_session.js +31 -1
- package/dist/src/firebase_auth/types.d.ts +15 -0
- package/dist/src/types/types.d.ts +6 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -247,12 +247,23 @@ export async function generateMetadata({ params }) {
|
|
|
247
247
|
|
|
248
248
|
### Theme switcher
|
|
249
249
|
|
|
250
|
+
### Firebase Auth
|
|
251
|
+
|
|
252
|
+
Set `firebaseAuth` on your `RoutingConfig` to enable — `IntlProvider` then
|
|
253
|
+
auto-wires `AuthUserProvider` and server-side `getAuthUser` session validation.
|
|
254
|
+
|
|
255
|
+
Features include:
|
|
256
|
+
- `createForgotPasswordAction(locale, actionCodeSettings?)`: Accepts optional Firebase `AuthActionCodeSettings` (e.g. `url` redirect link).
|
|
257
|
+
- `sendVerificationEmail(actionCodeSettings?)` on `useAuthUser()`: Custom action email settings when resending email verification.
|
|
258
|
+
- `followSameOriginContinueUrl`: Automatically forwards emailed action links with `continueUrl` to the specified path (or external URL) directly from `intlMiddleware` (default `true`; set `false` on `firebaseAuth` config to disable).
|
|
259
|
+
|
|
250
260
|
```tsx
|
|
251
261
|
import ThemeSwitcher from "cloudflare-next-intl/ThemeSwitcher";
|
|
252
262
|
|
|
253
263
|
<ThemeSwitcher lightLabelText="Light" darkLabelText="Dark" />
|
|
254
264
|
```
|
|
255
265
|
|
|
266
|
+
|
|
256
267
|
### Cookie consent
|
|
257
268
|
|
|
258
269
|
Set `cookieConsent` on your `RoutingConfig` to enable — `IntlProvider` then
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AuthActionMessages, AuthFormState } from '../types';
|
|
1
|
+
import type { AuthActionCodeSettings, AuthActionMessages, AuthFormState } from '../types';
|
|
2
2
|
/**
|
|
3
3
|
* Builds a login server action for React's `useActionState` form hook.
|
|
4
4
|
* The returned function has the `(prevState, formData) => Promise<AuthFormState>`
|
|
@@ -37,10 +37,10 @@ export declare function createSignUpAction(locale: string, messages: AuthActionM
|
|
|
37
37
|
* `formData` must contain an `email` field.
|
|
38
38
|
*
|
|
39
39
|
* @param locale Used to localize the returned error message.
|
|
40
|
-
* @param
|
|
40
|
+
* @param actionCodeSettings Optional settings for action email (continue URL, etc.).
|
|
41
41
|
* @returns A form action: `{ success: true }` on success, `{ error }` on failure.
|
|
42
42
|
* @example
|
|
43
|
-
* const [state, action] = useActionState(createForgotPasswordAction(locale
|
|
43
|
+
* const [state, action] = useActionState(createForgotPasswordAction(locale), {});
|
|
44
44
|
* <form action={action}>...</form>
|
|
45
45
|
*/
|
|
46
|
-
export declare function createForgotPasswordAction(locale: string,
|
|
46
|
+
export declare function createForgotPasswordAction(locale: string, actionCodeSettings?: AuthActionCodeSettings): (_prevState: AuthFormState, formData: FormData) => Promise<AuthFormState>;
|
|
@@ -79,20 +79,20 @@ export function createSignUpAction(locale, messages) {
|
|
|
79
79
|
* `formData` must contain an `email` field.
|
|
80
80
|
*
|
|
81
81
|
* @param locale Used to localize the returned error message.
|
|
82
|
-
* @param
|
|
82
|
+
* @param actionCodeSettings Optional settings for action email (continue URL, etc.).
|
|
83
83
|
* @returns A form action: `{ success: true }` on success, `{ error }` on failure.
|
|
84
84
|
* @example
|
|
85
|
-
* const [state, action] = useActionState(createForgotPasswordAction(locale
|
|
85
|
+
* const [state, action] = useActionState(createForgotPasswordAction(locale), {});
|
|
86
86
|
* <form action={action}>...</form>
|
|
87
87
|
*/
|
|
88
|
-
export function createForgotPasswordAction(locale,
|
|
88
|
+
export function createForgotPasswordAction(locale, actionCodeSettings) {
|
|
89
89
|
return async function forgotPasswordAction(_prevState, formData) {
|
|
90
90
|
requireFirebaseAuthConfig(config.firebaseAuth);
|
|
91
91
|
const { auth } = await getFirebaseAuthClient();
|
|
92
92
|
const { sendPasswordResetEmail } = await getFirebaseAuthModule();
|
|
93
93
|
const email = (formData.get('email')?.toString() ?? '').trim();
|
|
94
94
|
try {
|
|
95
|
-
await sendPasswordResetEmail(auth, email);
|
|
95
|
+
await sendPasswordResetEmail(auth, email, actionCodeSettings);
|
|
96
96
|
return { success: true };
|
|
97
97
|
}
|
|
98
98
|
catch (e) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AuthUser, SerializedAuthUser } from '../types';
|
|
1
|
+
import type { AuthActionCodeSettings, AuthUser, SerializedAuthUser } from '../types';
|
|
2
2
|
export interface AuthUserContextType {
|
|
3
3
|
/** Current Firebase user, or `null` if signed out (or not yet resolved while `loading`). */
|
|
4
4
|
user: AuthUser | null;
|
|
@@ -7,7 +7,7 @@ export interface AuthUserContextType {
|
|
|
7
7
|
/** Force-refreshes the current user's ID token/claims and re-syncs the session cookie. */
|
|
8
8
|
reloadUser: () => Promise<void>;
|
|
9
9
|
/** Sends a verification email to the currently signed-in user. */
|
|
10
|
-
sendVerificationEmail: () => Promise<void>;
|
|
10
|
+
sendVerificationEmail: (actionCodeSettings?: AuthActionCodeSettings) => Promise<void>;
|
|
11
11
|
/** Signs out, clears the session cookie, and redirects to `firebaseAuth.redirectAuthPath`. */
|
|
12
12
|
logout: () => Promise<void>;
|
|
13
13
|
}
|
|
@@ -311,13 +311,13 @@ export default function AuthUserProvider({ initialUser = null, children }) {
|
|
|
311
311
|
console.error('AuthUserProvider: reloadUser failed', e);
|
|
312
312
|
}
|
|
313
313
|
}, []);
|
|
314
|
-
const sendVerificationEmail = useCallback(async () => {
|
|
314
|
+
const sendVerificationEmail = useCallback(async (actionCodeSettings) => {
|
|
315
315
|
const { auth } = await getFirebaseAuthClient();
|
|
316
316
|
const user = auth.currentUser;
|
|
317
317
|
if (!user)
|
|
318
318
|
return;
|
|
319
319
|
const { sendEmailVerification } = await getFirebaseAuthModule();
|
|
320
|
-
await sendEmailVerification(user);
|
|
320
|
+
await sendEmailVerification(user, actionCodeSettings);
|
|
321
321
|
}, []);
|
|
322
322
|
const logout = useCallback(async () => {
|
|
323
323
|
try {
|
|
@@ -240,7 +240,37 @@ export default async function updateSession(request, baseResponse, locale, rebui
|
|
|
240
240
|
if (fa.actionLinkRedirectEnabled !== false && isEligibleActionPath) {
|
|
241
241
|
const mode = request.nextUrl.searchParams.get('mode');
|
|
242
242
|
if (mode) {
|
|
243
|
-
|
|
243
|
+
let target = resolveActionModePaths(fa)[mode];
|
|
244
|
+
if (fa.followSameOriginContinueUrl !== false) {
|
|
245
|
+
const continueUrl = request.nextUrl.searchParams.get('continueUrl');
|
|
246
|
+
if (continueUrl) {
|
|
247
|
+
try {
|
|
248
|
+
const parsed = new URL(continueUrl, request.url);
|
|
249
|
+
if (parsed.origin === request.nextUrl.origin) {
|
|
250
|
+
let continuePath = parsed.pathname;
|
|
251
|
+
if (locale !== config.defaultLocale) {
|
|
252
|
+
if (continuePath.startsWith(`/${locale}/`)) {
|
|
253
|
+
continuePath = continuePath.slice(locale.length + 1);
|
|
254
|
+
}
|
|
255
|
+
else if (continuePath === `/${locale}`) {
|
|
256
|
+
continuePath = '/';
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (continuePath !== '/') {
|
|
260
|
+
target = continuePath;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
// External continueUrl: redirect directly to the full external URL
|
|
265
|
+
parsed.search = request.nextUrl.search;
|
|
266
|
+
return buildRedirect(baseResponse, parsed);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
// Invalid continueUrl format — fall back to resolved mode target
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
244
274
|
// Skip when already on the destination — the forward sets the same
|
|
245
275
|
// `?mode=` it matched on, so redirecting again would loop forever.
|
|
246
276
|
if (target && target !== path) {
|
|
@@ -20,3 +20,18 @@ export interface AuthActionMessages {
|
|
|
20
20
|
mismatch?: string;
|
|
21
21
|
}
|
|
22
22
|
export type AuthUser = User | SerializedAuthUser;
|
|
23
|
+
/** Settings for configuring action code emails (password reset, email verification). */
|
|
24
|
+
export interface AuthActionCodeSettings {
|
|
25
|
+
url: string;
|
|
26
|
+
handleCodeInApp?: boolean;
|
|
27
|
+
iOS?: {
|
|
28
|
+
bundleId: string;
|
|
29
|
+
};
|
|
30
|
+
android?: {
|
|
31
|
+
packageName: string;
|
|
32
|
+
installApp?: boolean;
|
|
33
|
+
minimumVersion?: string;
|
|
34
|
+
};
|
|
35
|
+
dynamicLinkDomain?: string;
|
|
36
|
+
linkDomain?: string;
|
|
37
|
+
}
|
|
@@ -515,6 +515,12 @@ export interface FirebaseAuthRoutingConfig {
|
|
|
515
515
|
* Defaults to `true`.
|
|
516
516
|
*/
|
|
517
517
|
actionLinkRedirectEnabled?: boolean;
|
|
518
|
+
/**
|
|
519
|
+
* When `true` (the default), if an emailed-action-link carries a `continueUrl` query parameter
|
|
520
|
+
* matching the request's origin (same domain/app), the middleware will redirect to `continueUrl`'s
|
|
521
|
+
* path instead of the static mode path (e.g. `resetPasswordPath`). Set `false` to disable.
|
|
522
|
+
*/
|
|
523
|
+
followSameOriginContinueUrl?: boolean;
|
|
518
524
|
/**
|
|
519
525
|
* Restricts the emailed-action-link forward (see {@link resetPasswordPath})
|
|
520
526
|
* to this exact static path — set this to whatever path your Firebase
|
package/package.json
CHANGED