@main12/auth-login 0.3.8 → 0.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.
Files changed (29) hide show
  1. package/README.md +180 -4
  2. package/dist/components/AuthLayout.d.ts +9 -0
  3. package/dist/components/AuthPages.d.ts +15 -1
  4. package/dist/components/AuthPages.js +7 -1
  5. package/dist/components/AuthPagesServer.d.ts +6 -1
  6. package/dist/components/AuthPagesServer.js +11 -2
  7. package/dist/components/pages/ForgotPasswordPageHero.d.ts +1 -1
  8. package/dist/components/pages/ForgotPasswordPageHero.js +8 -6
  9. package/dist/components/pages/ForgotPasswordPageTailwind.d.ts +1 -1
  10. package/dist/components/pages/ForgotPasswordPageTailwind.js +12 -7
  11. package/dist/components/pages/LoginPageHero.js +18 -16
  12. package/dist/components/pages/LoginPageTailwind.js +18 -16
  13. package/dist/components/pages/SetPasswordPageHero.d.ts +1 -1
  14. package/dist/components/pages/SetPasswordPageHero.js +8 -6
  15. package/dist/components/pages/SetPasswordPageTailwind.d.ts +1 -1
  16. package/dist/components/pages/SetPasswordPageTailwind.js +9 -7
  17. package/dist/components/pages/SignupPageHero.d.ts +1 -1
  18. package/dist/components/pages/SignupPageHero.js +20 -14
  19. package/dist/components/pages/SignupPageTailwind.d.ts +1 -1
  20. package/dist/components/pages/SignupPageTailwind.js +17 -14
  21. package/dist/components/pages/VerifyOtpPageHero.js +9 -7
  22. package/dist/components/pages/VerifyOtpPageTailwind.js +13 -8
  23. package/dist/components/ui/locale.d.ts +29 -0
  24. package/dist/components/ui/locale.js +53 -0
  25. package/dist/components/ui/translations.d.ts +91 -0
  26. package/dist/components/ui/translations.js +179 -0
  27. package/dist/exports/client.d.ts +3 -0
  28. package/dist/exports/client.js +3 -0
  29. package/package.json +1 -1
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Zero-dependency locale detection.
3
+ *
4
+ * The plugin never imports next-intl, next-i18next, or any i18n library —
5
+ * instead it reads the same conventional signals those libraries already
6
+ * write, so `locale` "just works" automatically for consumers using them,
7
+ * while still defaulting sanely (`en`) for consumers with no i18n setup.
8
+ *
9
+ * Priority order:
10
+ * 1. Explicit `locale` prop passed to `<AuthPages />` (always wins, handled by caller)
11
+ * 2. `NEXT_LOCALE` cookie — written by next-intl, next-i18next, and most
12
+ * i18n routing middlewares by convention
13
+ * 3. `Accept-Language` request header (server-side only)
14
+ * 4. `<html lang="...">` attribute (client-side only)
15
+ * 5. Fallback: 'en'
16
+ */ const SUPPORTED_FALLBACK = 'en';
17
+ /** Extract the primary language code from a locale string, e.g. 'es-MX' -> 'es'. */ function normalize(locale) {
18
+ if (!locale) return undefined;
19
+ const primary = locale.split(/[-_]/)[0]?.toLowerCase();
20
+ return primary || undefined;
21
+ }
22
+ /** Parse the `NEXT_LOCALE` cookie value from a raw `Cookie` header string. */ function parseCookieLocale(cookieHeader) {
23
+ if (!cookieHeader) return undefined;
24
+ const match = cookieHeader.match(/(?:^|;\s*)NEXT_LOCALE=([^;]+)/);
25
+ return match ? normalize(decodeURIComponent(match[1])) : undefined;
26
+ }
27
+ /** Parse the first preferred language from an `Accept-Language` header. */ function parseAcceptLanguage(header) {
28
+ if (!header) return undefined;
29
+ const first = header.split(',')[0]?.trim();
30
+ return normalize(first);
31
+ }
32
+ /**
33
+ * Server-side locale detection — reads `Cookie` and `Accept-Language` headers.
34
+ * Use inside an RSC (e.g. `AuthPagesServer`) where `next/headers` is available.
35
+ */ export function detectServerLocale(headers) {
36
+ const fromCookie = parseCookieLocale(headers.get('cookie'));
37
+ if (fromCookie) return fromCookie;
38
+ const fromAcceptLanguage = parseAcceptLanguage(headers.get('accept-language'));
39
+ if (fromAcceptLanguage) return fromAcceptLanguage;
40
+ return SUPPORTED_FALLBACK;
41
+ }
42
+ /**
43
+ * Client-side locale detection — reads the `NEXT_LOCALE` cookie or falls back
44
+ * to `<html lang>`. Use inside client components when no explicit locale was
45
+ * passed down from the server.
46
+ */ export function detectClientLocale() {
47
+ if (typeof document === 'undefined') return SUPPORTED_FALLBACK;
48
+ const fromCookie = parseCookieLocale(document.cookie);
49
+ if (fromCookie) return fromCookie;
50
+ const fromHtmlLang = normalize(document.documentElement?.lang);
51
+ if (fromHtmlLang) return fromHtmlLang;
52
+ return SUPPORTED_FALLBACK;
53
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * UI copy for the auth pages (login, signup, forgot-password, verify-otp, set-password).
3
+ *
4
+ * Built-in support for English (`en`) and Spanish (`es`) out of the box — no
5
+ * configuration required. Consumers can override any subset of keys, and/or add
6
+ * entirely new locales, via the `messages` prop on `<AuthPages />` / individual
7
+ * page components. Missing keys always fall back to the built-in English copy.
8
+ */
9
+ export interface UiTranslations {
10
+ login: {
11
+ title: string;
12
+ subtitle: string;
13
+ passwordStepTitle: string;
14
+ passwordStepSubtitle: string;
15
+ otpPromptTitle: string;
16
+ otpPromptSubtitle: string;
17
+ continueWithGoogle: string;
18
+ or: string;
19
+ emailLabel: string;
20
+ passwordLabel: string;
21
+ continue: string;
22
+ forgotPassword: string;
23
+ edit: string;
24
+ verificationNotice: string;
25
+ sendCode: string;
26
+ sendingCode: string;
27
+ noAccount: string;
28
+ signUpLink: string;
29
+ };
30
+ signup: {
31
+ title: string;
32
+ subtitle: string;
33
+ fullNameLabel: string;
34
+ emailLabel: string;
35
+ continueWithGoogle: string;
36
+ or: string;
37
+ termsNotice: string;
38
+ termsLink: string;
39
+ andSeparator: string;
40
+ privacyLink: string;
41
+ createAccount: string;
42
+ haveAccount: string;
43
+ loginLink: string;
44
+ };
45
+ forgotPassword: {
46
+ title: string;
47
+ subtitle: string;
48
+ emailLabel: string;
49
+ sendResetCode: string;
50
+ backToLogin: string;
51
+ };
52
+ verifyOtp: {
53
+ title: string;
54
+ passwordResetTitle: string;
55
+ subtitle: string;
56
+ passwordResetSubtitle: string;
57
+ verify: string;
58
+ noCodeReceived: string;
59
+ resendCode: string;
60
+ resending: string;
61
+ resendIn: string;
62
+ backToLogin: string;
63
+ };
64
+ setPassword: {
65
+ title: string;
66
+ subtitle: string;
67
+ newPasswordLabel: string;
68
+ confirmPasswordLabel: string;
69
+ passwordRequirements: string;
70
+ setPassword: string;
71
+ };
72
+ }
73
+ /** Deep partial — every field at every level is optional, for override objects. */
74
+ export type DeepPartial<T> = {
75
+ [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
76
+ };
77
+ /** Built-in dictionaries. Consumers can add more locales via the `messages` prop. */
78
+ export declare const uiTranslations: Record<string, UiTranslations>;
79
+ /**
80
+ * Resolve the final UI translations for a given locale, applying any consumer
81
+ * overrides on top of the built-in dictionaries.
82
+ *
83
+ * Resolution order per key: `messages[locale]` → `messages.en` → built-in
84
+ * `[locale]` → built-in `en`. Consumers may pass a partial override object —
85
+ * any key they don't specify falls back automatically.
86
+ *
87
+ * @param locale - Target locale, e.g. 'en', 'es', or any custom locale defined in `messages`.
88
+ * @param messages - Optional map of locale -> partial translation overrides. Can also
89
+ * introduce brand-new locales not built into the plugin.
90
+ */
91
+ export declare function getUiTranslations(locale?: string, messages?: Record<string, DeepPartial<UiTranslations>>): UiTranslations;
@@ -0,0 +1,179 @@
1
+ /**
2
+ * UI copy for the auth pages (login, signup, forgot-password, verify-otp, set-password).
3
+ *
4
+ * Built-in support for English (`en`) and Spanish (`es`) out of the box — no
5
+ * configuration required. Consumers can override any subset of keys, and/or add
6
+ * entirely new locales, via the `messages` prop on `<AuthPages />` / individual
7
+ * page components. Missing keys always fall back to the built-in English copy.
8
+ */ const en = {
9
+ login: {
10
+ title: 'Welcome Back',
11
+ subtitle: 'Sign in with your email to continue.',
12
+ passwordStepTitle: 'Enter Password',
13
+ passwordStepSubtitle: 'Enter your password to sign in.',
14
+ otpPromptTitle: 'Verify Identity',
15
+ otpPromptSubtitle: "We need to verify it's you.",
16
+ continueWithGoogle: 'Continue with Google',
17
+ or: 'or',
18
+ emailLabel: 'Email',
19
+ passwordLabel: 'Password',
20
+ continue: 'Continue',
21
+ forgotPassword: 'Forgot password?',
22
+ edit: 'Edit',
23
+ verificationNotice: "We'll send a verification code to this email.",
24
+ sendCode: 'Send Code',
25
+ sendingCode: 'Sending...',
26
+ noAccount: "Don't have an account?",
27
+ signUpLink: 'Sign up'
28
+ },
29
+ signup: {
30
+ title: 'Create Account',
31
+ subtitle: 'Enter your details to get started',
32
+ fullNameLabel: 'Full Name',
33
+ emailLabel: 'Email',
34
+ continueWithGoogle: 'Continue with Google',
35
+ or: 'or',
36
+ termsNotice: 'By signing up, you agree to our',
37
+ termsLink: 'Terms of Service',
38
+ andSeparator: 'and',
39
+ privacyLink: 'Privacy Policy',
40
+ createAccount: 'Create Account',
41
+ haveAccount: 'Already have an account?',
42
+ loginLink: 'Login'
43
+ },
44
+ forgotPassword: {
45
+ title: 'Forgot Password',
46
+ subtitle: "Enter your email and we'll send you a reset code",
47
+ emailLabel: 'Email',
48
+ sendResetCode: 'Send Reset Code',
49
+ backToLogin: 'Back to Login'
50
+ },
51
+ verifyOtp: {
52
+ title: 'Check Your Email',
53
+ passwordResetTitle: 'Reset Password',
54
+ subtitle: 'We sent a 6-digit code to',
55
+ passwordResetSubtitle: 'Enter the code to reset your password',
56
+ verify: 'Verify',
57
+ noCodeReceived: "Didn't receive a code?",
58
+ resendCode: 'Resend Code',
59
+ resending: 'Sending...',
60
+ resendIn: 'Resend in {seconds}s',
61
+ backToLogin: 'Back to Login'
62
+ },
63
+ setPassword: {
64
+ title: 'Set Your Password',
65
+ subtitle: 'Create a secure password for your account',
66
+ newPasswordLabel: 'New Password',
67
+ confirmPasswordLabel: 'Confirm Password',
68
+ passwordRequirements: 'At least 8 chars with 3 of: uppercase, lowercase, number, special character',
69
+ setPassword: 'Set Password'
70
+ }
71
+ };
72
+ const es = {
73
+ login: {
74
+ title: 'Bienvenido de Nuevo',
75
+ subtitle: 'Inicia sesión con tu correo para continuar.',
76
+ passwordStepTitle: 'Ingresa tu Contraseña',
77
+ passwordStepSubtitle: 'Ingresa tu contraseña para iniciar sesión.',
78
+ otpPromptTitle: 'Verificar Identidad',
79
+ otpPromptSubtitle: 'Necesitamos verificar que eres tú.',
80
+ continueWithGoogle: 'Continuar con Google',
81
+ or: 'o',
82
+ emailLabel: 'Correo electrónico',
83
+ passwordLabel: 'Contraseña',
84
+ continue: 'Continuar',
85
+ forgotPassword: '¿Olvidaste tu contraseña?',
86
+ edit: 'Editar',
87
+ verificationNotice: 'Enviaremos un código de verificación a este correo.',
88
+ sendCode: 'Enviar Código',
89
+ sendingCode: 'Enviando...',
90
+ noAccount: '¿No tienes una cuenta?',
91
+ signUpLink: 'Regístrate'
92
+ },
93
+ signup: {
94
+ title: 'Crear Cuenta',
95
+ subtitle: 'Ingresa tus datos para comenzar',
96
+ fullNameLabel: 'Nombre Completo',
97
+ emailLabel: 'Correo electrónico',
98
+ continueWithGoogle: 'Continuar con Google',
99
+ or: 'o',
100
+ termsNotice: 'Al registrarte, aceptas nuestros',
101
+ termsLink: 'Términos de Servicio',
102
+ andSeparator: 'y',
103
+ privacyLink: 'Política de Privacidad',
104
+ createAccount: 'Crear Cuenta',
105
+ haveAccount: '¿Ya tienes una cuenta?',
106
+ loginLink: 'Inicia sesión'
107
+ },
108
+ forgotPassword: {
109
+ title: 'Recuperar Contraseña',
110
+ subtitle: 'Ingresa tu correo y te enviaremos un código para restablecerla',
111
+ emailLabel: 'Correo electrónico',
112
+ sendResetCode: 'Enviar Código',
113
+ backToLogin: 'Volver al Inicio de Sesión'
114
+ },
115
+ verifyOtp: {
116
+ title: 'Revisa tu Correo',
117
+ passwordResetTitle: 'Restablecer Contraseña',
118
+ subtitle: 'Enviamos un código de 6 dígitos a',
119
+ passwordResetSubtitle: 'Ingresa el código para restablecer tu contraseña',
120
+ verify: 'Verificar',
121
+ noCodeReceived: '¿No recibiste el código?',
122
+ resendCode: 'Reenviar Código',
123
+ resending: 'Enviando...',
124
+ resendIn: 'Reenviar en {seconds}s',
125
+ backToLogin: 'Volver al Inicio de Sesión'
126
+ },
127
+ setPassword: {
128
+ title: 'Establece tu Contraseña',
129
+ subtitle: 'Crea una contraseña segura para tu cuenta',
130
+ newPasswordLabel: 'Nueva Contraseña',
131
+ confirmPasswordLabel: 'Confirmar Contraseña',
132
+ passwordRequirements: 'Al menos 8 caracteres con 3 de: mayúscula, minúscula, número, carácter especial',
133
+ setPassword: 'Establecer Contraseña'
134
+ }
135
+ };
136
+ /** Built-in dictionaries. Consumers can add more locales via the `messages` prop. */ export const uiTranslations = {
137
+ en,
138
+ es
139
+ };
140
+ function isPlainObject(value) {
141
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
142
+ }
143
+ function deepMerge(base, override) {
144
+ if (!override) return base;
145
+ const result = {
146
+ ...base
147
+ };
148
+ for(const key in override){
149
+ const overrideValue = override[key];
150
+ const baseValue = base[key];
151
+ if (isPlainObject(overrideValue) && isPlainObject(baseValue)) {
152
+ result[key] = deepMerge(baseValue, overrideValue);
153
+ } else if (overrideValue !== undefined) {
154
+ result[key] = overrideValue;
155
+ }
156
+ }
157
+ return result;
158
+ }
159
+ /**
160
+ * Resolve the final UI translations for a given locale, applying any consumer
161
+ * overrides on top of the built-in dictionaries.
162
+ *
163
+ * Resolution order per key: `messages[locale]` → `messages.en` → built-in
164
+ * `[locale]` → built-in `en`. Consumers may pass a partial override object —
165
+ * any key they don't specify falls back automatically.
166
+ *
167
+ * @param locale - Target locale, e.g. 'en', 'es', or any custom locale defined in `messages`.
168
+ * @param messages - Optional map of locale -> partial translation overrides. Can also
169
+ * introduce brand-new locales not built into the plugin.
170
+ */ export function getUiTranslations(locale = 'en', messages) {
171
+ // Layer, in order: built-in en -> built-in locale -> consumer en override -> consumer locale override
172
+ let result = uiTranslations.en;
173
+ if (locale !== 'en' && uiTranslations[locale]) {
174
+ result = deepMerge(result, uiTranslations[locale]);
175
+ }
176
+ if (messages?.en) result = deepMerge(result, messages.en);
177
+ if (locale !== 'en' && messages?.[locale]) result = deepMerge(result, messages[locale]);
178
+ return result;
179
+ }
@@ -7,6 +7,9 @@ export { useForgotPasswordFlow } from '../auth/application/hooks/useForgotPasswo
7
7
  export { useSetPasswordFlow } from '../auth/application/hooks/useSetPasswordFlow';
8
8
  export { checkEmail, sendOtp, verifyOtp, setUserPassword, signup, initiateGoogleLogin, } from '../auth/application/services/authService';
9
9
  export { evaluatePasswordStrength, isPasswordValid, MIN_PASSWORD_LENGTH } from '../auth/domain/passwordRules';
10
+ export { getUiTranslations, uiTranslations } from '../components/ui/translations';
11
+ export type { UiTranslations, DeepPartial } from '../components/ui/translations';
12
+ export { detectClientLocale } from '../components/ui/locale';
10
13
  export { default as LoginPage } from '../components/pages/LoginPage';
11
14
  export { default as SignupPage } from '../components/pages/SignupPage';
12
15
  export { default as ForgotPasswordPage } from '../components/pages/ForgotPasswordPage';
@@ -14,6 +14,9 @@ export { useSetPasswordFlow } from '../auth/application/hooks/useSetPasswordFlow
14
14
  export { checkEmail, sendOtp, verifyOtp, setUserPassword, signup, initiateGoogleLogin } from '../auth/application/services/authService.js';
15
15
  // Domain utilities
16
16
  export { evaluatePasswordStrength, isPasswordValid, MIN_PASSWORD_LENGTH } from '../auth/domain/passwordRules.js';
17
+ // UI translations / locale utilities
18
+ export { getUiTranslations, uiTranslations } from '../components/ui/translations.js';
19
+ export { detectClientLocale } from '../components/ui/locale.js';
17
20
  // Page components
18
21
  export { default as LoginPage } from '../components/pages/LoginPage.js';
19
22
  export { default as SignupPage } from '../components/pages/SignupPage.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@main12/auth-login",
3
- "version": "0.3.8",
3
+ "version": "0.4.1",
4
4
  "description": "Reusable Payload CMS auth plugin — login, signup, OTP, forgot password, branded emails, Powered by Main12",
5
5
  "license": "MIT",
6
6
  "type": "module",