@mesob/auth-react 0.1.1 → 0.2.0

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 (116) hide show
  1. package/dist/components/auth/{auth-page-layout.d.ts → auth-layout.d.ts} +3 -3
  2. package/dist/components/auth/{auth-page-layout.js → auth-layout.js} +4 -4
  3. package/dist/components/auth/auth-layout.js.map +1 -0
  4. package/dist/components/auth/countdown.js +15 -6
  5. package/dist/components/auth/countdown.js.map +1 -1
  6. package/dist/components/auth/forgot-password.d.ts +1 -9
  7. package/dist/components/auth/forgot-password.js +267 -43
  8. package/dist/components/auth/forgot-password.js.map +1 -1
  9. package/dist/components/auth/reset-password-form.d.ts +2 -10
  10. package/dist/components/auth/reset-password-form.js +366 -118
  11. package/dist/components/auth/reset-password-form.js.map +1 -1
  12. package/dist/components/auth/sign-in.d.ts +2 -10
  13. package/dist/components/auth/sign-in.js +358 -130
  14. package/dist/components/auth/sign-in.js.map +1 -1
  15. package/dist/components/auth/sign-up.d.ts +2 -10
  16. package/dist/components/auth/sign-up.js +379 -131
  17. package/dist/components/auth/sign-up.js.map +1 -1
  18. package/dist/components/auth/verification-form.d.ts +2 -16
  19. package/dist/components/auth/verification-form.js +15 -6
  20. package/dist/components/auth/verification-form.js.map +1 -1
  21. package/dist/components/auth/verify-email.d.ts +10 -0
  22. package/dist/components/auth/{pages/verify-email-page.js → verify-email.js} +54 -34
  23. package/dist/components/auth/verify-email.js.map +1 -0
  24. package/dist/components/auth/verify-phone.d.ts +11 -0
  25. package/dist/components/auth/{pages/verify-phone-page.js → verify-phone.js} +53 -46
  26. package/dist/components/auth/verify-phone.js.map +1 -0
  27. package/dist/components/error-boundary.d.ts +2 -2
  28. package/dist/components/iam/permissions.d.ts +5 -0
  29. package/dist/components/iam/{permissions/permissions-page.js → permissions.js} +29 -13
  30. package/dist/components/iam/permissions.js.map +1 -0
  31. package/dist/components/iam/roles.d.ts +5 -0
  32. package/dist/components/iam/{roles/roles-page.js → roles.js} +29 -13
  33. package/dist/components/iam/roles.js.map +1 -0
  34. package/dist/components/iam/sessions.d.ts +5 -0
  35. package/dist/components/iam/{sessions/sessions-page.js → sessions.js} +13 -11
  36. package/dist/components/iam/sessions.js.map +1 -0
  37. package/dist/components/iam/tenants.d.ts +5 -0
  38. package/dist/components/iam/{tenants/tenants-page.js → tenants.js} +13 -11
  39. package/dist/components/iam/tenants.js.map +1 -0
  40. package/dist/components/iam/users.d.ts +5 -0
  41. package/dist/components/iam/{users/users-page.js → users.js} +13 -11
  42. package/dist/components/iam/users.js.map +1 -0
  43. package/dist/components/profile/account.d.ts +5 -0
  44. package/dist/components/profile/account.js +66 -0
  45. package/dist/components/profile/account.js.map +1 -0
  46. package/dist/components/profile/change-email-form.d.ts +5 -0
  47. package/dist/components/profile/change-email-form.js +721 -0
  48. package/dist/components/profile/change-email-form.js.map +1 -0
  49. package/dist/components/profile/change-password-form.d.ts +5 -0
  50. package/dist/components/profile/change-password-form.js +256 -0
  51. package/dist/components/profile/change-password-form.js.map +1 -0
  52. package/dist/components/profile/change-phone-form.d.ts +5 -0
  53. package/dist/components/profile/change-phone-form.js +758 -0
  54. package/dist/components/profile/change-phone-form.js.map +1 -0
  55. package/dist/components/profile/change-profile.d.ts +9 -0
  56. package/dist/components/profile/change-profile.js +37 -0
  57. package/dist/components/profile/change-profile.js.map +1 -0
  58. package/dist/components/profile/otp-verification-modal.d.ts +15 -0
  59. package/dist/components/profile/otp-verification-modal.js +261 -0
  60. package/dist/components/profile/otp-verification-modal.js.map +1 -0
  61. package/dist/components/profile/request-change-email-form.d.ts +10 -0
  62. package/dist/components/profile/request-change-email-form.js +293 -0
  63. package/dist/components/profile/request-change-email-form.js.map +1 -0
  64. package/dist/components/profile/request-change-phone-form.d.ts +10 -0
  65. package/dist/components/profile/request-change-phone-form.js +331 -0
  66. package/dist/components/profile/request-change-phone-form.js.map +1 -0
  67. package/dist/components/profile/security.d.ts +5 -0
  68. package/dist/components/profile/security.js +1439 -0
  69. package/dist/components/profile/security.js.map +1 -0
  70. package/dist/components/profile/verify-change-email-form.d.ts +11 -0
  71. package/dist/components/profile/verify-change-email-form.js +402 -0
  72. package/dist/components/profile/verify-change-email-form.js.map +1 -0
  73. package/dist/components/profile/verify-change-phone-form.d.ts +11 -0
  74. package/dist/components/profile/verify-change-phone-form.js +406 -0
  75. package/dist/components/profile/verify-change-phone-form.js.map +1 -0
  76. package/dist/components/shared/{data-table/data-table.js → data-table.js} +2 -2
  77. package/dist/components/shared/data-table.js.map +1 -0
  78. package/dist/index.d.ts +42 -93
  79. package/dist/index.js +2297 -1299
  80. package/dist/index.js.map +1 -1
  81. package/dist/types-D3s9oE-5.d.ts +75 -0
  82. package/dist/verification-form-ipSRTtQB.d.ts +22 -0
  83. package/package.json +3 -2
  84. package/dist/components/auth/auth-page-layout.js.map +0 -1
  85. package/dist/components/auth/pages/forgot-password-page.d.ts +0 -6
  86. package/dist/components/auth/pages/forgot-password-page.js +0 -362
  87. package/dist/components/auth/pages/forgot-password-page.js.map +0 -1
  88. package/dist/components/auth/pages/reset-password-page.d.ts +0 -9
  89. package/dist/components/auth/pages/reset-password-page.js +0 -514
  90. package/dist/components/auth/pages/reset-password-page.js.map +0 -1
  91. package/dist/components/auth/pages/sign-in-page.d.ts +0 -8
  92. package/dist/components/auth/pages/sign-in-page.js +0 -565
  93. package/dist/components/auth/pages/sign-in-page.js.map +0 -1
  94. package/dist/components/auth/pages/sign-up-page.d.ts +0 -9
  95. package/dist/components/auth/pages/sign-up-page.js +0 -518
  96. package/dist/components/auth/pages/sign-up-page.js.map +0 -1
  97. package/dist/components/auth/pages/verify-email-page.d.ts +0 -10
  98. package/dist/components/auth/pages/verify-email-page.js.map +0 -1
  99. package/dist/components/auth/pages/verify-phone-page.d.ts +0 -11
  100. package/dist/components/auth/pages/verify-phone-page.js.map +0 -1
  101. package/dist/components/iam/permissions/permissions-page.d.ts +0 -5
  102. package/dist/components/iam/permissions/permissions-page.js.map +0 -1
  103. package/dist/components/iam/roles/roles-page.d.ts +0 -5
  104. package/dist/components/iam/roles/roles-page.js.map +0 -1
  105. package/dist/components/iam/sessions/sessions-page.d.ts +0 -5
  106. package/dist/components/iam/sessions/sessions-page.js.map +0 -1
  107. package/dist/components/iam/tenants/tenants-page.d.ts +0 -5
  108. package/dist/components/iam/tenants/tenants-page.js.map +0 -1
  109. package/dist/components/iam/users/users-page.d.ts +0 -5
  110. package/dist/components/iam/users/users-page.js.map +0 -1
  111. package/dist/components/profile/profile-page.d.ts +0 -8
  112. package/dist/components/profile/profile-page.js +0 -163
  113. package/dist/components/profile/profile-page.js.map +0 -1
  114. package/dist/components/shared/data-table/data-table.js.map +0 -1
  115. package/dist/handle-error-BqDMxnQZ.d.ts +0 -8
  116. /package/dist/components/shared/{data-table/data-table.d.ts → data-table.d.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/auth/sign-up.tsx","../../../src/lib/translations.ts","../../../src/provider.tsx","../../../src/hooks/use-translator.ts"],"sourcesContent":["'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { Button } from '@mesob/ui/components/button';\nimport {\n Field,\n FieldError,\n FieldGroup,\n FieldLabel,\n} from '@mesob/ui/components/field';\nimport { Input } from '@mesob/ui/components/input';\nimport { IconEye, IconEyeOff } from '@tabler/icons-react';\nimport { useEffect, useState } from 'react';\nimport { Controller, useForm } from 'react-hook-form';\nimport { z } from 'zod';\nimport { useTranslator } from '../../hooks/use-translator';\n\nconst isPhone = (s: string) => /^\\+?[0-9()[\\]\\s-]{6,}$/.test(s);\n\ntype SignUpFormValues = {\n fullName: string;\n identifier: string;\n handle?: string;\n password: string;\n confirmPassword: string;\n};\n\ntype SignUpProps = {\n onSubmit: (values: SignUpFormValues) => Promise<void> | void;\n isLoading?: boolean;\n initialIdentifier?: string;\n};\n\nconst signUpSchema = (t: (key: string) => string) =>\n z\n .object({\n fullName: z.string().min(1, t('errors.fullNameRequired')),\n identifier: z\n .string()\n .min(1, t('errors.contactRequired'))\n .refine(\n (val) => {\n if (!val) {\n return false;\n }\n return val.includes('@') || isPhone(val);\n },\n {\n message: t('errors.invalidEmailOrPhone'),\n },\n ),\n password: z\n .string()\n .min(8, t('errors.passwordLength'))\n .max(128, t('errors.longPasswordError')),\n confirmPassword: z.string(),\n })\n .refine((data) => data.password === data.confirmPassword, {\n message: t('errors.passwordsMismatch'),\n path: ['confirmPassword'],\n });\n\nexport const SignUp = ({\n onSubmit,\n isLoading = false,\n initialIdentifier,\n}: SignUpProps) => {\n const t = useTranslator('Auth.signUp');\n const hasInitialIdentifier = !!initialIdentifier;\n const [showPassword, setShowPassword] = useState(false);\n const [showConfirmPassword, setShowConfirmPassword] = useState(false);\n\n const form = useForm<SignUpFormValues>({\n resolver: zodResolver(signUpSchema(t)),\n defaultValues: {\n fullName: '',\n identifier: initialIdentifier || '',\n password: '',\n confirmPassword: '',\n },\n });\n\n useEffect(() => {\n if (initialIdentifier) {\n form.setValue('identifier', initialIdentifier);\n }\n }, [initialIdentifier, form]);\n\n const handleSubmit = form.handleSubmit(async (values) => {\n await onSubmit(values);\n });\n\n const getIdentifierLabel = () => {\n if (!hasInitialIdentifier) {\n return t('form.accountLabel') || 'Email/Phone';\n }\n if (initialIdentifier?.includes('@')) {\n return t('form.emailLabel');\n }\n return t('form.phoneLabel');\n };\n const identifierLabel = getIdentifierLabel();\n\n return (\n <form id=\"sign-up-form\" onSubmit={handleSubmit}>\n <FieldGroup>\n <Controller\n name=\"fullName\"\n control={form.control}\n render={({ field, fieldState }) => (\n <Field data-invalid={fieldState.invalid}>\n <FieldLabel htmlFor=\"sign-up-fullName\">\n {t('form.fullNameLabel')}\n </FieldLabel>\n <Input\n {...field}\n id=\"sign-up-fullName\"\n placeholder={t('form.fullNamePlaceholder')}\n aria-invalid={fieldState.invalid}\n />\n {fieldState.invalid && <FieldError errors={[fieldState.error]} />}\n </Field>\n )}\n />\n <Controller\n name=\"identifier\"\n control={form.control}\n render={({ field, fieldState }) => (\n <Field data-invalid={fieldState.invalid}>\n <FieldLabel\n htmlFor=\"sign-up-identifier\"\n className={hasInitialIdentifier ? 'block' : undefined}\n >\n {identifierLabel}\n </FieldLabel>\n <Input\n {...field}\n id=\"sign-up-identifier\"\n type={field.value.includes('@') ? 'email' : 'tel'}\n placeholder={\n hasInitialIdentifier\n ? undefined\n : t('form.accountPlaceholder') || 'Email or phone number'\n }\n disabled={hasInitialIdentifier}\n aria-invalid={fieldState.invalid}\n />\n {fieldState.invalid && <FieldError errors={[fieldState.error]} />}\n </Field>\n )}\n />\n <Controller\n name=\"password\"\n control={form.control}\n render={({ field, fieldState }) => (\n <Field data-invalid={fieldState.invalid}>\n <FieldLabel htmlFor=\"sign-up-password\">\n {t('form.passwordLabel')}\n </FieldLabel>\n <div className=\"relative\">\n <Input\n {...field}\n id=\"sign-up-password\"\n type={showPassword ? 'text' : 'password'}\n placeholder={t('form.passwordPlaceholder')}\n aria-invalid={fieldState.invalid}\n />\n <button\n type=\"button\"\n onClick={() => setShowPassword(!showPassword)}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground\"\n >\n {showPassword ? (\n <IconEyeOff className=\"h-4 w-4\" />\n ) : (\n <IconEye className=\"h-4 w-4\" />\n )}\n </button>\n </div>\n {fieldState.invalid && <FieldError errors={[fieldState.error]} />}\n </Field>\n )}\n />\n <Controller\n name=\"confirmPassword\"\n control={form.control}\n render={({ field, fieldState }) => (\n <Field data-invalid={fieldState.invalid}>\n <FieldLabel htmlFor=\"sign-up-confirmPassword\">\n {t('form.confirmPasswordLabel')}\n </FieldLabel>\n <div className=\"relative\">\n <Input\n {...field}\n id=\"sign-up-confirmPassword\"\n type={showConfirmPassword ? 'text' : 'password'}\n placeholder={t('form.passwordPlaceholder')}\n aria-invalid={fieldState.invalid}\n />\n <button\n type=\"button\"\n onClick={() => setShowConfirmPassword(!showConfirmPassword)}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground\"\n >\n {showConfirmPassword ? (\n <IconEyeOff className=\"h-4 w-4\" />\n ) : (\n <IconEye className=\"h-4 w-4\" />\n )}\n </button>\n </div>\n {fieldState.invalid && <FieldError errors={[fieldState.error]} />}\n </Field>\n )}\n />\n </FieldGroup>\n <div className=\"mt-4\">\n <Button\n type=\"submit\"\n form=\"sign-up-form\"\n className=\"w-full\"\n disabled={isLoading}\n >\n {isLoading ? t('form.submitting') : t('form.submit')}\n </Button>\n </div>\n </form>\n );\n};\n","type Messages = Record<string, unknown>;\n\nexport function createTranslator(messages: Messages, namespace?: string) {\n return (key: string, params?: Record<string, string | number>): string => {\n const fullKey = namespace ? `${namespace}.${key}` : key;\n const keys = fullKey.split('.');\n\n let value: unknown = messages;\n for (const k of keys) {\n if (value && typeof value === 'object' && value !== null) {\n value = (value as Record<string, unknown>)[k];\n } else {\n return fullKey;\n }\n }\n\n if (typeof value !== 'string') {\n return fullKey;\n }\n\n // Simple parameter replacement\n if (params) {\n return value.replace(/\\{(\\w+)\\}/g, (_, param) =>\n String(params[param] ?? `{${param}}`),\n );\n }\n\n return value;\n };\n}\n","'use client';\n\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { deepmerge } from 'deepmerge-ts';\nimport createFetchClient from 'openapi-fetch';\nimport createClient from 'openapi-react-query';\nimport type { ReactNode } from 'react';\nimport { createContext, useContext, useEffect, useState } from 'react';\nimport type { paths } from './data/openapi';\nimport { createTranslator } from './lib/translations';\nimport {\n type AuthClientConfig,\n type AuthResponse,\n defaultAuthClientConfig,\n type Session,\n type User,\n} from './types';\nimport { createCustomFetch } from './utils/custom-fetch';\n\ntype OpenApiHooks = any;\n\ntype SessionState = {\n user: User | null;\n session: Session | null;\n isLoading: boolean;\n isAuthenticated: boolean;\n error: Error | null;\n};\n\ntype SessionContextValue = SessionState & {\n refresh: () => Promise<void>;\n signOut: () => Promise<void>;\n};\n\ntype ApiContextValue = {\n hooks: OpenApiHooks;\n setAuth: (auth: AuthResponse) => void;\n clearAuth: () => void;\n refresh: () => Promise<void>;\n};\n\ntype ConfigContextValue = {\n config: AuthClientConfig;\n t: (key: string, params?: Record<string, string | number>) => string;\n};\n\nconst SessionContext = createContext<SessionContextValue | null>(null);\nconst ApiContext = createContext<ApiContextValue | null>(null);\nconst ConfigContext = createContext<ConfigContextValue | null>(null);\n\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 1000 * 60 * 5,\n gcTime: 1000 * 60 * 10,\n retry: 1,\n refetchOnWindowFocus: false,\n },\n },\n});\n\nexport function useSession() {\n const context = useContext(SessionContext);\n if (!context) {\n throw new Error('useSession must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useApi() {\n const context = useContext(ApiContext);\n if (!context) {\n throw new Error('useApi must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useConfig() {\n const context = useContext(ConfigContext);\n if (!context) {\n throw new Error('useConfig must be used within MesobAuthProvider');\n }\n return context;\n}\n\ntype MesobAuthProviderProps = {\n config: AuthClientConfig;\n children: ReactNode;\n};\n\nexport function MesobAuthProvider({\n config,\n children,\n}: MesobAuthProviderProps) {\n const mergedConfig = deepmerge(\n { ...defaultAuthClientConfig } as Partial<AuthClientConfig>,\n config,\n ) as AuthClientConfig;\n\n const api = createFetchClient<paths>({\n baseUrl: mergedConfig.baseURL,\n fetch: createCustomFetch(mergedConfig),\n });\n\n const hooks = createClient(api);\n\n return (\n <QueryClientProvider client={queryClient}>\n <AuthStateProvider config={mergedConfig} hooks={hooks}>\n {children}\n </AuthStateProvider>\n </QueryClientProvider>\n );\n}\n\ntype AuthStateProviderProps = {\n config: AuthClientConfig;\n hooks: OpenApiHooks;\n children: ReactNode;\n};\n\nfunction AuthStateProvider({\n config,\n hooks,\n children,\n}: AuthStateProviderProps) {\n const [authState, setAuthState] = useState<{\n user: User | null;\n session: Session | null;\n isLoading: boolean;\n error: Error | null;\n }>({\n user: null,\n session: null,\n isLoading: false,\n error: null,\n });\n\n const {\n data: sessionData,\n isLoading: sessionLoading,\n error: sessionError,\n refetch,\n } = hooks.useQuery(\n 'get',\n '/session',\n {},\n {\n enabled: true,\n refetchOnMount: true,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n retry: false,\n },\n );\n\n useEffect(() => {\n if (sessionLoading) {\n setAuthState((prev) => ({ ...prev, isLoading: true }));\n return;\n }\n\n if (sessionError) {\n setAuthState({\n user: null,\n session: null,\n isLoading: false,\n error: sessionError as Error,\n });\n return;\n }\n\n if (sessionData) {\n setAuthState({\n user: sessionData.user,\n session: sessionData.session,\n isLoading: false,\n error: null,\n });\n return;\n }\n\n setAuthState({\n user: null,\n session: null,\n isLoading: false,\n error: null,\n });\n }, [sessionData, sessionLoading, sessionError]);\n\n const refresh = async () => {\n await refetch();\n };\n\n const setAuth = (auth: AuthResponse) => {\n setAuthState({\n user: auth.user,\n session: auth.session,\n isLoading: false,\n error: null,\n });\n };\n\n const clearAuth = () => {\n setAuthState({\n user: null,\n session: null,\n isLoading: false,\n error: null,\n });\n };\n\n const signOutMutation = hooks.useMutation('post', '/sign-out');\n\n const signOut = async () => {\n try {\n await signOutMutation.mutateAsync({});\n } finally {\n clearAuth();\n }\n };\n\n const t = createTranslator(config.messages || {});\n\n return (\n <ConfigContext.Provider value={{ config, t }}>\n <ApiContext.Provider value={{ hooks, setAuth, clearAuth, refresh }}>\n <SessionContext.Provider\n value={{\n user: authState.user,\n session: authState.session,\n isLoading: authState.isLoading,\n isAuthenticated: !!authState.user && !!authState.session,\n error: authState.error,\n refresh,\n signOut,\n }}\n >\n {children}\n </SessionContext.Provider>\n </ApiContext.Provider>\n </ConfigContext.Provider>\n );\n}\n","import { createTranslator } from '../lib/translations';\nimport { useConfig } from '../provider';\n\nexport function useTranslator(namespace?: string) {\n const { config } = useConfig();\n return createTranslator(config.messages || {}, namespace);\n}\n"],"mappings":"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","names":["useEffect","useState","jsx","useState","useEffect"]}
1
+ {"version":3,"sources":["../../../src/components/auth/sign-up.tsx","../../../src/hooks/use-translator.ts","../../../src/lib/translations.ts","../../../src/provider.tsx","../../../src/utils/cookie.ts","../../../src/constants/auth.error.codes.ts","../../../src/utils/handle-error.ts","../../../src/components/auth/auth-layout.tsx"],"sourcesContent":["'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport {\n Alert,\n AlertDescription,\n AlertTitle,\n} from '@mesob/ui/components/alert';\nimport { Button } from '@mesob/ui/components/button';\nimport {\n Field,\n FieldError,\n FieldGroup,\n FieldLabel,\n} from '@mesob/ui/components/field';\nimport { Input } from '@mesob/ui/components/input';\nimport { useMesob } from '@mesob/ui/components/mesob-context';\nimport { IconAlertCircle, IconEye, IconEyeOff } from '@tabler/icons-react';\nimport { useEffect, useState } from 'react';\nimport { Controller, useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\nimport { useTranslator } from '../../hooks/use-translator';\nimport { useApi, useConfig } from '../../provider';\nimport type { AuthErrorContent } from '../../utils/handle-error';\nimport { handleError } from '../../utils/handle-error';\nimport { AuthLayout } from './auth-layout';\n\nconst isPhone = (s: string) => /^\\+?[0-9()[\\]\\s-]{6,}$/.test(s);\n\ntype SignUpFormValues = {\n fullName: string;\n identifier: string;\n handle?: string;\n password: string;\n confirmPassword: string;\n};\n\ntype SignUpProps = {\n redirectUrl?: string;\n initialIdentifier?: string;\n};\n\nconst signUpSchema = (t: (key: string) => string) =>\n z\n .object({\n fullName: z.string().min(1, t('errors.fullNameRequired')),\n identifier: z\n .string()\n .min(1, t('errors.contactRequired'))\n .refine(\n (val) => {\n if (!val) {\n return false;\n }\n return val.includes('@') || isPhone(val);\n },\n {\n message: t('errors.invalidEmailOrPhone'),\n },\n ),\n password: z\n .string()\n .min(8, t('errors.passwordLength'))\n .max(128, t('errors.longPasswordError')),\n confirmPassword: z.string(),\n })\n .refine((data) => data.password === data.confirmPassword, {\n message: t('errors.passwordsMismatch'),\n path: ['confirmPassword'],\n });\n\nexport const SignUp = ({\n redirectUrl,\n initialIdentifier,\n}: SignUpProps = {}) => {\n const { hooks, setAuth } = useApi();\n const { config } = useConfig();\n const mesob = useMesob();\n const t = useTranslator('Auth.signUp');\n const Link = mesob?.linkComponent ?? config.navigation?.linkComponent;\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthErrorContent | null>(null);\n const [showPassword, setShowPassword] = useState(false);\n const [showConfirmPassword, setShowConfirmPassword] = useState(false);\n\n const signUpMutation = hooks.useMutation('post', '/sign-up');\n\n const signInLink = config.navigation?.links?.signIn || '/auth/sign-in';\n const onNavigate =\n config.navigation?.onNavigate ||\n ((path: string) => {\n if (typeof window !== 'undefined') {\n window.location.href = path;\n }\n });\n const logoImage = config.ui.logoImage;\n const defaultRedirect =\n redirectUrl || config.navigation?.defaultRedirectUrl || '/';\n\n const hasInitialIdentifier = !!initialIdentifier;\n\n const form = useForm<SignUpFormValues>({\n resolver: zodResolver(signUpSchema(t)),\n defaultValues: {\n fullName: '',\n identifier: initialIdentifier || '',\n password: '',\n confirmPassword: '',\n },\n });\n\n useEffect(() => {\n if (initialIdentifier) {\n form.setValue('identifier', initialIdentifier);\n }\n }, [initialIdentifier, form]);\n\n useEffect(() => {\n if (error) {\n toast.error(error.title || 'Error', {\n description: error.description,\n });\n }\n }, [error]);\n\n const handleSubmit = form.handleSubmit(async (values) => {\n setIsLoading(true);\n setError(null);\n\n try {\n const identifier = values.identifier;\n const usingPhone = isPhone(identifier);\n\n const res = await signUpMutation.mutateAsync({\n body: usingPhone\n ? {\n phone: identifier,\n password: values.password,\n fullName: values.fullName,\n handle: values.handle,\n }\n : {\n email: identifier,\n password: values.password,\n fullName: values.fullName,\n handle: values.handle,\n },\n });\n\n if ('verificationId' in res && res.verificationId) {\n if (usingPhone) {\n onNavigate(\n `/auth/verify-phone?context=sign-up&verificationId=${res.verificationId}&phone=${encodeURIComponent(identifier)}`,\n );\n } else {\n onNavigate(\n `/auth/verify-email?verificationId=${res.verificationId}&email=${encodeURIComponent(identifier)}`,\n );\n }\n return;\n }\n\n if ('user' in res && 'session' in res) {\n setAuth(res);\n }\n onNavigate(defaultRedirect);\n } catch (err) {\n handleError(err, setError, t);\n } finally {\n setIsLoading(false);\n }\n });\n\n const getIdentifierLabel = () => {\n if (!hasInitialIdentifier) {\n return t('form.accountLabel') || 'Email/Phone';\n }\n if (initialIdentifier?.includes('@')) {\n return t('form.emailLabel');\n }\n return t('form.phoneLabel');\n };\n const identifierLabel = getIdentifierLabel();\n\n let errorContent: AuthErrorContent | null = null;\n if (error) {\n if (typeof error === 'string') {\n errorContent = { title: 'Error', description: error };\n } else {\n errorContent = error;\n }\n }\n\n return (\n <AuthLayout\n title={t('title')}\n description={t('description')}\n logoImage={logoImage}\n footer={\n <p>\n {t('footer.hasAccount')}{' '}\n {Link ? (\n <Link href={signInLink} className=\"text-primary hover:underline\">\n {t('footer.signInCta')}\n </Link>\n ) : (\n <a\n href={signInLink}\n onClick={(e) => {\n e.preventDefault();\n onNavigate(signInLink);\n }}\n className=\"text-primary hover:underline\"\n >\n {t('footer.signInCta')}\n </a>\n )}\n </p>\n }\n >\n <form id=\"sign-up-form\" onSubmit={handleSubmit}>\n <FieldGroup>\n <Controller\n name=\"fullName\"\n control={form.control}\n render={({ field, fieldState }) => (\n <Field data-invalid={fieldState.invalid}>\n <FieldLabel htmlFor=\"sign-up-fullName\">\n {t('form.fullNameLabel')}\n </FieldLabel>\n <Input\n {...field}\n id=\"sign-up-fullName\"\n placeholder={t('form.fullNamePlaceholder')}\n aria-invalid={fieldState.invalid}\n />\n {fieldState.invalid && (\n <FieldError errors={[fieldState.error]} />\n )}\n </Field>\n )}\n />\n <Controller\n name=\"identifier\"\n control={form.control}\n render={({ field, fieldState }) => (\n <Field data-invalid={fieldState.invalid}>\n <FieldLabel\n htmlFor=\"sign-up-identifier\"\n className={hasInitialIdentifier ? 'block' : undefined}\n >\n {identifierLabel}\n </FieldLabel>\n <Input\n {...field}\n id=\"sign-up-identifier\"\n type={field.value.includes('@') ? 'email' : 'tel'}\n placeholder={\n hasInitialIdentifier\n ? undefined\n : t('form.accountPlaceholder') || 'Email or phone number'\n }\n disabled={hasInitialIdentifier}\n aria-invalid={fieldState.invalid}\n />\n {fieldState.invalid && (\n <FieldError errors={[fieldState.error]} />\n )}\n </Field>\n )}\n />\n <Controller\n name=\"password\"\n control={form.control}\n render={({ field, fieldState }) => (\n <Field data-invalid={fieldState.invalid}>\n <FieldLabel htmlFor=\"sign-up-password\">\n {t('form.passwordLabel')}\n </FieldLabel>\n <div className=\"relative\">\n <Input\n {...field}\n id=\"sign-up-password\"\n type={showPassword ? 'text' : 'password'}\n placeholder={t('form.passwordPlaceholder')}\n aria-invalid={fieldState.invalid}\n />\n <button\n type=\"button\"\n onClick={() => setShowPassword(!showPassword)}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground\"\n >\n {showPassword ? (\n <IconEyeOff className=\"h-4 w-4\" />\n ) : (\n <IconEye className=\"h-4 w-4\" />\n )}\n </button>\n </div>\n {fieldState.invalid && (\n <FieldError errors={[fieldState.error]} />\n )}\n </Field>\n )}\n />\n <Controller\n name=\"confirmPassword\"\n control={form.control}\n render={({ field, fieldState }) => (\n <Field data-invalid={fieldState.invalid}>\n <FieldLabel htmlFor=\"sign-up-confirmPassword\">\n {t('form.confirmPasswordLabel')}\n </FieldLabel>\n <div className=\"relative\">\n <Input\n {...field}\n id=\"sign-up-confirmPassword\"\n type={showConfirmPassword ? 'text' : 'password'}\n placeholder={t('form.passwordPlaceholder')}\n aria-invalid={fieldState.invalid}\n />\n <button\n type=\"button\"\n onClick={() => setShowConfirmPassword(!showConfirmPassword)}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground\"\n >\n {showConfirmPassword ? (\n <IconEyeOff className=\"h-4 w-4\" />\n ) : (\n <IconEye className=\"h-4 w-4\" />\n )}\n </button>\n </div>\n {fieldState.invalid && (\n <FieldError errors={[fieldState.error]} />\n )}\n </Field>\n )}\n />\n </FieldGroup>\n <div className=\"mt-4\">\n <Button\n type=\"submit\"\n form=\"sign-up-form\"\n className=\"w-full\"\n disabled={isLoading || signUpMutation.isPending}\n >\n {isLoading || signUpMutation.isPending\n ? t('form.submitting')\n : t('form.submit')}\n </Button>\n </div>\n </form>\n {errorContent && (\n <Alert variant=\"destructive\" className=\"mt-4\">\n <IconAlertCircle className=\"h-4 w-4\" />\n <AlertTitle>{errorContent.title}</AlertTitle>\n <AlertDescription>{errorContent.description}</AlertDescription>\n </Alert>\n )}\n </AuthLayout>\n );\n};\n","import { useMesob } from '@mesob/ui/components/mesob-context';\nimport { createTranslator } from '../lib/translations';\nimport { useConfig } from '../provider';\n\nexport function useTranslator(namespace?: string) {\n const mesob = useMesob();\n const { config } = useConfig();\n\n if (mesob?.t) {\n return (key: string, params?: Record<string, string | number>) =>\n mesob.t!(namespace ? `${namespace}.${key}` : key, params);\n }\n\n return createTranslator(config.messages || {}, namespace);\n}\n","type Messages = Record<string, unknown>;\n\nexport function createTranslator(messages: Messages, namespace?: string) {\n return (key: string, params?: Record<string, string | number>): string => {\n const fullKey = namespace ? `${namespace}.${key}` : key;\n const keys = fullKey.split('.');\n\n let value: unknown = messages;\n for (const k of keys) {\n if (value && typeof value === 'object' && value !== null) {\n value = (value as Record<string, unknown>)[k];\n } else {\n return fullKey;\n }\n }\n\n if (typeof value !== 'string') {\n return fullKey;\n }\n\n // Simple parameter replacement\n if (params) {\n return value.replace(/\\{(\\w+)\\}/g, (_, param) =>\n String(params[param] ?? `{${param}}`),\n );\n }\n\n return value;\n };\n}\n","'use client';\n\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { deepmerge } from 'deepmerge-ts';\nimport createFetchClient from 'openapi-fetch';\nimport createClient from 'openapi-react-query';\nimport type { ReactNode } from 'react';\nimport { createContext, useContext, useMemo, useState } from 'react';\nimport type { paths } from './data/openapi';\nimport { createTranslator } from './lib/translations';\nimport {\n type AuthClientConfig,\n type AuthResponse,\n defaultAuthClientConfig,\n type Session,\n type User,\n} from './types';\nimport { getSessionCookieName } from './utils/cookie';\nimport { createCustomFetch } from './utils/custom-fetch';\n\n// biome-ignore lint/suspicious/noExplicitAny: OpenAPI hooks type\ntype OpenApiHooks = any;\n\n// --- Utility: Check if running on server ---\nfunction isServer(): boolean {\n return typeof document === 'undefined';\n}\n\n/**\n * @deprecated Cookie is httpOnly and cannot be read client-side.\n * Use `useSession().isAuthenticated` instead.\n * This function always returns false on client.\n */\nexport function hasAuthCookie(_cookieName: string): boolean {\n // Cookie is httpOnly, can't check client-side\n // Always return false - use useSession() for auth status\n return false;\n}\n\n// --- Types ---\nexport type AuthStatus = 'loading' | 'authenticated' | 'unauthenticated';\n\ntype AuthState = {\n user: User | null;\n session: Session | null;\n status: AuthStatus;\n error: Error | null;\n};\n\ntype SessionContextValue = AuthState & {\n isLoading: boolean;\n isAuthenticated: boolean;\n refresh: () => Promise<void>;\n signOut: () => Promise<void>;\n};\n\ntype ApiContextValue = {\n hooks: OpenApiHooks;\n setAuth: (auth: AuthResponse) => void;\n clearAuth: () => void;\n refresh: () => Promise<void>;\n};\n\ntype ConfigContextValue = {\n config: AuthClientConfig;\n cookieName: string;\n t: (key: string, params?: Record<string, string | number>) => string;\n};\n\nconst SessionContext = createContext<SessionContextValue | null>(null);\nconst ApiContext = createContext<ApiContextValue | null>(null);\nconst ConfigContext = createContext<ConfigContextValue | null>(null);\n\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n refetchOnWindowFocus: false,\n },\n },\n});\n\n// --- Hooks ---\n\n/**\n * Get session state including user, session, and auth status.\n * - `status`: 'loading' | 'authenticated' | 'unauthenticated'\n * - `isLoading`: true while fetching session\n * - `isAuthenticated`: true if user and session exist\n */\nexport function useSession(): SessionContextValue {\n const context = useContext(SessionContext);\n if (!context) {\n throw new Error('useSession must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useApi(): ApiContextValue {\n const context = useContext(ApiContext);\n if (!context) {\n throw new Error('useApi must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useConfig(): ConfigContextValue {\n const context = useContext(ConfigContext);\n if (!context) {\n throw new Error('useConfig must be used within MesobAuthProvider');\n }\n return context;\n}\n\n/**\n * @deprecated Cookie is httpOnly, can't be checked client-side.\n * Use `useSession().isAuthenticated` instead.\n */\nexport function useHasAuthCookie(): boolean {\n const { status } = useSession();\n return status === 'authenticated' || status === 'loading';\n}\n\n// --- Provider ---\n\ntype MesobAuthProviderProps = {\n config: AuthClientConfig;\n children: ReactNode;\n};\n\nexport function MesobAuthProvider({\n config,\n children,\n}: MesobAuthProviderProps) {\n const mergedConfig = useMemo(\n () =>\n deepmerge(\n { ...defaultAuthClientConfig } as Partial<AuthClientConfig>,\n config,\n ) as AuthClientConfig,\n [config],\n );\n\n const api = useMemo(\n () =>\n createFetchClient<paths>({\n baseUrl: mergedConfig.baseURL,\n fetch: createCustomFetch(mergedConfig),\n }),\n [mergedConfig],\n );\n\n const hooks = useMemo(() => createClient(api), [api]);\n const cookieName = useMemo(\n () => getSessionCookieName(mergedConfig),\n [mergedConfig],\n );\n\n return (\n <QueryClientProvider client={queryClient}>\n <AuthStateProvider\n config={mergedConfig}\n hooks={hooks}\n cookieName={cookieName}\n >\n {children}\n </AuthStateProvider>\n </QueryClientProvider>\n );\n}\n\ntype AuthStateProviderProps = {\n config: AuthClientConfig;\n hooks: OpenApiHooks;\n cookieName: string;\n children: ReactNode;\n};\n\nfunction AuthStateProvider({\n config,\n hooks,\n cookieName,\n children,\n}: AuthStateProviderProps) {\n // Manual override for sign-out / sign-in\n const [override, setOverride] = useState<AuthState | null>(null);\n\n // Always fetch session - cookie is httpOnly, can't check client-side\n // Server will read the cookie and return user/session if valid\n const {\n data: sessionData,\n isLoading,\n isFetched,\n error: sessionError,\n refetch,\n } = hooks.useQuery(\n 'get',\n '/session',\n {},\n {\n enabled: !(override || isServer()),\n refetchOnMount: false,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n retry: false,\n gcTime: 0,\n staleTime: 0,\n },\n );\n\n // Derive state directly - no useEffect\n const user = override?.user ?? sessionData?.user ?? null;\n const session = override?.session ?? sessionData?.session ?? null;\n const error = override?.error ?? (sessionError as Error | null);\n\n // Check error status code\n const errorStatus = (() => {\n if (!sessionError) {\n return null;\n }\n const err = sessionError as { status?: number };\n return err.status ?? null;\n })();\n\n // Check if error is a network/connection error\n const isNetworkError = (() => {\n if (!sessionError) {\n return false;\n }\n const error = sessionError as Error & { cause?: unknown; data?: unknown };\n const errorMessage =\n error.message || String(error) || JSON.stringify(error);\n // Network errors: TypeError, DOMException, or fetch failures\n if (\n error instanceof TypeError ||\n error instanceof DOMException ||\n error.name === 'TypeError' ||\n errorMessage.includes('Failed to fetch') ||\n errorMessage.includes('ERR_CONNECTION_REFUSED') ||\n errorMessage.includes('NetworkError') ||\n errorMessage.includes('Network request failed') ||\n errorMessage.includes('fetch failed')\n ) {\n return true;\n }\n // Check error cause\n if (error.cause) {\n const causeStr = String(error.cause);\n if (\n causeStr.includes('Failed to fetch') ||\n causeStr.includes('ERR_CONNECTION_REFUSED') ||\n causeStr.includes('NetworkError')\n ) {\n return true;\n }\n }\n return false;\n })();\n\n // Compute status\n // biome-ignore lint: Status determination requires multiple checks\n const status: AuthStatus = (() => {\n if (override) {\n return override.status;\n }\n if (isServer()) {\n return 'loading';\n }\n if (user && session) {\n return 'authenticated';\n }\n // Check for network errors or auth errors first - allow auth page to show\n if (isNetworkError || errorStatus === 401) {\n return 'unauthenticated';\n }\n // If we have an error but it's not a network error, still check loading state\n if (sessionError && !isNetworkError && errorStatus !== 401) {\n if (errorStatus && errorStatus >= 500) {\n return 'authenticated';\n }\n // Other errors mean unauthenticated\n if (isFetched) {\n return 'unauthenticated';\n }\n }\n if (isLoading || !isFetched) {\n return 'loading';\n }\n if (isFetched && !user && !session) {\n return 'unauthenticated';\n }\n return 'unauthenticated';\n })();\n\n const signOutMutation = hooks.useMutation('post', '/sign-out');\n const t = createTranslator(config.messages || {});\n\n const setAuth = (auth: AuthResponse) => {\n setOverride({\n user: auth.user,\n session: auth.session,\n status: 'authenticated',\n error: null,\n });\n };\n\n const clearAuth = () => {\n setOverride({\n user: null,\n session: null,\n status: 'unauthenticated',\n error: null,\n });\n };\n\n const refresh = async () => {\n setOverride(null);\n await refetch();\n };\n\n const signOut = async () => {\n try {\n await signOutMutation.mutateAsync({});\n } finally {\n clearAuth();\n }\n };\n\n return (\n <ConfigContext.Provider value={{ config, cookieName, t }}>\n <ApiContext.Provider value={{ hooks, setAuth, clearAuth, refresh }}>\n <SessionContext.Provider\n value={{\n user,\n session,\n status,\n error,\n isLoading: status === 'loading',\n isAuthenticated: status === 'authenticated',\n refresh,\n signOut,\n }}\n >\n {children}\n </SessionContext.Provider>\n </ApiContext.Provider>\n </ConfigContext.Provider>\n );\n}\n","import type { AuthClientConfig } from '../types';\n\nconst isProduction =\n typeof process !== 'undefined' && process.env.NODE_ENV === 'production';\n\nexport const getSessionCookieName = (config: AuthClientConfig): string => {\n const prefix = config.cookiePrefix || '';\n const baseName = 'session_token';\n if (prefix) {\n return `${prefix}_${baseName}`;\n }\n return isProduction ? '__Host-session_token' : baseName;\n};\n","export const AUTH_ERROR_MAPPING: Record<\n string,\n { title: string; description: string }\n> = {\n USER_NOT_FOUND: {\n title: 'Account Not Found',\n description:\n 'We could not find an account with that identifier. Please check your spelling or sign up.',\n },\n INVALID_PASSWORD: {\n title: 'Invalid Password',\n description: 'The password you entered is incorrect. Please try again.',\n },\n USER_EXISTS: {\n title: 'Account Already Exists',\n description:\n 'An account with this identifier already exists. Please sign in instead.',\n },\n VERIFICATION_EXPIRED: {\n title: 'Verification Expired',\n description:\n 'The verification code or link has expired. Please request a new one.',\n },\n VERIFICATION_MISMATCH: {\n title: 'Invalid Code',\n description:\n 'The verification code you entered is invalid. Please double-check and try again.',\n },\n VERIFICATION_NOT_FOUND: {\n title: 'Verification Not Found',\n description:\n 'We could not find a pending verification request. Please restart the process.',\n },\n TOO_MANY_ATTEMPTS: {\n title: 'Too Many Attempts',\n description:\n 'You have made too many requests recently. Please wait a moment before trying again.',\n },\n REQUIRES_VERIFICATION: {\n title: 'Verification Required',\n description:\n 'You need to verify your account before you can continue. Please check your email or phone.',\n },\n UNAUTHORIZED: {\n title: 'Unauthorized',\n description:\n 'You are not authorized to perform this action. Please sign in again.',\n },\n ACCESS_DENIED: {\n title: 'Access Denied',\n description:\n 'You do not have permission to access this resource. Please contact support if you believe this is an error.',\n },\n HAS_NO_PASSWORD: {\n title: 'No Password Set',\n description:\n 'Your account does not have a password set (e.g. social login). Please sign in with your provider or reset your password.',\n },\n};\n\nexport const validCodes = Object.keys(AUTH_ERROR_MAPPING);\n","import { AUTH_ERROR_MAPPING, validCodes } from '../constants/auth.error.codes';\nimport type { AuthError } from '../types';\n\nexport type AuthErrorContent = {\n title: string;\n description: string;\n};\n\n// Translator function type\ntype TranslatorFunction = (\n key: string,\n params?: Record<string, string | number>,\n) => string;\n\n// Type guard to check if error is an AuthError\nfunction isAuthError(err: unknown): err is AuthError {\n return (\n typeof err === 'object' &&\n err !== null &&\n 'message' in err &&\n typeof (err as { message: unknown }).message === 'string'\n );\n}\n\nfunction extractErrorCode(err: AuthError): string {\n if (err.code && validCodes.includes(err.code)) {\n return err.code;\n }\n if (err.message) {\n const messageUpper = err.message.toUpperCase().trim();\n if (validCodes.includes(messageUpper)) {\n return messageUpper;\n }\n }\n return '';\n}\n\nfunction sanitizeErrorMessage(message: string): string {\n const lowerMessage = message.toLowerCase();\n const isDatabaseError =\n lowerMessage.includes('failed query') ||\n lowerMessage.includes('select') ||\n lowerMessage.includes('insert') ||\n lowerMessage.includes('update') ||\n lowerMessage.includes('delete') ||\n lowerMessage.includes('from') ||\n lowerMessage.includes('where') ||\n lowerMessage.includes('limit') ||\n lowerMessage.includes('params:') ||\n lowerMessage.includes('query') ||\n message.includes('\"iam\".') ||\n message.includes('\"tenants\"') ||\n message.includes('\"users\"') ||\n message.includes('\"sessions\"') ||\n message.includes('\"accounts\"') ||\n lowerMessage.includes('relation') ||\n lowerMessage.includes('column') ||\n lowerMessage.includes('syntax error') ||\n lowerMessage.includes('database') ||\n lowerMessage.includes('postgres') ||\n lowerMessage.includes('sql');\n\n if (isDatabaseError) {\n return 'An error occurred while processing your request';\n }\n\n return message;\n}\n\nfunction handleAuthError(\n err: AuthError,\n setError: (error: AuthErrorContent | null) => void,\n t: TranslatorFunction,\n) {\n const errorCode = extractErrorCode(err);\n\n if (errorCode && AUTH_ERROR_MAPPING[errorCode]) {\n const mapping = AUTH_ERROR_MAPPING[errorCode];\n setError({\n title: mapping.title,\n description: mapping.description,\n });\n return;\n }\n\n const sanitizedMessage = sanitizeErrorMessage(\n err.message || t('errors.fallback'),\n );\n setError({\n title: t('errors.fallback'),\n description: sanitizedMessage,\n });\n}\n\nfunction handleGenericError(\n err: unknown,\n setError: (error: AuthErrorContent | null) => void,\n t: TranslatorFunction,\n) {\n const rawMessage = err instanceof Error ? err.message : t('errors.fallback');\n const sanitizedMessage = sanitizeErrorMessage(rawMessage);\n setError({\n title: 'Error',\n description: sanitizedMessage,\n });\n}\n\nexport const handleError = (\n err: unknown,\n setError: (error: AuthErrorContent | null) => void,\n t: TranslatorFunction,\n) => {\n if (isAuthError(err)) {\n handleAuthError(err, setError, t);\n } else {\n handleGenericError(err, setError, t);\n }\n};\n","'use client';\n\nimport type { ReactNode } from 'react';\n\ntype AuthLayoutProps = {\n title: string;\n description?: string;\n children: ReactNode;\n footer?: ReactNode;\n logoImage?: string;\n};\n\nexport const AuthLayout = ({\n title,\n description,\n children,\n footer,\n logoImage,\n}: AuthLayoutProps) => {\n return (\n <div className=\"space-y-4\">\n <div className=\"flex size-8 mb-6 w-full items-center justify-center rounded-md\">\n {/** biome-ignore lint/performance/noImgElement: logo image */}\n <img src={logoImage || ''} alt=\"Mesob\" width={42} height={42} />\n </div>\n <div className=\"text-center\">\n <h1 className=\"text-2xl font-bold tracking-tight\">{title}</h1>\n {description && (\n <p className=\"mt-2 text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n\n {children}\n\n <div className=\"mt-2 w-full\">\n {footer && (\n <div className=\"w-full text-center text-sm text-muted-foreground\">\n {footer}\n </div>\n )}\n </div>\n </div>\n );\n};\n"],"mappings":"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","names":["useMesob","useState","jsx","jsx","jsxs","useMesob","useState"]}
@@ -1,16 +1,2 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { A as AuthErrorContent } from '../../handle-error-BqDMxnQZ.js';
3
-
4
- type VerificationFormValues = {
5
- code: string;
6
- };
7
- type VerificationFormProps = {
8
- verificationId: string;
9
- onSubmit: (values: VerificationFormValues) => Promise<void> | void;
10
- onResend: () => Promise<void> | void;
11
- isLoading?: boolean;
12
- error?: AuthErrorContent | string | null;
13
- };
14
- declare const VerificationForm: ({ onSubmit, onResend, isLoading, }: VerificationFormProps) => react_jsx_runtime.JSX.Element;
15
-
16
- export { VerificationForm };
1
+ import 'react/jsx-runtime';
2
+ export { V as VerificationForm } from '../../verification-form-ipSRTtQB.js';
@@ -13,6 +13,9 @@ import { Spinner as Spinner2 } from "@mesob/ui/components/spinner";
13
13
  import { Controller, useForm } from "react-hook-form";
14
14
  import { z } from "zod";
15
15
 
16
+ // src/hooks/use-translator.ts
17
+ import { useMesob } from "@mesob/ui/components/mesob-context";
18
+
16
19
  // src/lib/translations.ts
17
20
  function createTranslator(messages, namespace) {
18
21
  return (key, params) => {
@@ -44,7 +47,12 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
44
47
  import { deepmerge } from "deepmerge-ts";
45
48
  import createFetchClient from "openapi-fetch";
46
49
  import createClient from "openapi-react-query";
47
- import { createContext, useContext, useEffect, useState } from "react";
50
+ import { createContext, useContext, useMemo, useState } from "react";
51
+
52
+ // src/utils/cookie.ts
53
+ var isProduction = typeof process !== "undefined" && process.env.NODE_ENV === "production";
54
+
55
+ // src/provider.tsx
48
56
  import { jsx } from "react/jsx-runtime";
49
57
  var SessionContext = createContext(null);
50
58
  var ApiContext = createContext(null);
@@ -52,9 +60,6 @@ var ConfigContext = createContext(null);
52
60
  var queryClient = new QueryClient({
53
61
  defaultOptions: {
54
62
  queries: {
55
- staleTime: 1e3 * 60 * 5,
56
- gcTime: 1e3 * 60 * 10,
57
- retry: 1,
58
63
  refetchOnWindowFocus: false
59
64
  }
60
65
  }
@@ -69,14 +74,18 @@ function useConfig() {
69
74
 
70
75
  // src/hooks/use-translator.ts
71
76
  function useTranslator(namespace) {
77
+ const mesob = useMesob();
72
78
  const { config } = useConfig();
79
+ if (mesob?.t) {
80
+ return (key, params) => mesob.t(namespace ? `${namespace}.${key}` : key, params);
81
+ }
73
82
  return createTranslator(config.messages || {}, namespace);
74
83
  }
75
84
 
76
85
  // src/components/auth/countdown.tsx
77
86
  import { Button } from "@mesob/ui/components/button";
78
87
  import { Spinner } from "@mesob/ui/components/spinner";
79
- import { useEffect as useEffect2, useState as useState2 } from "react";
88
+ import { useEffect, useState as useState2 } from "react";
80
89
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
81
90
  var Countdown = ({
82
91
  initialSeconds = 60,
@@ -86,7 +95,7 @@ var Countdown = ({
86
95
  const t = useTranslator("Common");
87
96
  const [seconds, setSeconds] = useState2(initialSeconds);
88
97
  const [isResending, setIsResending] = useState2(false);
89
- useEffect2(() => {
98
+ useEffect(() => {
90
99
  if (seconds <= 0) {
91
100
  return;
92
101
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/auth/verification-form.tsx","../../../src/lib/translations.ts","../../../src/provider.tsx","../../../src/hooks/use-translator.ts","../../../src/components/auth/countdown.tsx"],"sourcesContent":["'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { Button } from '@mesob/ui/components/button';\nimport { Field, FieldError, FieldGroup } from '@mesob/ui/components/field';\nimport {\n InputOTP,\n InputOTPGroup,\n InputOTPSlot,\n} from '@mesob/ui/components/input-otp';\nimport { Spinner } from '@mesob/ui/components/spinner';\nimport { Controller, useForm } from 'react-hook-form';\nimport { z } from 'zod';\nimport { useTranslator } from '../../hooks/use-translator';\nimport type { AuthErrorContent } from '../../utils/handle-error';\nimport { Countdown } from './countdown';\n\ntype VerificationFormValues = {\n code: string;\n};\n\ntype VerificationFormProps = {\n verificationId: string;\n onSubmit: (values: VerificationFormValues) => Promise<void> | void;\n onResend: () => Promise<void> | void;\n isLoading?: boolean;\n error?: AuthErrorContent | string | null;\n};\n\nconst verificationSchema = (t: (key: string) => string) =>\n z.object({\n code: z.string().length(6, t('form.codeLength')),\n });\n\nexport const VerificationForm = ({\n onSubmit,\n onResend,\n isLoading = false,\n}: VerificationFormProps) => {\n const t = useTranslator('Auth.verification');\n const form = useForm<VerificationFormValues>({\n resolver: zodResolver(verificationSchema(t)),\n defaultValues: {\n code: '',\n },\n });\n\n const handleSubmit = form.handleSubmit(async (values) => {\n await onSubmit(values);\n });\n\n return (\n <form id=\"verification-form\" onSubmit={handleSubmit}>\n <FieldGroup>\n <Controller\n name=\"code\"\n control={form.control}\n render={({ field, fieldState }) => (\n <Field data-invalid={fieldState.invalid}>\n <div className=\"flex justify-center\">\n <InputOTP\n maxLength={6}\n id=\"otp\"\n required\n value={field.value ?? ''}\n onChange={field.onChange}\n onBlur={field.onBlur}\n containerClassName=\"gap-4 justify-center mb-2 flex items-center\"\n aria-invalid={fieldState.invalid}\n >\n <InputOTPGroup className=\"gap-3 *:data-[slot=input-otp-slot]:h-12 *:data-[slot=input-otp-slot]:w-12 *:data-[slot=input-otp-slot]:rounded-md *:data-[slot=input-otp-slot]:border *:data-[slot=input-otp-slot]:text-xl\">\n <InputOTPSlot className=\"h-12\" index={0} />\n <InputOTPSlot className=\"h-12\" index={1} />\n <InputOTPSlot className=\"h-12\" index={2} />\n <InputOTPSlot className=\"h-12\" index={3} />\n <InputOTPSlot className=\"h-12\" index={4} />\n <InputOTPSlot className=\"h-12\" index={5} />\n </InputOTPGroup>\n </InputOTP>\n </div>\n {fieldState.invalid && <FieldError errors={[fieldState.error]} />}\n </Field>\n )}\n />\n </FieldGroup>\n <div className=\"flex justify-between items-center mt-4\">\n <Countdown onResend={onResend} resending={isLoading} />\n <Button\n type=\"submit\"\n form=\"verification-form\"\n disabled={isLoading || form.watch('code').length !== 6}\n >\n {isLoading && <Spinner />}\n {t('form.confirm')}\n </Button>\n </div>\n </form>\n );\n};\n","type Messages = Record<string, unknown>;\n\nexport function createTranslator(messages: Messages, namespace?: string) {\n return (key: string, params?: Record<string, string | number>): string => {\n const fullKey = namespace ? `${namespace}.${key}` : key;\n const keys = fullKey.split('.');\n\n let value: unknown = messages;\n for (const k of keys) {\n if (value && typeof value === 'object' && value !== null) {\n value = (value as Record<string, unknown>)[k];\n } else {\n return fullKey;\n }\n }\n\n if (typeof value !== 'string') {\n return fullKey;\n }\n\n // Simple parameter replacement\n if (params) {\n return value.replace(/\\{(\\w+)\\}/g, (_, param) =>\n String(params[param] ?? `{${param}}`),\n );\n }\n\n return value;\n };\n}\n","'use client';\n\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { deepmerge } from 'deepmerge-ts';\nimport createFetchClient from 'openapi-fetch';\nimport createClient from 'openapi-react-query';\nimport type { ReactNode } from 'react';\nimport { createContext, useContext, useEffect, useState } from 'react';\nimport type { paths } from './data/openapi';\nimport { createTranslator } from './lib/translations';\nimport {\n type AuthClientConfig,\n type AuthResponse,\n defaultAuthClientConfig,\n type Session,\n type User,\n} from './types';\nimport { createCustomFetch } from './utils/custom-fetch';\n\ntype OpenApiHooks = any;\n\ntype SessionState = {\n user: User | null;\n session: Session | null;\n isLoading: boolean;\n isAuthenticated: boolean;\n error: Error | null;\n};\n\ntype SessionContextValue = SessionState & {\n refresh: () => Promise<void>;\n signOut: () => Promise<void>;\n};\n\ntype ApiContextValue = {\n hooks: OpenApiHooks;\n setAuth: (auth: AuthResponse) => void;\n clearAuth: () => void;\n refresh: () => Promise<void>;\n};\n\ntype ConfigContextValue = {\n config: AuthClientConfig;\n t: (key: string, params?: Record<string, string | number>) => string;\n};\n\nconst SessionContext = createContext<SessionContextValue | null>(null);\nconst ApiContext = createContext<ApiContextValue | null>(null);\nconst ConfigContext = createContext<ConfigContextValue | null>(null);\n\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 1000 * 60 * 5,\n gcTime: 1000 * 60 * 10,\n retry: 1,\n refetchOnWindowFocus: false,\n },\n },\n});\n\nexport function useSession() {\n const context = useContext(SessionContext);\n if (!context) {\n throw new Error('useSession must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useApi() {\n const context = useContext(ApiContext);\n if (!context) {\n throw new Error('useApi must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useConfig() {\n const context = useContext(ConfigContext);\n if (!context) {\n throw new Error('useConfig must be used within MesobAuthProvider');\n }\n return context;\n}\n\ntype MesobAuthProviderProps = {\n config: AuthClientConfig;\n children: ReactNode;\n};\n\nexport function MesobAuthProvider({\n config,\n children,\n}: MesobAuthProviderProps) {\n const mergedConfig = deepmerge(\n { ...defaultAuthClientConfig } as Partial<AuthClientConfig>,\n config,\n ) as AuthClientConfig;\n\n const api = createFetchClient<paths>({\n baseUrl: mergedConfig.baseURL,\n fetch: createCustomFetch(mergedConfig),\n });\n\n const hooks = createClient(api);\n\n return (\n <QueryClientProvider client={queryClient}>\n <AuthStateProvider config={mergedConfig} hooks={hooks}>\n {children}\n </AuthStateProvider>\n </QueryClientProvider>\n );\n}\n\ntype AuthStateProviderProps = {\n config: AuthClientConfig;\n hooks: OpenApiHooks;\n children: ReactNode;\n};\n\nfunction AuthStateProvider({\n config,\n hooks,\n children,\n}: AuthStateProviderProps) {\n const [authState, setAuthState] = useState<{\n user: User | null;\n session: Session | null;\n isLoading: boolean;\n error: Error | null;\n }>({\n user: null,\n session: null,\n isLoading: false,\n error: null,\n });\n\n const {\n data: sessionData,\n isLoading: sessionLoading,\n error: sessionError,\n refetch,\n } = hooks.useQuery(\n 'get',\n '/session',\n {},\n {\n enabled: true,\n refetchOnMount: true,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n retry: false,\n },\n );\n\n useEffect(() => {\n if (sessionLoading) {\n setAuthState((prev) => ({ ...prev, isLoading: true }));\n return;\n }\n\n if (sessionError) {\n setAuthState({\n user: null,\n session: null,\n isLoading: false,\n error: sessionError as Error,\n });\n return;\n }\n\n if (sessionData) {\n setAuthState({\n user: sessionData.user,\n session: sessionData.session,\n isLoading: false,\n error: null,\n });\n return;\n }\n\n setAuthState({\n user: null,\n session: null,\n isLoading: false,\n error: null,\n });\n }, [sessionData, sessionLoading, sessionError]);\n\n const refresh = async () => {\n await refetch();\n };\n\n const setAuth = (auth: AuthResponse) => {\n setAuthState({\n user: auth.user,\n session: auth.session,\n isLoading: false,\n error: null,\n });\n };\n\n const clearAuth = () => {\n setAuthState({\n user: null,\n session: null,\n isLoading: false,\n error: null,\n });\n };\n\n const signOutMutation = hooks.useMutation('post', '/sign-out');\n\n const signOut = async () => {\n try {\n await signOutMutation.mutateAsync({});\n } finally {\n clearAuth();\n }\n };\n\n const t = createTranslator(config.messages || {});\n\n return (\n <ConfigContext.Provider value={{ config, t }}>\n <ApiContext.Provider value={{ hooks, setAuth, clearAuth, refresh }}>\n <SessionContext.Provider\n value={{\n user: authState.user,\n session: authState.session,\n isLoading: authState.isLoading,\n isAuthenticated: !!authState.user && !!authState.session,\n error: authState.error,\n refresh,\n signOut,\n }}\n >\n {children}\n </SessionContext.Provider>\n </ApiContext.Provider>\n </ConfigContext.Provider>\n );\n}\n","import { createTranslator } from '../lib/translations';\nimport { useConfig } from '../provider';\n\nexport function useTranslator(namespace?: string) {\n const { config } = useConfig();\n return createTranslator(config.messages || {}, namespace);\n}\n","'use client';\n\nimport { Button } from '@mesob/ui/components/button';\nimport { Spinner } from '@mesob/ui/components/spinner';\nimport { useEffect, useState } from 'react';\nimport { useTranslator } from '../../hooks/use-translator';\n\ntype CountdownProps = {\n initialSeconds?: number;\n onResend: () => Promise<void> | void;\n resending?: boolean;\n};\n\nexport const Countdown = ({\n initialSeconds = 60,\n onResend,\n resending = false,\n}: CountdownProps) => {\n const t = useTranslator('Common');\n const [seconds, setSeconds] = useState(initialSeconds);\n const [isResending, setIsResending] = useState(false);\n\n useEffect(() => {\n if (seconds <= 0) {\n return;\n }\n\n const timer = setInterval(() => {\n setSeconds((prev) => {\n if (prev <= 1) {\n clearInterval(timer);\n return 0;\n }\n return prev - 1;\n });\n }, 1000);\n\n return () => clearInterval(timer);\n }, [seconds]);\n\n const handleResend = async () => {\n setIsResending(true);\n try {\n await onResend();\n setSeconds(initialSeconds);\n } catch (_error) {\n // Error handling is done by parent\n } finally {\n setIsResending(false);\n }\n };\n\n if (seconds > 0) {\n return (\n <Button variant=\"ghost\" disabled>\n {t('resendIn', { seconds })}\n </Button>\n );\n }\n\n return (\n <Button\n variant=\"ghost\"\n onClick={handleResend}\n disabled={isResending || resending}\n >\n {isResending || (resending && <Spinner />)}\n {t('resend')}\n </Button>\n );\n};\n"],"mappings":"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","names":["Button","Spinner","useEffect","useState","jsx","useState","useEffect","jsx","jsxs","Button","Spinner"]}
1
+ {"version":3,"sources":["../../../src/components/auth/verification-form.tsx","../../../src/hooks/use-translator.ts","../../../src/lib/translations.ts","../../../src/provider.tsx","../../../src/utils/cookie.ts","../../../src/components/auth/countdown.tsx"],"sourcesContent":["'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { Button } from '@mesob/ui/components/button';\nimport { Field, FieldError, FieldGroup } from '@mesob/ui/components/field';\nimport {\n InputOTP,\n InputOTPGroup,\n InputOTPSlot,\n} from '@mesob/ui/components/input-otp';\nimport { Spinner } from '@mesob/ui/components/spinner';\nimport { Controller, useForm } from 'react-hook-form';\nimport { z } from 'zod';\nimport { useTranslator } from '../../hooks/use-translator';\nimport type { AuthErrorContent } from '../../utils/handle-error';\nimport { Countdown } from './countdown';\n\ntype VerificationFormValues = {\n code: string;\n};\n\ntype VerificationFormProps = {\n verificationId: string;\n onSubmit: (values: VerificationFormValues) => Promise<void> | void;\n onResend: () => Promise<void> | void;\n isLoading?: boolean;\n error?: AuthErrorContent | string | null;\n};\n\nconst verificationSchema = (t: (key: string) => string) =>\n z.object({\n code: z.string().length(6, t('form.codeLength')),\n });\n\nexport const VerificationForm = ({\n onSubmit,\n onResend,\n isLoading = false,\n}: VerificationFormProps) => {\n const t = useTranslator('Auth.verification');\n const form = useForm<VerificationFormValues>({\n resolver: zodResolver(verificationSchema(t)),\n defaultValues: {\n code: '',\n },\n });\n\n const handleSubmit = form.handleSubmit(async (values) => {\n await onSubmit(values);\n });\n\n return (\n <form id=\"verification-form\" onSubmit={handleSubmit}>\n <FieldGroup>\n <Controller\n name=\"code\"\n control={form.control}\n render={({ field, fieldState }) => (\n <Field data-invalid={fieldState.invalid}>\n <div className=\"flex justify-center\">\n <InputOTP\n maxLength={6}\n id=\"otp\"\n required\n value={field.value ?? ''}\n onChange={field.onChange}\n onBlur={field.onBlur}\n containerClassName=\"gap-4 justify-center mb-2 flex items-center\"\n aria-invalid={fieldState.invalid}\n >\n <InputOTPGroup className=\"gap-3 *:data-[slot=input-otp-slot]:h-12 *:data-[slot=input-otp-slot]:w-12 *:data-[slot=input-otp-slot]:rounded-md *:data-[slot=input-otp-slot]:border *:data-[slot=input-otp-slot]:text-xl\">\n <InputOTPSlot className=\"h-12\" index={0} />\n <InputOTPSlot className=\"h-12\" index={1} />\n <InputOTPSlot className=\"h-12\" index={2} />\n <InputOTPSlot className=\"h-12\" index={3} />\n <InputOTPSlot className=\"h-12\" index={4} />\n <InputOTPSlot className=\"h-12\" index={5} />\n </InputOTPGroup>\n </InputOTP>\n </div>\n {fieldState.invalid && <FieldError errors={[fieldState.error]} />}\n </Field>\n )}\n />\n </FieldGroup>\n <div className=\"flex justify-between items-center mt-4\">\n <Countdown onResend={onResend} resending={isLoading} />\n <Button\n type=\"submit\"\n form=\"verification-form\"\n disabled={isLoading || form.watch('code').length !== 6}\n >\n {isLoading && <Spinner />}\n {t('form.confirm')}\n </Button>\n </div>\n </form>\n );\n};\n","import { useMesob } from '@mesob/ui/components/mesob-context';\nimport { createTranslator } from '../lib/translations';\nimport { useConfig } from '../provider';\n\nexport function useTranslator(namespace?: string) {\n const mesob = useMesob();\n const { config } = useConfig();\n\n if (mesob?.t) {\n return (key: string, params?: Record<string, string | number>) =>\n mesob.t!(namespace ? `${namespace}.${key}` : key, params);\n }\n\n return createTranslator(config.messages || {}, namespace);\n}\n","type Messages = Record<string, unknown>;\n\nexport function createTranslator(messages: Messages, namespace?: string) {\n return (key: string, params?: Record<string, string | number>): string => {\n const fullKey = namespace ? `${namespace}.${key}` : key;\n const keys = fullKey.split('.');\n\n let value: unknown = messages;\n for (const k of keys) {\n if (value && typeof value === 'object' && value !== null) {\n value = (value as Record<string, unknown>)[k];\n } else {\n return fullKey;\n }\n }\n\n if (typeof value !== 'string') {\n return fullKey;\n }\n\n // Simple parameter replacement\n if (params) {\n return value.replace(/\\{(\\w+)\\}/g, (_, param) =>\n String(params[param] ?? `{${param}}`),\n );\n }\n\n return value;\n };\n}\n","'use client';\n\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { deepmerge } from 'deepmerge-ts';\nimport createFetchClient from 'openapi-fetch';\nimport createClient from 'openapi-react-query';\nimport type { ReactNode } from 'react';\nimport { createContext, useContext, useMemo, useState } from 'react';\nimport type { paths } from './data/openapi';\nimport { createTranslator } from './lib/translations';\nimport {\n type AuthClientConfig,\n type AuthResponse,\n defaultAuthClientConfig,\n type Session,\n type User,\n} from './types';\nimport { getSessionCookieName } from './utils/cookie';\nimport { createCustomFetch } from './utils/custom-fetch';\n\n// biome-ignore lint/suspicious/noExplicitAny: OpenAPI hooks type\ntype OpenApiHooks = any;\n\n// --- Utility: Check if running on server ---\nfunction isServer(): boolean {\n return typeof document === 'undefined';\n}\n\n/**\n * @deprecated Cookie is httpOnly and cannot be read client-side.\n * Use `useSession().isAuthenticated` instead.\n * This function always returns false on client.\n */\nexport function hasAuthCookie(_cookieName: string): boolean {\n // Cookie is httpOnly, can't check client-side\n // Always return false - use useSession() for auth status\n return false;\n}\n\n// --- Types ---\nexport type AuthStatus = 'loading' | 'authenticated' | 'unauthenticated';\n\ntype AuthState = {\n user: User | null;\n session: Session | null;\n status: AuthStatus;\n error: Error | null;\n};\n\ntype SessionContextValue = AuthState & {\n isLoading: boolean;\n isAuthenticated: boolean;\n refresh: () => Promise<void>;\n signOut: () => Promise<void>;\n};\n\ntype ApiContextValue = {\n hooks: OpenApiHooks;\n setAuth: (auth: AuthResponse) => void;\n clearAuth: () => void;\n refresh: () => Promise<void>;\n};\n\ntype ConfigContextValue = {\n config: AuthClientConfig;\n cookieName: string;\n t: (key: string, params?: Record<string, string | number>) => string;\n};\n\nconst SessionContext = createContext<SessionContextValue | null>(null);\nconst ApiContext = createContext<ApiContextValue | null>(null);\nconst ConfigContext = createContext<ConfigContextValue | null>(null);\n\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n refetchOnWindowFocus: false,\n },\n },\n});\n\n// --- Hooks ---\n\n/**\n * Get session state including user, session, and auth status.\n * - `status`: 'loading' | 'authenticated' | 'unauthenticated'\n * - `isLoading`: true while fetching session\n * - `isAuthenticated`: true if user and session exist\n */\nexport function useSession(): SessionContextValue {\n const context = useContext(SessionContext);\n if (!context) {\n throw new Error('useSession must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useApi(): ApiContextValue {\n const context = useContext(ApiContext);\n if (!context) {\n throw new Error('useApi must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useConfig(): ConfigContextValue {\n const context = useContext(ConfigContext);\n if (!context) {\n throw new Error('useConfig must be used within MesobAuthProvider');\n }\n return context;\n}\n\n/**\n * @deprecated Cookie is httpOnly, can't be checked client-side.\n * Use `useSession().isAuthenticated` instead.\n */\nexport function useHasAuthCookie(): boolean {\n const { status } = useSession();\n return status === 'authenticated' || status === 'loading';\n}\n\n// --- Provider ---\n\ntype MesobAuthProviderProps = {\n config: AuthClientConfig;\n children: ReactNode;\n};\n\nexport function MesobAuthProvider({\n config,\n children,\n}: MesobAuthProviderProps) {\n const mergedConfig = useMemo(\n () =>\n deepmerge(\n { ...defaultAuthClientConfig } as Partial<AuthClientConfig>,\n config,\n ) as AuthClientConfig,\n [config],\n );\n\n const api = useMemo(\n () =>\n createFetchClient<paths>({\n baseUrl: mergedConfig.baseURL,\n fetch: createCustomFetch(mergedConfig),\n }),\n [mergedConfig],\n );\n\n const hooks = useMemo(() => createClient(api), [api]);\n const cookieName = useMemo(\n () => getSessionCookieName(mergedConfig),\n [mergedConfig],\n );\n\n return (\n <QueryClientProvider client={queryClient}>\n <AuthStateProvider\n config={mergedConfig}\n hooks={hooks}\n cookieName={cookieName}\n >\n {children}\n </AuthStateProvider>\n </QueryClientProvider>\n );\n}\n\ntype AuthStateProviderProps = {\n config: AuthClientConfig;\n hooks: OpenApiHooks;\n cookieName: string;\n children: ReactNode;\n};\n\nfunction AuthStateProvider({\n config,\n hooks,\n cookieName,\n children,\n}: AuthStateProviderProps) {\n // Manual override for sign-out / sign-in\n const [override, setOverride] = useState<AuthState | null>(null);\n\n // Always fetch session - cookie is httpOnly, can't check client-side\n // Server will read the cookie and return user/session if valid\n const {\n data: sessionData,\n isLoading,\n isFetched,\n error: sessionError,\n refetch,\n } = hooks.useQuery(\n 'get',\n '/session',\n {},\n {\n enabled: !(override || isServer()),\n refetchOnMount: false,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n retry: false,\n gcTime: 0,\n staleTime: 0,\n },\n );\n\n // Derive state directly - no useEffect\n const user = override?.user ?? sessionData?.user ?? null;\n const session = override?.session ?? sessionData?.session ?? null;\n const error = override?.error ?? (sessionError as Error | null);\n\n // Check error status code\n const errorStatus = (() => {\n if (!sessionError) {\n return null;\n }\n const err = sessionError as { status?: number };\n return err.status ?? null;\n })();\n\n // Check if error is a network/connection error\n const isNetworkError = (() => {\n if (!sessionError) {\n return false;\n }\n const error = sessionError as Error & { cause?: unknown; data?: unknown };\n const errorMessage =\n error.message || String(error) || JSON.stringify(error);\n // Network errors: TypeError, DOMException, or fetch failures\n if (\n error instanceof TypeError ||\n error instanceof DOMException ||\n error.name === 'TypeError' ||\n errorMessage.includes('Failed to fetch') ||\n errorMessage.includes('ERR_CONNECTION_REFUSED') ||\n errorMessage.includes('NetworkError') ||\n errorMessage.includes('Network request failed') ||\n errorMessage.includes('fetch failed')\n ) {\n return true;\n }\n // Check error cause\n if (error.cause) {\n const causeStr = String(error.cause);\n if (\n causeStr.includes('Failed to fetch') ||\n causeStr.includes('ERR_CONNECTION_REFUSED') ||\n causeStr.includes('NetworkError')\n ) {\n return true;\n }\n }\n return false;\n })();\n\n // Compute status\n // biome-ignore lint: Status determination requires multiple checks\n const status: AuthStatus = (() => {\n if (override) {\n return override.status;\n }\n if (isServer()) {\n return 'loading';\n }\n if (user && session) {\n return 'authenticated';\n }\n // Check for network errors or auth errors first - allow auth page to show\n if (isNetworkError || errorStatus === 401) {\n return 'unauthenticated';\n }\n // If we have an error but it's not a network error, still check loading state\n if (sessionError && !isNetworkError && errorStatus !== 401) {\n if (errorStatus && errorStatus >= 500) {\n return 'authenticated';\n }\n // Other errors mean unauthenticated\n if (isFetched) {\n return 'unauthenticated';\n }\n }\n if (isLoading || !isFetched) {\n return 'loading';\n }\n if (isFetched && !user && !session) {\n return 'unauthenticated';\n }\n return 'unauthenticated';\n })();\n\n const signOutMutation = hooks.useMutation('post', '/sign-out');\n const t = createTranslator(config.messages || {});\n\n const setAuth = (auth: AuthResponse) => {\n setOverride({\n user: auth.user,\n session: auth.session,\n status: 'authenticated',\n error: null,\n });\n };\n\n const clearAuth = () => {\n setOverride({\n user: null,\n session: null,\n status: 'unauthenticated',\n error: null,\n });\n };\n\n const refresh = async () => {\n setOverride(null);\n await refetch();\n };\n\n const signOut = async () => {\n try {\n await signOutMutation.mutateAsync({});\n } finally {\n clearAuth();\n }\n };\n\n return (\n <ConfigContext.Provider value={{ config, cookieName, t }}>\n <ApiContext.Provider value={{ hooks, setAuth, clearAuth, refresh }}>\n <SessionContext.Provider\n value={{\n user,\n session,\n status,\n error,\n isLoading: status === 'loading',\n isAuthenticated: status === 'authenticated',\n refresh,\n signOut,\n }}\n >\n {children}\n </SessionContext.Provider>\n </ApiContext.Provider>\n </ConfigContext.Provider>\n );\n}\n","import type { AuthClientConfig } from '../types';\n\nconst isProduction =\n typeof process !== 'undefined' && process.env.NODE_ENV === 'production';\n\nexport const getSessionCookieName = (config: AuthClientConfig): string => {\n const prefix = config.cookiePrefix || '';\n const baseName = 'session_token';\n if (prefix) {\n return `${prefix}_${baseName}`;\n }\n return isProduction ? '__Host-session_token' : baseName;\n};\n","'use client';\n\nimport { Button } from '@mesob/ui/components/button';\nimport { Spinner } from '@mesob/ui/components/spinner';\nimport { useEffect, useState } from 'react';\nimport { useTranslator } from '../../hooks/use-translator';\n\ntype CountdownProps = {\n initialSeconds?: number;\n onResend: () => Promise<void> | void;\n resending?: boolean;\n};\n\nexport const Countdown = ({\n initialSeconds = 60,\n onResend,\n resending = false,\n}: CountdownProps) => {\n const t = useTranslator('Common');\n const [seconds, setSeconds] = useState(initialSeconds);\n const [isResending, setIsResending] = useState(false);\n\n useEffect(() => {\n if (seconds <= 0) {\n return;\n }\n\n const timer = setInterval(() => {\n setSeconds((prev) => {\n if (prev <= 1) {\n clearInterval(timer);\n return 0;\n }\n return prev - 1;\n });\n }, 1000);\n\n return () => clearInterval(timer);\n }, [seconds]);\n\n const handleResend = async () => {\n setIsResending(true);\n try {\n await onResend();\n setSeconds(initialSeconds);\n } catch (_error) {\n // Error handling is done by parent\n } finally {\n setIsResending(false);\n }\n };\n\n if (seconds > 0) {\n return (\n <Button variant=\"ghost\" disabled>\n {t('resendIn', { seconds })}\n </Button>\n );\n }\n\n return (\n <Button\n variant=\"ghost\"\n onClick={handleResend}\n disabled={isResending || resending}\n >\n {isResending || (resending && <Spinner />)}\n {t('resend')}\n </Button>\n );\n};\n"],"mappings":";;;AAEA,SAAS,mBAAmB;AAC5B,SAAS,UAAAA,eAAc;AACvB,SAAS,OAAO,YAAY,kBAAkB;AAC9C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,WAAAC,gBAAe;AACxB,SAAS,YAAY,eAAe;AACpC,SAAS,SAAS;;;ACZlB,SAAS,gBAAgB;;;ACElB,SAAS,iBAAiB,UAAoB,WAAoB;AACvE,SAAO,CAAC,KAAa,WAAqD;AACxE,UAAM,UAAU,YAAY,GAAG,SAAS,IAAI,GAAG,KAAK;AACpD,UAAM,OAAO,QAAQ,MAAM,GAAG;AAE9B,QAAI,QAAiB;AACrB,eAAW,KAAK,MAAM;AACpB,UAAI,SAAS,OAAO,UAAU,YAAY,UAAU,MAAM;AACxD,gBAAS,MAAkC,CAAC;AAAA,MAC9C,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO;AAAA,IACT;AAGA,QAAI,QAAQ;AACV,aAAO,MAAM;AAAA,QAAQ;AAAA,QAAc,CAAC,GAAG,UACrC,OAAO,OAAO,KAAK,KAAK,IAAI,KAAK,GAAG;AAAA,MACtC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;AC3BA,SAAS,aAAa,2BAA2B;AACjD,SAAS,iBAAiB;AAC1B,OAAO,uBAAuB;AAC9B,OAAO,kBAAkB;AAEzB,SAAS,eAAe,YAAY,SAAS,gBAAgB;;;ACL7D,IAAM,eACJ,OAAO,YAAY,eAAe,QAAQ,IAAI,aAAa;;;AD4JvD;AA1FN,IAAM,iBAAiB,cAA0C,IAAI;AACrE,IAAM,aAAa,cAAsC,IAAI;AAC7D,IAAM,gBAAgB,cAAyC,IAAI;AAEnE,IAAM,cAAc,IAAI,YAAY;AAAA,EAClC,gBAAgB;AAAA,IACd,SAAS;AAAA,MACP,sBAAsB;AAAA,IACxB;AAAA,EACF;AACF,CAAC;AA0BM,SAAS,YAAgC;AAC9C,QAAM,UAAU,WAAW,aAAa;AACxC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AACA,SAAO;AACT;;;AF3GO,SAAS,cAAc,WAAoB;AAChD,QAAM,QAAQ,SAAS;AACvB,QAAM,EAAE,OAAO,IAAI,UAAU;AAE7B,MAAI,OAAO,GAAG;AACZ,WAAO,CAAC,KAAa,WACnB,MAAM,EAAG,YAAY,GAAG,SAAS,IAAI,GAAG,KAAK,KAAK,MAAM;AAAA,EAC5D;AAEA,SAAO,iBAAiB,OAAO,YAAY,CAAC,GAAG,SAAS;AAC1D;;;AIZA,SAAS,cAAc;AACvB,SAAS,eAAe;AACxB,SAAS,WAAW,YAAAC,iBAAgB;AAkD9B,gBAAAC,MAOF,YAPE;AAzCC,IAAM,YAAY,CAAC;AAAA,EACxB,iBAAiB;AAAA,EACjB;AAAA,EACA,YAAY;AACd,MAAsB;AACpB,QAAM,IAAI,cAAc,QAAQ;AAChC,QAAM,CAAC,SAAS,UAAU,IAAIC,UAAS,cAAc;AACrD,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,KAAK;AAEpD,YAAU,MAAM;AACd,QAAI,WAAW,GAAG;AAChB;AAAA,IACF;AAEA,UAAM,QAAQ,YAAY,MAAM;AAC9B,iBAAW,CAAC,SAAS;AACnB,YAAI,QAAQ,GAAG;AACb,wBAAc,KAAK;AACnB,iBAAO;AAAA,QACT;AACA,eAAO,OAAO;AAAA,MAChB,CAAC;AAAA,IACH,GAAG,GAAI;AAEP,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,eAAe,YAAY;AAC/B,mBAAe,IAAI;AACnB,QAAI;AACF,YAAM,SAAS;AACf,iBAAW,cAAc;AAAA,IAC3B,SAAS,QAAQ;AAAA,IAEjB,UAAE;AACA,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,UAAU,GAAG;AACf,WACE,gBAAAD,KAAC,UAAO,SAAQ,SAAQ,UAAQ,MAC7B,YAAE,YAAY,EAAE,QAAQ,CAAC,GAC5B;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU,eAAe;AAAA,MAExB;AAAA,uBAAgB,aAAa,gBAAAA,KAAC,WAAQ;AAAA,QACtC,EAAE,QAAQ;AAAA;AAAA;AAAA,EACb;AAEJ;;;ALAkB,SACE,OAAAE,MADF,QAAAC,aAAA;AAzClB,IAAM,qBAAqB,CAAC,MAC1B,EAAE,OAAO;AAAA,EACP,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,iBAAiB,CAAC;AACjD,CAAC;AAEI,IAAM,mBAAmB,CAAC;AAAA,EAC/B;AAAA,EACA;AAAA,EACA,YAAY;AACd,MAA6B;AAC3B,QAAM,IAAI,cAAc,mBAAmB;AAC3C,QAAM,OAAO,QAAgC;AAAA,IAC3C,UAAU,YAAY,mBAAmB,CAAC,CAAC;AAAA,IAC3C,eAAe;AAAA,MACb,MAAM;AAAA,IACR;AAAA,EACF,CAAC;AAED,QAAM,eAAe,KAAK,aAAa,OAAO,WAAW;AACvD,UAAM,SAAS,MAAM;AAAA,EACvB,CAAC;AAED,SACE,gBAAAA,MAAC,UAAK,IAAG,qBAAoB,UAAU,cACrC;AAAA,oBAAAD,KAAC,cACC,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,KAAK;AAAA,QACd,QAAQ,CAAC,EAAE,OAAO,WAAW,MAC3B,gBAAAC,MAAC,SAAM,gBAAc,WAAW,SAC9B;AAAA,0BAAAD,KAAC,SAAI,WAAU,uBACb,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW;AAAA,cACX,IAAG;AAAA,cACH,UAAQ;AAAA,cACR,OAAO,MAAM,SAAS;AAAA,cACtB,UAAU,MAAM;AAAA,cAChB,QAAQ,MAAM;AAAA,cACd,oBAAmB;AAAA,cACnB,gBAAc,WAAW;AAAA,cAEzB,0BAAAC,MAAC,iBAAc,WAAU,8LACvB;AAAA,gCAAAD,KAAC,gBAAa,WAAU,QAAO,OAAO,GAAG;AAAA,gBACzC,gBAAAA,KAAC,gBAAa,WAAU,QAAO,OAAO,GAAG;AAAA,gBACzC,gBAAAA,KAAC,gBAAa,WAAU,QAAO,OAAO,GAAG;AAAA,gBACzC,gBAAAA,KAAC,gBAAa,WAAU,QAAO,OAAO,GAAG;AAAA,gBACzC,gBAAAA,KAAC,gBAAa,WAAU,QAAO,OAAO,GAAG;AAAA,gBACzC,gBAAAA,KAAC,gBAAa,WAAU,QAAO,OAAO,GAAG;AAAA,iBAC3C;AAAA;AAAA,UACF,GACF;AAAA,UACC,WAAW,WAAW,gBAAAA,KAAC,cAAW,QAAQ,CAAC,WAAW,KAAK,GAAG;AAAA,WACjE;AAAA;AAAA,IAEJ,GACF;AAAA,IACA,gBAAAC,MAAC,SAAI,WAAU,0CACb;AAAA,sBAAAD,KAAC,aAAU,UAAoB,WAAW,WAAW;AAAA,MACrD,gBAAAC;AAAA,QAACC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,MAAK;AAAA,UACL,UAAU,aAAa,KAAK,MAAM,MAAM,EAAE,WAAW;AAAA,UAEpD;AAAA,yBAAa,gBAAAF,KAACG,UAAA,EAAQ;AAAA,YACtB,EAAE,cAAc;AAAA;AAAA;AAAA,MACnB;AAAA,OACF;AAAA,KACF;AAEJ;","names":["Button","Spinner","useState","jsx","useState","jsx","jsxs","Button","Spinner"]}
@@ -0,0 +1,10 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ type VerifyEmailProps = {
4
+ verificationId: string;
5
+ email: string;
6
+ redirectUrl?: string;
7
+ };
8
+ declare const VerifyEmail: ({ verificationId, email, redirectUrl, }: VerifyEmailProps) => react_jsx_runtime.JSX.Element;
9
+
10
+ export { VerifyEmail };
@@ -1,14 +1,18 @@
1
1
  "use client";
2
2
 
3
- // src/components/auth/pages/verify-email-page.tsx
3
+ // src/components/auth/verify-email.tsx
4
4
  import {
5
5
  Alert,
6
6
  AlertDescription,
7
7
  AlertTitle
8
8
  } from "@mesob/ui/components/alert";
9
- import { toast } from "@mesob/ui/components/sonner";
9
+ import { useMesob as useMesob2 } from "@mesob/ui/components/mesob-context";
10
10
  import { IconAlertCircle } from "@tabler/icons-react";
11
- import { useEffect as useEffect3, useState as useState3 } from "react";
11
+ import { useEffect as useEffect2, useState as useState3 } from "react";
12
+ import { toast } from "sonner";
13
+
14
+ // src/hooks/use-translator.ts
15
+ import { useMesob } from "@mesob/ui/components/mesob-context";
12
16
 
13
17
  // src/lib/translations.ts
14
18
  function createTranslator(messages, namespace) {
@@ -41,7 +45,12 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
41
45
  import { deepmerge } from "deepmerge-ts";
42
46
  import createFetchClient from "openapi-fetch";
43
47
  import createClient from "openapi-react-query";
44
- import { createContext, useContext, useEffect, useState } from "react";
48
+ import { createContext, useContext, useMemo, useState } from "react";
49
+
50
+ // src/utils/cookie.ts
51
+ var isProduction = typeof process !== "undefined" && process.env.NODE_ENV === "production";
52
+
53
+ // src/provider.tsx
45
54
  import { jsx } from "react/jsx-runtime";
46
55
  var SessionContext = createContext(null);
47
56
  var ApiContext = createContext(null);
@@ -49,9 +58,6 @@ var ConfigContext = createContext(null);
49
58
  var queryClient = new QueryClient({
50
59
  defaultOptions: {
51
60
  queries: {
52
- staleTime: 1e3 * 60 * 5,
53
- gcTime: 1e3 * 60 * 10,
54
- retry: 1,
55
61
  refetchOnWindowFocus: false
56
62
  }
57
63
  }
@@ -71,6 +77,16 @@ function useConfig() {
71
77
  return context;
72
78
  }
73
79
 
80
+ // src/hooks/use-translator.ts
81
+ function useTranslator(namespace) {
82
+ const mesob = useMesob();
83
+ const { config } = useConfig();
84
+ if (mesob?.t) {
85
+ return (key, params) => mesob.t(namespace ? `${namespace}.${key}` : key, params);
86
+ }
87
+ return createTranslator(config.messages || {}, namespace);
88
+ }
89
+
74
90
  // src/constants/auth.error.codes.ts
75
91
  var AUTH_ERROR_MAPPING = {
76
92
  USER_NOT_FOUND: {
@@ -136,6 +152,14 @@ function extractErrorCode(err) {
136
152
  }
137
153
  return "";
138
154
  }
155
+ function sanitizeErrorMessage(message) {
156
+ const lowerMessage = message.toLowerCase();
157
+ const isDatabaseError = lowerMessage.includes("failed query") || lowerMessage.includes("select") || lowerMessage.includes("insert") || lowerMessage.includes("update") || lowerMessage.includes("delete") || lowerMessage.includes("from") || lowerMessage.includes("where") || lowerMessage.includes("limit") || lowerMessage.includes("params:") || lowerMessage.includes("query") || message.includes('"iam".') || message.includes('"tenants"') || message.includes('"users"') || message.includes('"sessions"') || message.includes('"accounts"') || lowerMessage.includes("relation") || lowerMessage.includes("column") || lowerMessage.includes("syntax error") || lowerMessage.includes("database") || lowerMessage.includes("postgres") || lowerMessage.includes("sql");
158
+ if (isDatabaseError) {
159
+ return "An error occurred while processing your request";
160
+ }
161
+ return message;
162
+ }
139
163
  function handleAuthError(err, setError, t) {
140
164
  const errorCode = extractErrorCode(err);
141
165
  if (errorCode && AUTH_ERROR_MAPPING[errorCode]) {
@@ -146,16 +170,20 @@ function handleAuthError(err, setError, t) {
146
170
  });
147
171
  return;
148
172
  }
173
+ const sanitizedMessage = sanitizeErrorMessage(
174
+ err.message || t("errors.fallback")
175
+ );
149
176
  setError({
150
177
  title: t("errors.fallback"),
151
- description: err.message || t("errors.fallback")
178
+ description: sanitizedMessage
152
179
  });
153
180
  }
154
181
  function handleGenericError(err, setError, t) {
155
- const message = err instanceof Error ? err.message : t("errors.fallback");
182
+ const rawMessage = err instanceof Error ? err.message : t("errors.fallback");
183
+ const sanitizedMessage = sanitizeErrorMessage(rawMessage);
156
184
  setError({
157
185
  title: "Error",
158
- description: message
186
+ description: sanitizedMessage
159
187
  });
160
188
  }
161
189
  var handleError = (err, setError, t) => {
@@ -166,9 +194,9 @@ var handleError = (err, setError, t) => {
166
194
  }
167
195
  };
168
196
 
169
- // src/components/auth/auth-page-layout.tsx
197
+ // src/components/auth/auth-layout.tsx
170
198
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
171
- var AuthPageLayout = ({
199
+ var AuthLayout = ({
172
200
  title,
173
201
  description,
174
202
  children,
@@ -199,16 +227,10 @@ import { Spinner as Spinner2 } from "@mesob/ui/components/spinner";
199
227
  import { Controller, useForm } from "react-hook-form";
200
228
  import { z } from "zod";
201
229
 
202
- // src/hooks/use-translator.ts
203
- function useTranslator(namespace) {
204
- const { config } = useConfig();
205
- return createTranslator(config.messages || {}, namespace);
206
- }
207
-
208
230
  // src/components/auth/countdown.tsx
209
231
  import { Button } from "@mesob/ui/components/button";
210
232
  import { Spinner } from "@mesob/ui/components/spinner";
211
- import { useEffect as useEffect2, useState as useState2 } from "react";
233
+ import { useEffect, useState as useState2 } from "react";
212
234
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
213
235
  var Countdown = ({
214
236
  initialSeconds = 60,
@@ -218,7 +240,7 @@ var Countdown = ({
218
240
  const t = useTranslator("Common");
219
241
  const [seconds, setSeconds] = useState2(initialSeconds);
220
242
  const [isResending, setIsResending] = useState2(false);
221
- useEffect2(() => {
243
+ useEffect(() => {
222
244
  if (seconds <= 0) {
223
245
  return;
224
246
  }
@@ -330,21 +352,20 @@ var VerificationForm = ({
330
352
  ] });
331
353
  };
332
354
 
333
- // src/components/auth/pages/verify-email-page.tsx
355
+ // src/components/auth/verify-email.tsx
334
356
  import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
335
- var VerifyEmailPage = ({
357
+ var VerifyEmail = ({
336
358
  verificationId,
337
359
  email,
338
360
  redirectUrl
339
361
  }) => {
340
362
  const { hooks, setAuth } = useApi();
341
363
  const { config } = useConfig();
342
- const t = createTranslator(config.messages || {}, "Auth.verification");
343
- const common = createTranslator(config.messages || {}, "Common");
344
- const footer = createTranslator(
345
- config.messages || {},
346
- "Auth.forgotPassword.footer"
347
- );
364
+ const mesob = useMesob2();
365
+ const t = useTranslator("Auth.verification");
366
+ const common = useTranslator("Common");
367
+ const footer = useTranslator("Auth.forgotPassword.footer");
368
+ const Link = mesob?.linkComponent ?? config.navigation?.linkComponent;
348
369
  const [isLoading, setIsLoading] = useState3(false);
349
370
  const [error, setError] = useState3(null);
350
371
  const verifyEmailMutation = hooks.useMutation(
@@ -356,7 +377,6 @@ var VerifyEmailPage = ({
356
377
  "/email/verification/request"
357
378
  );
358
379
  const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
359
- const Link = config.navigation?.linkComponent;
360
380
  const onNavigate = config.navigation?.onNavigate || ((path) => {
361
381
  if (typeof window !== "undefined") {
362
382
  window.location.href = path;
@@ -364,7 +384,7 @@ var VerifyEmailPage = ({
364
384
  });
365
385
  const logoImage = config.ui.logoImage;
366
386
  const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
367
- useEffect3(() => {
387
+ useEffect2(() => {
368
388
  if (error) {
369
389
  toast.error(error.title || "Error", {
370
390
  description: error.description
@@ -422,7 +442,7 @@ var VerifyEmailPage = ({
422
442
  };
423
443
  if (!verificationId) {
424
444
  return /* @__PURE__ */ jsx5(
425
- AuthPageLayout,
445
+ AuthLayout,
426
446
  {
427
447
  title: common("invalidLinkTitle"),
428
448
  description: common("invalidLinkDescription"),
@@ -451,7 +471,7 @@ var VerifyEmailPage = ({
451
471
  }
452
472
  }
453
473
  return /* @__PURE__ */ jsxs4(
454
- AuthPageLayout,
474
+ AuthLayout,
455
475
  {
456
476
  title: t("email.title"),
457
477
  description: t("email.description"),
@@ -489,6 +509,6 @@ var VerifyEmailPage = ({
489
509
  );
490
510
  };
491
511
  export {
492
- VerifyEmailPage
512
+ VerifyEmail
493
513
  };
494
- //# sourceMappingURL=verify-email-page.js.map
514
+ //# sourceMappingURL=verify-email.js.map