@mesob/auth-react 0.2.3 → 0.2.5

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 (61) hide show
  1. package/dist/components/auth/countdown.js +2 -3
  2. package/dist/components/auth/countdown.js.map +1 -1
  3. package/dist/components/auth/forgot-password.js +9 -11
  4. package/dist/components/auth/forgot-password.js.map +1 -1
  5. package/dist/components/auth/reset-password-form.js +11 -13
  6. package/dist/components/auth/reset-password-form.js.map +1 -1
  7. package/dist/components/auth/sign-in.js +9 -11
  8. package/dist/components/auth/sign-in.js.map +1 -1
  9. package/dist/components/auth/sign-up.js +8 -10
  10. package/dist/components/auth/sign-up.js.map +1 -1
  11. package/dist/components/auth/verification-form.js +9 -8
  12. package/dist/components/auth/verification-form.js.map +1 -1
  13. package/dist/components/auth/verify-email.js +12 -15
  14. package/dist/components/auth/verify-email.js.map +1 -1
  15. package/dist/components/auth/verify-phone.js +13 -14
  16. package/dist/components/auth/verify-phone.js.map +1 -1
  17. package/dist/components/error-boundary.js +1 -1
  18. package/dist/components/error-boundary.js.map +1 -1
  19. package/dist/components/iam/permissions.js +3 -4
  20. package/dist/components/iam/permissions.js.map +1 -1
  21. package/dist/components/iam/roles.js +3 -4
  22. package/dist/components/iam/roles.js.map +1 -1
  23. package/dist/components/iam/sessions.js +3 -3
  24. package/dist/components/iam/sessions.js.map +1 -1
  25. package/dist/components/iam/tenants.js +3 -4
  26. package/dist/components/iam/tenants.js.map +1 -1
  27. package/dist/components/iam/users.js +3 -4
  28. package/dist/components/iam/users.js.map +1 -1
  29. package/dist/components/profile/account.js +1 -1
  30. package/dist/components/profile/account.js.map +1 -1
  31. package/dist/components/profile/change-email-form.js +13 -15
  32. package/dist/components/profile/change-email-form.js.map +1 -1
  33. package/dist/components/profile/change-password-form.js +6 -6
  34. package/dist/components/profile/change-password-form.js.map +1 -1
  35. package/dist/components/profile/change-phone-form.js +13 -15
  36. package/dist/components/profile/change-phone-form.js.map +1 -1
  37. package/dist/components/profile/change-profile.js +3 -3
  38. package/dist/components/profile/change-profile.js.map +1 -1
  39. package/dist/components/profile/otp-verification-modal.js +10 -9
  40. package/dist/components/profile/otp-verification-modal.js.map +1 -1
  41. package/dist/components/profile/request-change-email-form.js +1 -4
  42. package/dist/components/profile/request-change-email-form.js.map +1 -1
  43. package/dist/components/profile/request-change-phone-form.js +1 -4
  44. package/dist/components/profile/request-change-phone-form.js.map +1 -1
  45. package/dist/components/profile/security.js +22 -27
  46. package/dist/components/profile/security.js.map +1 -1
  47. package/dist/components/profile/verify-change-email-form.js +10 -9
  48. package/dist/components/profile/verify-change-email-form.js.map +1 -1
  49. package/dist/components/profile/verify-change-phone-form.js +10 -9
  50. package/dist/components/profile/verify-change-phone-form.js.map +1 -1
  51. package/dist/components/shared/data-table.js +2 -2
  52. package/dist/components/shared/data-table.js.map +1 -1
  53. package/dist/components/skeletons/auth-form-skeleton.js +1 -1
  54. package/dist/components/skeletons/auth-form-skeleton.js.map +1 -1
  55. package/dist/components/skeletons/profile-skeleton.js +1 -1
  56. package/dist/components/skeletons/profile-skeleton.js.map +1 -1
  57. package/dist/components/skeletons/table-skeleton.js +1 -1
  58. package/dist/components/skeletons/table-skeleton.js.map +1 -1
  59. package/dist/index.js +84 -107
  60. package/dist/index.js.map +1 -1
  61. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/profile/verify-change-email-form.tsx","../../../src/provider.tsx","../../../src/lib/translations.ts","../../../src/utils/cookie.ts","../../../src/components/profile/otp-verification-modal.tsx","../../../src/components/auth/verification-form.tsx","../../../src/hooks/use-translator.ts","../../../src/components/auth/countdown.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { toast } from 'sonner';\nimport { useApi, useSession } from '../../provider';\nimport { OtpVerificationModal } from './otp-verification-modal';\n\ntype AuthErrorLike = {\n code?: string;\n message?: string;\n name?: string;\n};\n\nfunction isAuthError(error: unknown): error is AuthErrorLike {\n return (\n typeof error === 'object' &&\n error !== null &&\n ('code' in error || 'message' in error || 'name' in error)\n );\n}\n\nfunction getErrorCode(error: AuthErrorLike): string | undefined {\n if (error.code) {\n return error.code;\n }\n if (error.message) {\n const upperMessage = error.message.toUpperCase().trim();\n const validCodes = [\n 'USER_NOT_FOUND',\n 'USER_EXISTS',\n 'INVALID_PASSWORD',\n 'VERIFICATION_EXPIRED',\n 'VERIFICATION_MISMATCH',\n 'VERIFICATION_NOT_FOUND',\n 'TOO_MANY_ATTEMPTS',\n 'UNAUTHORIZED',\n ];\n if (validCodes.includes(upperMessage)) {\n return upperMessage;\n }\n }\n return undefined;\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (isAuthError(error)) {\n const errorCode = getErrorCode(error);\n switch (errorCode) {\n case 'USER_EXISTS':\n return 'This email is already taken. Please use a different email.';\n case 'VERIFICATION_EXPIRED':\n return 'Verification code has expired. Please request a new one.';\n case 'VERIFICATION_MISMATCH':\n return 'Invalid verification code. Please try again.';\n case 'VERIFICATION_NOT_FOUND':\n return 'Verification not found. Please request a new code.';\n default:\n return error.message || 'An error occurred. Please try again.';\n }\n }\n if (error instanceof Error) {\n return error.message;\n }\n return 'An error occurred. Please try again.';\n}\n\ntype VerifyChangeEmailFormProps = {\n email: string;\n verificationId: string | null;\n onSuccess: () => void;\n onCancel: () => void;\n};\n\nexport function VerifyChangeEmailForm({\n email,\n verificationId,\n onSuccess,\n onCancel,\n}: VerifyChangeEmailFormProps) {\n const { refresh } = useSession();\n const { hooks } = useApi();\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [currentVerificationId, setCurrentVerificationId] =\n useState(verificationId);\n\n const verifyEmailMutation = hooks.useMutation(\n 'post',\n '/email/verification/confirm',\n );\n const updateEmailMutation = hooks.useMutation('put', '/profile/email');\n const requestEmailVerificationMutation = hooks.useMutation(\n 'post',\n '/email/verification/request',\n );\n\n const onOtpSubmit = async (code: string) => {\n if (!currentVerificationId) {\n toast.error('Verification not found. Please request a new code.');\n return;\n }\n try {\n setIsSubmitting(true);\n\n // Verify email\n await verifyEmailMutation.mutateAsync({\n body: {\n verificationId: currentVerificationId,\n code,\n },\n });\n\n // Update email via auth client\n await updateEmailMutation.mutateAsync({\n body: { email },\n });\n\n toast.success('Email updated successfully');\n await refresh();\n onSuccess();\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n toast.error(errorMessage);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n if (!currentVerificationId) {\n toast.error('Verification not found. Please request a new code.');\n return null;\n }\n\n return (\n <OtpVerificationModal\n open\n title=\"Verify email\"\n description={`Enter the verification code sent to ${email}`}\n verificationId={currentVerificationId}\n isLoading={isSubmitting}\n onSubmit={onOtpSubmit}\n onResend={async () => {\n try {\n setIsSubmitting(true);\n const next = await requestEmailVerificationMutation.mutateAsync({\n body: { email },\n });\n setCurrentVerificationId(next.data?.verificationId ?? null);\n toast.success('Verification code resent');\n } catch (error) {\n toast.error(getErrorMessage(error));\n } finally {\n setIsSubmitting(false);\n }\n }}\n onCancel={onCancel}\n />\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","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","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 {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '@mesob/ui/components/dialog';\nimport { VerificationForm } from '../auth/verification-form';\n\ntype OtpVerificationModalProps = {\n open: boolean;\n title: string;\n description?: string;\n verificationId: string;\n isLoading?: boolean;\n onSubmit: (code: string) => Promise<void> | void;\n onResend?: () => Promise<void> | void;\n onCancel?: () => void;\n};\n\nexport function OtpVerificationModal({\n open,\n title,\n description,\n verificationId,\n isLoading,\n onSubmit,\n onResend,\n onCancel,\n}: OtpVerificationModalProps) {\n return (\n <Dialog\n open={open}\n onOpenChange={(nextOpen) => {\n if (!nextOpen) {\n onCancel?.();\n }\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{title}</DialogTitle>\n {description && <DialogDescription>{description}</DialogDescription>}\n </DialogHeader>\n\n <VerificationForm\n verificationId={verificationId}\n isLoading={isLoading}\n onSubmit={async ({ code }: { code: string }) => onSubmit(code)}\n onResend={onResend ?? (() => undefined)}\n />\n </DialogContent>\n </Dialog>\n );\n}\n","'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","'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":["useState","Button","Spinner","useState","jsx","useState","jsx","jsxs","Button","Spinner","jsx","jsxs","jsx","useState"]}
1
+ {"version":3,"sources":["../../../src/components/profile/verify-change-email-form.tsx","../../../src/provider.tsx","../../../src/lib/translations.ts","../../../src/utils/cookie.ts","../../../src/components/profile/otp-verification-modal.tsx","../../../src/components/auth/verification-form.tsx","../../../src/hooks/use-translator.ts","../../../src/components/auth/countdown.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { toast } from 'sonner';\nimport { useApi, useSession } from '../../provider';\nimport { OtpVerificationModal } from './otp-verification-modal';\n\ntype AuthErrorLike = {\n code?: string;\n message?: string;\n name?: string;\n};\n\nfunction isAuthError(error: unknown): error is AuthErrorLike {\n return (\n typeof error === 'object' &&\n error !== null &&\n ('code' in error || 'message' in error || 'name' in error)\n );\n}\n\nfunction getErrorCode(error: AuthErrorLike): string | undefined {\n if (error.code) {\n return error.code;\n }\n if (error.message) {\n const upperMessage = error.message.toUpperCase().trim();\n const validCodes = [\n 'USER_NOT_FOUND',\n 'USER_EXISTS',\n 'INVALID_PASSWORD',\n 'VERIFICATION_EXPIRED',\n 'VERIFICATION_MISMATCH',\n 'VERIFICATION_NOT_FOUND',\n 'TOO_MANY_ATTEMPTS',\n 'UNAUTHORIZED',\n ];\n if (validCodes.includes(upperMessage)) {\n return upperMessage;\n }\n }\n return undefined;\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (isAuthError(error)) {\n const errorCode = getErrorCode(error);\n switch (errorCode) {\n case 'USER_EXISTS':\n return 'This email is already taken. Please use a different email.';\n case 'VERIFICATION_EXPIRED':\n return 'Verification code has expired. Please request a new one.';\n case 'VERIFICATION_MISMATCH':\n return 'Invalid verification code. Please try again.';\n case 'VERIFICATION_NOT_FOUND':\n return 'Verification not found. Please request a new code.';\n default:\n return error.message || 'An error occurred. Please try again.';\n }\n }\n if (error instanceof Error) {\n return error.message;\n }\n return 'An error occurred. Please try again.';\n}\n\ntype VerifyChangeEmailFormProps = {\n email: string;\n verificationId: string | null;\n onSuccess: () => void;\n onCancel: () => void;\n};\n\nexport function VerifyChangeEmailForm({\n email,\n verificationId,\n onSuccess,\n onCancel,\n}: VerifyChangeEmailFormProps) {\n const { refresh } = useSession();\n const { hooks } = useApi();\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [currentVerificationId, setCurrentVerificationId] =\n useState(verificationId);\n\n const verifyEmailMutation = hooks.useMutation(\n 'post',\n '/email/verification/confirm',\n );\n const updateEmailMutation = hooks.useMutation('put', '/profile/email');\n const requestEmailVerificationMutation = hooks.useMutation(\n 'post',\n '/email/verification/request',\n );\n\n const onOtpSubmit = async (code: string) => {\n if (!currentVerificationId) {\n toast.error('Verification not found. Please request a new code.');\n return;\n }\n try {\n setIsSubmitting(true);\n\n // Verify email\n await verifyEmailMutation.mutateAsync({\n body: {\n verificationId: currentVerificationId,\n code,\n },\n });\n\n // Update email via auth client\n await updateEmailMutation.mutateAsync({\n body: { email },\n });\n\n toast.success('Email updated successfully');\n await refresh();\n onSuccess();\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n toast.error(errorMessage);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n if (!currentVerificationId) {\n toast.error('Verification not found. Please request a new code.');\n return null;\n }\n\n return (\n <OtpVerificationModal\n open\n title=\"Verify email\"\n description={`Enter the verification code sent to ${email}`}\n verificationId={currentVerificationId}\n isLoading={isSubmitting}\n onSubmit={onOtpSubmit}\n onResend={async () => {\n try {\n setIsSubmitting(true);\n const next = await requestEmailVerificationMutation.mutateAsync({\n body: { email },\n });\n setCurrentVerificationId(next.data?.verificationId ?? null);\n toast.success('Verification code resent');\n } catch (error) {\n toast.error(getErrorMessage(error));\n } finally {\n setIsSubmitting(false);\n }\n }}\n onCancel={onCancel}\n />\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","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","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 {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '@mesob/ui/components';\nimport { VerificationForm } from '../auth/verification-form';\n\ntype OtpVerificationModalProps = {\n open: boolean;\n title: string;\n description?: string;\n verificationId: string;\n isLoading?: boolean;\n onSubmit: (code: string) => Promise<void> | void;\n onResend?: () => Promise<void> | void;\n onCancel?: () => void;\n};\n\nexport function OtpVerificationModal({\n open,\n title,\n description,\n verificationId,\n isLoading,\n onSubmit,\n onResend,\n onCancel,\n}: OtpVerificationModalProps) {\n return (\n <Dialog\n open={open}\n onOpenChange={(nextOpen: boolean) => {\n if (!nextOpen) {\n onCancel?.();\n }\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{title}</DialogTitle>\n {description && <DialogDescription>{description}</DialogDescription>}\n </DialogHeader>\n\n <VerificationForm\n verificationId={verificationId}\n isLoading={isLoading}\n onSubmit={async ({ code }: { code: string }) => onSubmit(code)}\n onResend={onResend ?? (() => undefined)}\n />\n </DialogContent>\n </Dialog>\n );\n}\n","'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport {\n Button,\n Field,\n FieldError,\n FieldGroup,\n InputOTP,\n InputOTPGroup,\n InputOTPSlot,\n Spinner,\n} from '@mesob/ui/components';\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/providers';\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","'use client';\n\nimport { Button, Spinner } from '@mesob/ui/components';\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":["useState","Button","Spinner","useState","jsx","useState","jsx","jsxs","Button","Spinner","jsx","jsxs","jsx","useState"]}
@@ -81,23 +81,25 @@ import {
81
81
  DialogDescription,
82
82
  DialogHeader,
83
83
  DialogTitle
84
- } from "@mesob/ui/components/dialog";
84
+ } from "@mesob/ui/components";
85
85
 
86
86
  // src/components/auth/verification-form.tsx
87
87
  import { zodResolver } from "@hookform/resolvers/zod";
88
- import { Button as Button2 } from "@mesob/ui/components/button";
89
- import { Field, FieldError, FieldGroup } from "@mesob/ui/components/field";
90
88
  import {
89
+ Button as Button2,
90
+ Field,
91
+ FieldError,
92
+ FieldGroup,
91
93
  InputOTP,
92
94
  InputOTPGroup,
93
- InputOTPSlot
94
- } from "@mesob/ui/components/input-otp";
95
- import { Spinner as Spinner2 } from "@mesob/ui/components/spinner";
95
+ InputOTPSlot,
96
+ Spinner as Spinner2
97
+ } from "@mesob/ui/components";
96
98
  import { Controller, useForm } from "react-hook-form";
97
99
  import { z } from "zod";
98
100
 
99
101
  // src/hooks/use-translator.ts
100
- import { useMesob } from "@mesob/ui/components/mesob-context";
102
+ import { useMesob } from "@mesob/ui/providers";
101
103
  function useTranslator(namespace) {
102
104
  const mesob = useMesob();
103
105
  const { config } = useConfig();
@@ -108,8 +110,7 @@ function useTranslator(namespace) {
108
110
  }
109
111
 
110
112
  // src/components/auth/countdown.tsx
111
- import { Button } from "@mesob/ui/components/button";
112
- import { Spinner } from "@mesob/ui/components/spinner";
113
+ import { Button, Spinner } from "@mesob/ui/components";
113
114
  import { useEffect, useState as useState2 } from "react";
114
115
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
115
116
  var Countdown = ({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/profile/verify-change-phone-form.tsx","../../../src/provider.tsx","../../../src/lib/translations.ts","../../../src/utils/cookie.ts","../../../src/components/profile/otp-verification-modal.tsx","../../../src/components/auth/verification-form.tsx","../../../src/hooks/use-translator.ts","../../../src/components/auth/countdown.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { toast } from 'sonner';\nimport { useApi, useSession } from '../../provider';\nimport { OtpVerificationModal } from './otp-verification-modal';\n\ntype AuthErrorLike = {\n code?: string;\n message?: string;\n name?: string;\n};\n\nfunction isAuthError(error: unknown): error is AuthErrorLike {\n return (\n typeof error === 'object' &&\n error !== null &&\n ('code' in error || 'message' in error || 'name' in error)\n );\n}\n\nfunction getErrorCode(error: AuthErrorLike): string | undefined {\n if (error.code) {\n return error.code;\n }\n if (error.message) {\n const upperMessage = error.message.toUpperCase().trim();\n const validCodes = [\n 'USER_NOT_FOUND',\n 'USER_EXISTS',\n 'INVALID_PASSWORD',\n 'VERIFICATION_EXPIRED',\n 'VERIFICATION_MISMATCH',\n 'VERIFICATION_NOT_FOUND',\n 'TOO_MANY_ATTEMPTS',\n 'UNAUTHORIZED',\n ];\n if (validCodes.includes(upperMessage)) {\n return upperMessage;\n }\n }\n return undefined;\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (isAuthError(error)) {\n const errorCode = getErrorCode(error);\n switch (errorCode) {\n case 'USER_EXISTS':\n return 'This phone number is already taken. Please use a different number.';\n case 'VERIFICATION_EXPIRED':\n return 'Verification code has expired. Please request a new one.';\n case 'VERIFICATION_MISMATCH':\n return 'Invalid verification code. Please try again.';\n case 'VERIFICATION_NOT_FOUND':\n return 'Verification not found. Please request a new code.';\n default:\n return error.message || 'An error occurred. Please try again.';\n }\n }\n if (error instanceof Error) {\n return error.message;\n }\n return 'An error occurred. Please try again.';\n}\n\ntype VerifyChangePhoneFormProps = {\n phone: string;\n verificationId: string | null;\n onSuccess: () => void;\n onCancel: () => void;\n};\n\nexport function VerifyChangePhoneForm({\n phone,\n verificationId,\n onSuccess,\n onCancel,\n}: VerifyChangePhoneFormProps) {\n const { refresh } = useSession();\n const { hooks } = useApi();\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [currentVerificationId, setCurrentVerificationId] =\n useState(verificationId);\n\n const verifyPhoneOtpMutation = hooks.useMutation(\n 'post',\n '/phone/verification/confirm',\n );\n const updatePhoneMutation = hooks.useMutation('put', '/profile/phone');\n const requestPhoneOtpMutation = hooks.useMutation(\n 'post',\n '/phone/verification/request',\n );\n\n const onOtpSubmit = async (code: string) => {\n if (!currentVerificationId) {\n toast.error('Verification not found. Please request a new code.');\n return;\n }\n try {\n setIsSubmitting(true);\n\n // Verify phone\n await verifyPhoneOtpMutation.mutateAsync({\n body: {\n verificationId: currentVerificationId,\n code,\n context: 'change-phone',\n },\n });\n\n // Update phone via auth client\n await updatePhoneMutation.mutateAsync({\n body: { phone },\n });\n\n toast.success('Phone number updated successfully');\n await refresh();\n onSuccess();\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n toast.error(errorMessage);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n if (!currentVerificationId) {\n toast.error('Verification not found. Please request a new code.');\n return null;\n }\n\n return (\n <OtpVerificationModal\n open\n title=\"Verify phone\"\n description={`Enter the verification code sent to ${phone}`}\n verificationId={currentVerificationId}\n isLoading={isSubmitting}\n onSubmit={onOtpSubmit}\n onResend={async () => {\n try {\n setIsSubmitting(true);\n const next = await requestPhoneOtpMutation.mutateAsync({\n body: {\n phone,\n context: 'change-phone',\n },\n });\n setCurrentVerificationId(next.data?.verificationId ?? null);\n toast.success('Verification code resent');\n } catch (error) {\n toast.error(getErrorMessage(error));\n } finally {\n setIsSubmitting(false);\n }\n }}\n onCancel={onCancel}\n />\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","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","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 {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '@mesob/ui/components/dialog';\nimport { VerificationForm } from '../auth/verification-form';\n\ntype OtpVerificationModalProps = {\n open: boolean;\n title: string;\n description?: string;\n verificationId: string;\n isLoading?: boolean;\n onSubmit: (code: string) => Promise<void> | void;\n onResend?: () => Promise<void> | void;\n onCancel?: () => void;\n};\n\nexport function OtpVerificationModal({\n open,\n title,\n description,\n verificationId,\n isLoading,\n onSubmit,\n onResend,\n onCancel,\n}: OtpVerificationModalProps) {\n return (\n <Dialog\n open={open}\n onOpenChange={(nextOpen) => {\n if (!nextOpen) {\n onCancel?.();\n }\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{title}</DialogTitle>\n {description && <DialogDescription>{description}</DialogDescription>}\n </DialogHeader>\n\n <VerificationForm\n verificationId={verificationId}\n isLoading={isLoading}\n onSubmit={async ({ code }: { code: string }) => onSubmit(code)}\n onResend={onResend ?? (() => undefined)}\n />\n </DialogContent>\n </Dialog>\n );\n}\n","'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","'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":["useState","Button","Spinner","useState","jsx","useState","jsx","jsxs","Button","Spinner","jsx","jsxs","jsx","useState"]}
1
+ {"version":3,"sources":["../../../src/components/profile/verify-change-phone-form.tsx","../../../src/provider.tsx","../../../src/lib/translations.ts","../../../src/utils/cookie.ts","../../../src/components/profile/otp-verification-modal.tsx","../../../src/components/auth/verification-form.tsx","../../../src/hooks/use-translator.ts","../../../src/components/auth/countdown.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { toast } from 'sonner';\nimport { useApi, useSession } from '../../provider';\nimport { OtpVerificationModal } from './otp-verification-modal';\n\ntype AuthErrorLike = {\n code?: string;\n message?: string;\n name?: string;\n};\n\nfunction isAuthError(error: unknown): error is AuthErrorLike {\n return (\n typeof error === 'object' &&\n error !== null &&\n ('code' in error || 'message' in error || 'name' in error)\n );\n}\n\nfunction getErrorCode(error: AuthErrorLike): string | undefined {\n if (error.code) {\n return error.code;\n }\n if (error.message) {\n const upperMessage = error.message.toUpperCase().trim();\n const validCodes = [\n 'USER_NOT_FOUND',\n 'USER_EXISTS',\n 'INVALID_PASSWORD',\n 'VERIFICATION_EXPIRED',\n 'VERIFICATION_MISMATCH',\n 'VERIFICATION_NOT_FOUND',\n 'TOO_MANY_ATTEMPTS',\n 'UNAUTHORIZED',\n ];\n if (validCodes.includes(upperMessage)) {\n return upperMessage;\n }\n }\n return undefined;\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (isAuthError(error)) {\n const errorCode = getErrorCode(error);\n switch (errorCode) {\n case 'USER_EXISTS':\n return 'This phone number is already taken. Please use a different number.';\n case 'VERIFICATION_EXPIRED':\n return 'Verification code has expired. Please request a new one.';\n case 'VERIFICATION_MISMATCH':\n return 'Invalid verification code. Please try again.';\n case 'VERIFICATION_NOT_FOUND':\n return 'Verification not found. Please request a new code.';\n default:\n return error.message || 'An error occurred. Please try again.';\n }\n }\n if (error instanceof Error) {\n return error.message;\n }\n return 'An error occurred. Please try again.';\n}\n\ntype VerifyChangePhoneFormProps = {\n phone: string;\n verificationId: string | null;\n onSuccess: () => void;\n onCancel: () => void;\n};\n\nexport function VerifyChangePhoneForm({\n phone,\n verificationId,\n onSuccess,\n onCancel,\n}: VerifyChangePhoneFormProps) {\n const { refresh } = useSession();\n const { hooks } = useApi();\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [currentVerificationId, setCurrentVerificationId] =\n useState(verificationId);\n\n const verifyPhoneOtpMutation = hooks.useMutation(\n 'post',\n '/phone/verification/confirm',\n );\n const updatePhoneMutation = hooks.useMutation('put', '/profile/phone');\n const requestPhoneOtpMutation = hooks.useMutation(\n 'post',\n '/phone/verification/request',\n );\n\n const onOtpSubmit = async (code: string) => {\n if (!currentVerificationId) {\n toast.error('Verification not found. Please request a new code.');\n return;\n }\n try {\n setIsSubmitting(true);\n\n // Verify phone\n await verifyPhoneOtpMutation.mutateAsync({\n body: {\n verificationId: currentVerificationId,\n code,\n context: 'change-phone',\n },\n });\n\n // Update phone via auth client\n await updatePhoneMutation.mutateAsync({\n body: { phone },\n });\n\n toast.success('Phone number updated successfully');\n await refresh();\n onSuccess();\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n toast.error(errorMessage);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n if (!currentVerificationId) {\n toast.error('Verification not found. Please request a new code.');\n return null;\n }\n\n return (\n <OtpVerificationModal\n open\n title=\"Verify phone\"\n description={`Enter the verification code sent to ${phone}`}\n verificationId={currentVerificationId}\n isLoading={isSubmitting}\n onSubmit={onOtpSubmit}\n onResend={async () => {\n try {\n setIsSubmitting(true);\n const next = await requestPhoneOtpMutation.mutateAsync({\n body: {\n phone,\n context: 'change-phone',\n },\n });\n setCurrentVerificationId(next.data?.verificationId ?? null);\n toast.success('Verification code resent');\n } catch (error) {\n toast.error(getErrorMessage(error));\n } finally {\n setIsSubmitting(false);\n }\n }}\n onCancel={onCancel}\n />\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","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","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 {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '@mesob/ui/components';\nimport { VerificationForm } from '../auth/verification-form';\n\ntype OtpVerificationModalProps = {\n open: boolean;\n title: string;\n description?: string;\n verificationId: string;\n isLoading?: boolean;\n onSubmit: (code: string) => Promise<void> | void;\n onResend?: () => Promise<void> | void;\n onCancel?: () => void;\n};\n\nexport function OtpVerificationModal({\n open,\n title,\n description,\n verificationId,\n isLoading,\n onSubmit,\n onResend,\n onCancel,\n}: OtpVerificationModalProps) {\n return (\n <Dialog\n open={open}\n onOpenChange={(nextOpen: boolean) => {\n if (!nextOpen) {\n onCancel?.();\n }\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{title}</DialogTitle>\n {description && <DialogDescription>{description}</DialogDescription>}\n </DialogHeader>\n\n <VerificationForm\n verificationId={verificationId}\n isLoading={isLoading}\n onSubmit={async ({ code }: { code: string }) => onSubmit(code)}\n onResend={onResend ?? (() => undefined)}\n />\n </DialogContent>\n </Dialog>\n );\n}\n","'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport {\n Button,\n Field,\n FieldError,\n FieldGroup,\n InputOTP,\n InputOTPGroup,\n InputOTPSlot,\n Spinner,\n} from '@mesob/ui/components';\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/providers';\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","'use client';\n\nimport { Button, Spinner } from '@mesob/ui/components';\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,YAAAA,iBAAgB;AACzB,SAAS,aAAa;;;ACDtB,SAAS,aAAa,2BAA2B;AACjD,SAAS,iBAAiB;AAC1B,OAAO,uBAAuB;AAC9B,OAAO,kBAAkB;AAEzB,SAAS,eAAe,YAAY,SAAS,gBAAgB;;;ACLtD,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,IAAM,eACJ,OAAO,YAAY,eAAe,QAAQ,IAAI,aAAa;;;AF4JvD;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;AAUM,SAAS,aAAkC;AAChD,QAAM,UAAU,WAAW,cAAc;AACzC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AACA,SAAO;AACT;AAEO,SAAS,SAA0B;AACxC,QAAM,UAAU,WAAW,UAAU;AACrC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,SAAO;AACT;AAEO,SAAS,YAAgC;AAC9C,QAAM,UAAU,WAAW,aAAa;AACxC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AACA,SAAO;AACT;;;AG7GA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACNP,SAAS,mBAAmB;AAC5B;AAAA,EACE,UAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAAC;AAAA,OACK;AACP,SAAS,YAAY,eAAe;AACpC,SAAS,SAAS;;;ACdlB,SAAS,gBAAgB;AAIlB,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;;;ACZA,SAAS,QAAQ,eAAe;AAChC,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;;;AFGkB,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;;;AD1DQ,SACE,OAAAC,MADF,QAAAC,aAAA;AApBD,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA8B;AAC5B,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,cAAc,CAAC,aAAsB;AACnC,YAAI,CAAC,UAAU;AACb,qBAAW;AAAA,QACb;AAAA,MACF;AAAA,MAEA,0BAAAC,MAAC,iBACC;AAAA,wBAAAA,MAAC,gBACC;AAAA,0BAAAD,KAAC,eAAa,iBAAM;AAAA,UACnB,eAAe,gBAAAA,KAAC,qBAAmB,uBAAY;AAAA,WAClD;AAAA,QAEA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA,UAAU,OAAO,EAAE,KAAK,MAAwB,SAAS,IAAI;AAAA,YAC7D,UAAU,aAAa,MAAM;AAAA;AAAA,QAC/B;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;;;AJ8EI,gBAAAE,YAAA;AAzHJ,SAAS,YAAY,OAAwC;AAC3D,SACE,OAAO,UAAU,YACjB,UAAU,SACT,UAAU,SAAS,aAAa,SAAS,UAAU;AAExD;AAEA,SAAS,aAAa,OAA0C;AAC9D,MAAI,MAAM,MAAM;AACd,WAAO,MAAM;AAAA,EACf;AACA,MAAI,MAAM,SAAS;AACjB,UAAM,eAAe,MAAM,QAAQ,YAAY,EAAE,KAAK;AACtD,UAAM,aAAa;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,WAAW,SAAS,YAAY,GAAG;AACrC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,OAAwB;AAC/C,MAAI,YAAY,KAAK,GAAG;AACtB,UAAM,YAAY,aAAa,KAAK;AACpC,YAAQ,WAAW;AAAA,MACjB,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO,MAAM,WAAW;AAAA,IAC5B;AAAA,EACF;AACA,MAAI,iBAAiB,OAAO;AAC1B,WAAO,MAAM;AAAA,EACf;AACA,SAAO;AACT;AASO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA+B;AAC7B,QAAM,EAAE,QAAQ,IAAI,WAAW;AAC/B,QAAM,EAAE,MAAM,IAAI,OAAO;AACzB,QAAM,CAAC,cAAc,eAAe,IAAIC,UAAS,KAAK;AACtD,QAAM,CAAC,uBAAuB,wBAAwB,IACpDA,UAAS,cAAc;AAEzB,QAAM,yBAAyB,MAAM;AAAA,IACnC;AAAA,IACA;AAAA,EACF;AACA,QAAM,sBAAsB,MAAM,YAAY,OAAO,gBAAgB;AACrE,QAAM,0BAA0B,MAAM;AAAA,IACpC;AAAA,IACA;AAAA,EACF;AAEA,QAAM,cAAc,OAAO,SAAiB;AAC1C,QAAI,CAAC,uBAAuB;AAC1B,YAAM,MAAM,oDAAoD;AAChE;AAAA,IACF;AACA,QAAI;AACF,sBAAgB,IAAI;AAGpB,YAAM,uBAAuB,YAAY;AAAA,QACvC,MAAM;AAAA,UACJ,gBAAgB;AAAA,UAChB;AAAA,UACA,SAAS;AAAA,QACX;AAAA,MACF,CAAC;AAGD,YAAM,oBAAoB,YAAY;AAAA,QACpC,MAAM,EAAE,MAAM;AAAA,MAChB,CAAC;AAED,YAAM,QAAQ,mCAAmC;AACjD,YAAM,QAAQ;AACd,gBAAU;AAAA,IACZ,SAAS,OAAO;AACd,YAAM,eAAe,gBAAgB,KAAK;AAC1C,YAAM,MAAM,YAAY;AAAA,IAC1B,UAAE;AACA,sBAAgB,KAAK;AAAA,IACvB;AAAA,EACF;AAEA,MAAI,CAAC,uBAAuB;AAC1B,UAAM,MAAM,oDAAoD;AAChE,WAAO;AAAA,EACT;AAEA,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC,MAAI;AAAA,MACJ,OAAM;AAAA,MACN,aAAa,uCAAuC,KAAK;AAAA,MACzD,gBAAgB;AAAA,MAChB,WAAW;AAAA,MACX,UAAU;AAAA,MACV,UAAU,YAAY;AACpB,YAAI;AACF,0BAAgB,IAAI;AACpB,gBAAM,OAAO,MAAM,wBAAwB,YAAY;AAAA,YACrD,MAAM;AAAA,cACJ;AAAA,cACA,SAAS;AAAA,YACX;AAAA,UACF,CAAC;AACD,mCAAyB,KAAK,MAAM,kBAAkB,IAAI;AAC1D,gBAAM,QAAQ,0BAA0B;AAAA,QAC1C,SAAS,OAAO;AACd,gBAAM,MAAM,gBAAgB,KAAK,CAAC;AAAA,QACpC,UAAE;AACA,0BAAgB,KAAK;AAAA,QACvB;AAAA,MACF;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;","names":["useState","Button","Spinner","useState","jsx","useState","jsx","jsxs","Button","Spinner","jsx","jsxs","jsx","useState"]}
@@ -8,10 +8,10 @@ import {
8
8
  TableHead,
9
9
  TableHeader,
10
10
  TableRow
11
- } from "@mesob/ui/components/table";
11
+ } from "@mesob/ui/components";
12
12
 
13
13
  // src/components/skeletons/table-skeleton.tsx
14
- import { Skeleton } from "@mesob/ui/components/skeleton";
14
+ import { Skeleton } from "@mesob/ui/components";
15
15
  import { jsx, jsxs } from "react/jsx-runtime";
16
16
  function TableSkeleton({ columns = 5, rows = 10 }) {
17
17
  const headerKeys = Array.from({ length: columns }, (_, i) => `header-${i}`);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/shared/data-table.tsx","../../../src/components/skeletons/table-skeleton.tsx"],"sourcesContent":["'use client';\n\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@mesob/ui/components/table';\nimport type { ReactNode } from 'react';\nimport { TableSkeleton } from '../skeletons/table-skeleton';\n\nexport type DataTableColumn<T> = {\n key: string;\n header: string;\n cell: (row: T) => ReactNode;\n sortable?: boolean;\n};\n\ntype DataTableProps<T> = {\n data: T[];\n columns: DataTableColumn<T>[];\n isLoading?: boolean;\n onRowClick?: (row: T) => void;\n emptyMessage?: string;\n actions?: ReactNode;\n};\n\nexport function DataTable<T extends { id: string }>({\n data,\n columns,\n isLoading,\n onRowClick,\n emptyMessage = 'No data available',\n actions,\n}: DataTableProps<T>) {\n if (isLoading) {\n return <TableSkeleton columns={columns.length} rows={5} />;\n }\n\n if (data.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-[400px] p-6\">\n <p className=\"text-muted-foreground\">{emptyMessage}</p>\n {actions && <div className=\"mt-4\">{actions}</div>}\n </div>\n );\n }\n\n return (\n <div className=\"w-full space-y-4\">\n {actions && <div className=\"flex justify-end\">{actions}</div>}\n\n <div className=\"border rounded-lg overflow-hidden\">\n <Table>\n <TableHeader>\n <TableRow>\n {columns.map((column) => (\n <TableHead key={column.key}>{column.header}</TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {data.map((row) => (\n <TableRow\n key={row.id}\n onClick={() => onRowClick?.(row)}\n className={onRowClick ? 'cursor-pointer hover:bg-muted/50' : ''}\n >\n {columns.map((column) => (\n <TableCell key={`${row.id}-${column.key}`}>\n {column.cell(row)}\n </TableCell>\n ))}\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { Skeleton } from '@mesob/ui/components/skeleton';\n\ntype TableSkeletonProps = {\n columns?: number;\n rows?: number;\n};\n\nexport function TableSkeleton({ columns = 5, rows = 10 }: TableSkeletonProps) {\n const headerKeys = Array.from({ length: columns }, (_, i) => `header-${i}`);\n const rowKeys = Array.from({ length: rows }, (_, i) => `row-${i}`);\n const cellKeys = Array.from({ length: rows }, (_, rowIdx) =>\n Array.from({ length: columns }, (_, colIdx) => `cell-${rowIdx}-${colIdx}`),\n );\n\n return (\n <div className=\"w-full space-y-4\">\n {/* Header */}\n <div className=\"flex justify-between items-center\">\n <Skeleton className=\"h-8 w-48\" />\n <Skeleton className=\"h-10 w-32\" />\n </div>\n\n {/* Search/filters */}\n <div className=\"flex gap-4\">\n <Skeleton className=\"h-10 flex-1 max-w-sm\" />\n <Skeleton className=\"h-10 w-24\" />\n <Skeleton className=\"h-10 w-24\" />\n </div>\n\n {/* Table */}\n <div className=\"border rounded-lg overflow-hidden\">\n {/* Table header */}\n <div className=\"flex gap-4 p-4 bg-muted\">\n {headerKeys.map((key) => (\n <Skeleton key={key} className=\"h-4 flex-1\" />\n ))}\n </div>\n\n {/* Table rows */}\n {rowKeys.map((rowKey, rowIdx) => (\n <div key={rowKey} className=\"flex gap-4 p-4 border-t\">\n {cellKeys[rowIdx]?.map((cellKey) => (\n <Skeleton key={cellKey} className=\"h-4 flex-1\" />\n ))}\n </div>\n ))}\n </div>\n\n {/* Pagination */}\n <div className=\"flex justify-between items-center\">\n <Skeleton className=\"h-4 w-32\" />\n <div className=\"flex gap-2\">\n <Skeleton className=\"h-10 w-20\" />\n <Skeleton className=\"h-10 w-20\" />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["_","jsx","jsxs"]}
1
+ {"version":3,"sources":["../../../src/components/shared/data-table.tsx","../../../src/components/skeletons/table-skeleton.tsx"],"sourcesContent":["'use client';\n\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@mesob/ui/components';\nimport type { ReactNode } from 'react';\nimport { TableSkeleton } from '../skeletons/table-skeleton';\n\nexport type DataTableColumn<T> = {\n key: string;\n header: string;\n cell: (row: T) => ReactNode;\n sortable?: boolean;\n};\n\ntype DataTableProps<T> = {\n data: T[];\n columns: DataTableColumn<T>[];\n isLoading?: boolean;\n onRowClick?: (row: T) => void;\n emptyMessage?: string;\n actions?: ReactNode;\n};\n\nexport function DataTable<T extends { id: string }>({\n data,\n columns,\n isLoading,\n onRowClick,\n emptyMessage = 'No data available',\n actions,\n}: DataTableProps<T>) {\n if (isLoading) {\n return <TableSkeleton columns={columns.length} rows={5} />;\n }\n\n if (data.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-[400px] p-6\">\n <p className=\"text-muted-foreground\">{emptyMessage}</p>\n {actions && <div className=\"mt-4\">{actions}</div>}\n </div>\n );\n }\n\n return (\n <div className=\"w-full space-y-4\">\n {actions && <div className=\"flex justify-end\">{actions}</div>}\n\n <div className=\"border rounded-lg overflow-hidden\">\n <Table>\n <TableHeader>\n <TableRow>\n {columns.map((column) => (\n <TableHead key={column.key}>{column.header}</TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {data.map((row) => (\n <TableRow\n key={row.id}\n onClick={() => onRowClick?.(row)}\n className={onRowClick ? 'cursor-pointer hover:bg-muted/50' : ''}\n >\n {columns.map((column) => (\n <TableCell key={`${row.id}-${column.key}`}>\n {column.cell(row)}\n </TableCell>\n ))}\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { Skeleton } from '@mesob/ui/components';\n\ntype TableSkeletonProps = {\n columns?: number;\n rows?: number;\n};\n\nexport function TableSkeleton({ columns = 5, rows = 10 }: TableSkeletonProps) {\n const headerKeys = Array.from({ length: columns }, (_, i) => `header-${i}`);\n const rowKeys = Array.from({ length: rows }, (_, i) => `row-${i}`);\n const cellKeys = Array.from({ length: rows }, (_, rowIdx) =>\n Array.from({ length: columns }, (_, colIdx) => `cell-${rowIdx}-${colIdx}`),\n );\n\n return (\n <div className=\"w-full space-y-4\">\n {/* Header */}\n <div className=\"flex justify-between items-center\">\n <Skeleton className=\"h-8 w-48\" />\n <Skeleton className=\"h-10 w-32\" />\n </div>\n\n {/* Search/filters */}\n <div className=\"flex gap-4\">\n <Skeleton className=\"h-10 flex-1 max-w-sm\" />\n <Skeleton className=\"h-10 w-24\" />\n <Skeleton className=\"h-10 w-24\" />\n </div>\n\n {/* Table */}\n <div className=\"border rounded-lg overflow-hidden\">\n {/* Table header */}\n <div className=\"flex gap-4 p-4 bg-muted\">\n {headerKeys.map((key) => (\n <Skeleton key={key} className=\"h-4 flex-1\" />\n ))}\n </div>\n\n {/* Table rows */}\n {rowKeys.map((rowKey, rowIdx) => (\n <div key={rowKey} className=\"flex gap-4 p-4 border-t\">\n {cellKeys[rowIdx]?.map((cellKey) => (\n <Skeleton key={cellKey} className=\"h-4 flex-1\" />\n ))}\n </div>\n ))}\n </div>\n\n {/* Pagination */}\n <div className=\"flex justify-between items-center\">\n <Skeleton className=\"h-4 w-32\" />\n <div className=\"flex gap-2\">\n <Skeleton className=\"h-10 w-20\" />\n <Skeleton className=\"h-10 w-20\" />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["_","jsx","jsxs"]}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/components/skeletons/auth-form-skeleton.tsx
4
- import { Skeleton } from "@mesob/ui/components/skeleton";
4
+ import { Skeleton } from "@mesob/ui/components";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  function AuthFormSkeleton() {
7
7
  return /* @__PURE__ */ jsxs("div", { className: "w-full max-w-md space-y-6 p-6", children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/skeletons/auth-form-skeleton.tsx"],"sourcesContent":["'use client';\n\nimport { Skeleton } from '@mesob/ui/components/skeleton';\n\nexport function AuthFormSkeleton() {\n return (\n <div className=\"w-full max-w-md space-y-6 p-6\">\n <div className=\"space-y-2 text-center\">\n <Skeleton className=\"h-8 w-48 mx-auto\" />\n <Skeleton className=\"h-4 w-64 mx-auto\" />\n </div>\n\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n\n <Skeleton className=\"h-10 w-full\" />\n </div>\n\n <div className=\"space-y-2\">\n <Skeleton className=\"h-px w-full\" />\n <Skeleton className=\"h-4 w-32 mx-auto\" />\n </div>\n </div>\n );\n}\n"],"mappings":";;;AAEA,SAAS,gBAAgB;AAKnB,SACE,KADF;AAHC,SAAS,mBAAmB;AACjC,SACE,qBAAC,SAAI,WAAU,iCACb;AAAA,yBAAC,SAAI,WAAU,yBACb;AAAA,0BAAC,YAAS,WAAU,oBAAmB;AAAA,MACvC,oBAAC,YAAS,WAAU,oBAAmB;AAAA,OACzC;AAAA,IAEA,qBAAC,SAAI,WAAU,aACb;AAAA,2BAAC,SAAI,WAAU,aACb;AAAA,4BAAC,YAAS,WAAU,YAAW;AAAA,QAC/B,oBAAC,YAAS,WAAU,eAAc;AAAA,SACpC;AAAA,MAEA,qBAAC,SAAI,WAAU,aACb;AAAA,4BAAC,YAAS,WAAU,YAAW;AAAA,QAC/B,oBAAC,YAAS,WAAU,eAAc;AAAA,SACpC;AAAA,MAEA,oBAAC,YAAS,WAAU,eAAc;AAAA,OACpC;AAAA,IAEA,qBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,YAAS,WAAU,eAAc;AAAA,MAClC,oBAAC,YAAS,WAAU,oBAAmB;AAAA,OACzC;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/skeletons/auth-form-skeleton.tsx"],"sourcesContent":["'use client';\n\nimport { Skeleton } from '@mesob/ui/components';\n\nexport function AuthFormSkeleton() {\n return (\n <div className=\"w-full max-w-md space-y-6 p-6\">\n <div className=\"space-y-2 text-center\">\n <Skeleton className=\"h-8 w-48 mx-auto\" />\n <Skeleton className=\"h-4 w-64 mx-auto\" />\n </div>\n\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n\n <Skeleton className=\"h-10 w-full\" />\n </div>\n\n <div className=\"space-y-2\">\n <Skeleton className=\"h-px w-full\" />\n <Skeleton className=\"h-4 w-32 mx-auto\" />\n </div>\n </div>\n );\n}\n"],"mappings":";;;AAEA,SAAS,gBAAgB;AAKnB,SACE,KADF;AAHC,SAAS,mBAAmB;AACjC,SACE,qBAAC,SAAI,WAAU,iCACb;AAAA,yBAAC,SAAI,WAAU,yBACb;AAAA,0BAAC,YAAS,WAAU,oBAAmB;AAAA,MACvC,oBAAC,YAAS,WAAU,oBAAmB;AAAA,OACzC;AAAA,IAEA,qBAAC,SAAI,WAAU,aACb;AAAA,2BAAC,SAAI,WAAU,aACb;AAAA,4BAAC,YAAS,WAAU,YAAW;AAAA,QAC/B,oBAAC,YAAS,WAAU,eAAc;AAAA,SACpC;AAAA,MAEA,qBAAC,SAAI,WAAU,aACb;AAAA,4BAAC,YAAS,WAAU,YAAW;AAAA,QAC/B,oBAAC,YAAS,WAAU,eAAc;AAAA,SACpC;AAAA,MAEA,oBAAC,YAAS,WAAU,eAAc;AAAA,OACpC;AAAA,IAEA,qBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,YAAS,WAAU,eAAc;AAAA,MAClC,oBAAC,YAAS,WAAU,oBAAmB;AAAA,OACzC;AAAA,KACF;AAEJ;","names":[]}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/components/skeletons/profile-skeleton.tsx
4
- import { Skeleton } from "@mesob/ui/components/skeleton";
4
+ import { Skeleton } from "@mesob/ui/components";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  function ProfileSkeleton() {
7
7
  return /* @__PURE__ */ jsxs("div", { className: "w-full max-w-4xl space-y-8 p-6", children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/skeletons/profile-skeleton.tsx"],"sourcesContent":["'use client';\n\nimport { Skeleton } from '@mesob/ui/components/skeleton';\n\nexport function ProfileSkeleton() {\n return (\n <div className=\"w-full max-w-4xl space-y-8 p-6\">\n {/* Header */}\n <div className=\"flex items-center gap-6\">\n <Skeleton className=\"h-24 w-24 rounded-full\" />\n <div className=\"space-y-2 flex-1\">\n <Skeleton className=\"h-8 w-48\" />\n <Skeleton className=\"h-4 w-64\" />\n </div>\n </div>\n\n {/* Profile sections */}\n <div className=\"space-y-6\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"space-y-4\">\n <Skeleton className=\"h-6 w-32\" />\n <div className=\"space-y-3\">\n <div className=\"flex justify-between items-center\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-4 w-32\" />\n </div>\n <div className=\"flex justify-between items-center\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-4 w-40\" />\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":";;;AAEA,SAAS,gBAAgB;AAOjB,cACA,YADA;AALD,SAAS,kBAAkB;AAChC,SACE,qBAAC,SAAI,WAAU,kCAEb;AAAA,yBAAC,SAAI,WAAU,2BACb;AAAA,0BAAC,YAAS,WAAU,0BAAyB;AAAA,MAC7C,qBAAC,SAAI,WAAU,oBACb;AAAA,4BAAC,YAAS,WAAU,YAAW;AAAA,QAC/B,oBAAC,YAAS,WAAU,YAAW;AAAA,SACjC;AAAA,OACF;AAAA,IAGA,oBAAC,SAAI,WAAU,aACZ,WAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,qBAAC,SAAY,WAAU,aACrB;AAAA,0BAAC,YAAS,WAAU,YAAW;AAAA,MAC/B,qBAAC,SAAI,WAAU,aACb;AAAA,6BAAC,SAAI,WAAU,qCACb;AAAA,8BAAC,YAAS,WAAU,YAAW;AAAA,UAC/B,oBAAC,YAAS,WAAU,YAAW;AAAA,WACjC;AAAA,QACA,qBAAC,SAAI,WAAU,qCACb;AAAA,8BAAC,YAAS,WAAU,YAAW;AAAA,UAC/B,oBAAC,YAAS,WAAU,YAAW;AAAA,WACjC;AAAA,SACF;AAAA,SAXQ,CAYV,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/skeletons/profile-skeleton.tsx"],"sourcesContent":["'use client';\n\nimport { Skeleton } from '@mesob/ui/components';\n\nexport function ProfileSkeleton() {\n return (\n <div className=\"w-full max-w-4xl space-y-8 p-6\">\n {/* Header */}\n <div className=\"flex items-center gap-6\">\n <Skeleton className=\"h-24 w-24 rounded-full\" />\n <div className=\"space-y-2 flex-1\">\n <Skeleton className=\"h-8 w-48\" />\n <Skeleton className=\"h-4 w-64\" />\n </div>\n </div>\n\n {/* Profile sections */}\n <div className=\"space-y-6\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"space-y-4\">\n <Skeleton className=\"h-6 w-32\" />\n <div className=\"space-y-3\">\n <div className=\"flex justify-between items-center\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-4 w-32\" />\n </div>\n <div className=\"flex justify-between items-center\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-4 w-40\" />\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":";;;AAEA,SAAS,gBAAgB;AAOjB,cACA,YADA;AALD,SAAS,kBAAkB;AAChC,SACE,qBAAC,SAAI,WAAU,kCAEb;AAAA,yBAAC,SAAI,WAAU,2BACb;AAAA,0BAAC,YAAS,WAAU,0BAAyB;AAAA,MAC7C,qBAAC,SAAI,WAAU,oBACb;AAAA,4BAAC,YAAS,WAAU,YAAW;AAAA,QAC/B,oBAAC,YAAS,WAAU,YAAW;AAAA,SACjC;AAAA,OACF;AAAA,IAGA,oBAAC,SAAI,WAAU,aACZ,WAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,qBAAC,SAAY,WAAU,aACrB;AAAA,0BAAC,YAAS,WAAU,YAAW;AAAA,MAC/B,qBAAC,SAAI,WAAU,aACb;AAAA,6BAAC,SAAI,WAAU,qCACb;AAAA,8BAAC,YAAS,WAAU,YAAW;AAAA,UAC/B,oBAAC,YAAS,WAAU,YAAW;AAAA,WACjC;AAAA,QACA,qBAAC,SAAI,WAAU,qCACb;AAAA,8BAAC,YAAS,WAAU,YAAW;AAAA,UAC/B,oBAAC,YAAS,WAAU,YAAW;AAAA,WACjC;AAAA,SACF;AAAA,SAXQ,CAYV,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/components/skeletons/table-skeleton.tsx
4
- import { Skeleton } from "@mesob/ui/components/skeleton";
4
+ import { Skeleton } from "@mesob/ui/components";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  function TableSkeleton({ columns = 5, rows = 10 }) {
7
7
  const headerKeys = Array.from({ length: columns }, (_, i) => `header-${i}`);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/skeletons/table-skeleton.tsx"],"sourcesContent":["'use client';\n\nimport { Skeleton } from '@mesob/ui/components/skeleton';\n\ntype TableSkeletonProps = {\n columns?: number;\n rows?: number;\n};\n\nexport function TableSkeleton({ columns = 5, rows = 10 }: TableSkeletonProps) {\n const headerKeys = Array.from({ length: columns }, (_, i) => `header-${i}`);\n const rowKeys = Array.from({ length: rows }, (_, i) => `row-${i}`);\n const cellKeys = Array.from({ length: rows }, (_, rowIdx) =>\n Array.from({ length: columns }, (_, colIdx) => `cell-${rowIdx}-${colIdx}`),\n );\n\n return (\n <div className=\"w-full space-y-4\">\n {/* Header */}\n <div className=\"flex justify-between items-center\">\n <Skeleton className=\"h-8 w-48\" />\n <Skeleton className=\"h-10 w-32\" />\n </div>\n\n {/* Search/filters */}\n <div className=\"flex gap-4\">\n <Skeleton className=\"h-10 flex-1 max-w-sm\" />\n <Skeleton className=\"h-10 w-24\" />\n <Skeleton className=\"h-10 w-24\" />\n </div>\n\n {/* Table */}\n <div className=\"border rounded-lg overflow-hidden\">\n {/* Table header */}\n <div className=\"flex gap-4 p-4 bg-muted\">\n {headerKeys.map((key) => (\n <Skeleton key={key} className=\"h-4 flex-1\" />\n ))}\n </div>\n\n {/* Table rows */}\n {rowKeys.map((rowKey, rowIdx) => (\n <div key={rowKey} className=\"flex gap-4 p-4 border-t\">\n {cellKeys[rowIdx]?.map((cellKey) => (\n <Skeleton key={cellKey} className=\"h-4 flex-1\" />\n ))}\n </div>\n ))}\n </div>\n\n {/* Pagination */}\n <div className=\"flex justify-between items-center\">\n <Skeleton className=\"h-4 w-32\" />\n <div className=\"flex gap-2\">\n <Skeleton className=\"h-10 w-20\" />\n <Skeleton className=\"h-10 w-20\" />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;AAEA,SAAS,gBAAgB;AAiBnB,SACE,KADF;AAVC,SAAS,cAAc,EAAE,UAAU,GAAG,OAAO,GAAG,GAAuB;AAC5E,QAAM,aAAa,MAAM,KAAK,EAAE,QAAQ,QAAQ,GAAG,CAAC,GAAG,MAAM,UAAU,CAAC,EAAE;AAC1E,QAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,KAAK,GAAG,CAAC,GAAG,MAAM,OAAO,CAAC,EAAE;AACjE,QAAM,WAAW,MAAM;AAAA,IAAK,EAAE,QAAQ,KAAK;AAAA,IAAG,CAAC,GAAG,WAChD,MAAM,KAAK,EAAE,QAAQ,QAAQ,GAAG,CAACA,IAAG,WAAW,QAAQ,MAAM,IAAI,MAAM,EAAE;AAAA,EAC3E;AAEA,SACE,qBAAC,SAAI,WAAU,oBAEb;AAAA,yBAAC,SAAI,WAAU,qCACb;AAAA,0BAAC,YAAS,WAAU,YAAW;AAAA,MAC/B,oBAAC,YAAS,WAAU,aAAY;AAAA,OAClC;AAAA,IAGA,qBAAC,SAAI,WAAU,cACb;AAAA,0BAAC,YAAS,WAAU,wBAAuB;AAAA,MAC3C,oBAAC,YAAS,WAAU,aAAY;AAAA,MAChC,oBAAC,YAAS,WAAU,aAAY;AAAA,OAClC;AAAA,IAGA,qBAAC,SAAI,WAAU,qCAEb;AAAA,0BAAC,SAAI,WAAU,2BACZ,qBAAW,IAAI,CAAC,QACf,oBAAC,YAAmB,WAAU,gBAAf,GAA4B,CAC5C,GACH;AAAA,MAGC,QAAQ,IAAI,CAAC,QAAQ,WACpB,oBAAC,SAAiB,WAAU,2BACzB,mBAAS,MAAM,GAAG,IAAI,CAAC,YACtB,oBAAC,YAAuB,WAAU,gBAAnB,OAAgC,CAChD,KAHO,MAIV,CACD;AAAA,OACH;AAAA,IAGA,qBAAC,SAAI,WAAU,qCACb;AAAA,0BAAC,YAAS,WAAU,YAAW;AAAA,MAC/B,qBAAC,SAAI,WAAU,cACb;AAAA,4BAAC,YAAS,WAAU,aAAY;AAAA,QAChC,oBAAC,YAAS,WAAU,aAAY;AAAA,SAClC;AAAA,OACF;AAAA,KACF;AAEJ;","names":["_"]}
1
+ {"version":3,"sources":["../../../src/components/skeletons/table-skeleton.tsx"],"sourcesContent":["'use client';\n\nimport { Skeleton } from '@mesob/ui/components';\n\ntype TableSkeletonProps = {\n columns?: number;\n rows?: number;\n};\n\nexport function TableSkeleton({ columns = 5, rows = 10 }: TableSkeletonProps) {\n const headerKeys = Array.from({ length: columns }, (_, i) => `header-${i}`);\n const rowKeys = Array.from({ length: rows }, (_, i) => `row-${i}`);\n const cellKeys = Array.from({ length: rows }, (_, rowIdx) =>\n Array.from({ length: columns }, (_, colIdx) => `cell-${rowIdx}-${colIdx}`),\n );\n\n return (\n <div className=\"w-full space-y-4\">\n {/* Header */}\n <div className=\"flex justify-between items-center\">\n <Skeleton className=\"h-8 w-48\" />\n <Skeleton className=\"h-10 w-32\" />\n </div>\n\n {/* Search/filters */}\n <div className=\"flex gap-4\">\n <Skeleton className=\"h-10 flex-1 max-w-sm\" />\n <Skeleton className=\"h-10 w-24\" />\n <Skeleton className=\"h-10 w-24\" />\n </div>\n\n {/* Table */}\n <div className=\"border rounded-lg overflow-hidden\">\n {/* Table header */}\n <div className=\"flex gap-4 p-4 bg-muted\">\n {headerKeys.map((key) => (\n <Skeleton key={key} className=\"h-4 flex-1\" />\n ))}\n </div>\n\n {/* Table rows */}\n {rowKeys.map((rowKey, rowIdx) => (\n <div key={rowKey} className=\"flex gap-4 p-4 border-t\">\n {cellKeys[rowIdx]?.map((cellKey) => (\n <Skeleton key={cellKey} className=\"h-4 flex-1\" />\n ))}\n </div>\n ))}\n </div>\n\n {/* Pagination */}\n <div className=\"flex justify-between items-center\">\n <Skeleton className=\"h-4 w-32\" />\n <div className=\"flex gap-2\">\n <Skeleton className=\"h-10 w-20\" />\n <Skeleton className=\"h-10 w-20\" />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;AAEA,SAAS,gBAAgB;AAiBnB,SACE,KADF;AAVC,SAAS,cAAc,EAAE,UAAU,GAAG,OAAO,GAAG,GAAuB;AAC5E,QAAM,aAAa,MAAM,KAAK,EAAE,QAAQ,QAAQ,GAAG,CAAC,GAAG,MAAM,UAAU,CAAC,EAAE;AAC1E,QAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,KAAK,GAAG,CAAC,GAAG,MAAM,OAAO,CAAC,EAAE;AACjE,QAAM,WAAW,MAAM;AAAA,IAAK,EAAE,QAAQ,KAAK;AAAA,IAAG,CAAC,GAAG,WAChD,MAAM,KAAK,EAAE,QAAQ,QAAQ,GAAG,CAACA,IAAG,WAAW,QAAQ,MAAM,IAAI,MAAM,EAAE;AAAA,EAC3E;AAEA,SACE,qBAAC,SAAI,WAAU,oBAEb;AAAA,yBAAC,SAAI,WAAU,qCACb;AAAA,0BAAC,YAAS,WAAU,YAAW;AAAA,MAC/B,oBAAC,YAAS,WAAU,aAAY;AAAA,OAClC;AAAA,IAGA,qBAAC,SAAI,WAAU,cACb;AAAA,0BAAC,YAAS,WAAU,wBAAuB;AAAA,MAC3C,oBAAC,YAAS,WAAU,aAAY;AAAA,MAChC,oBAAC,YAAS,WAAU,aAAY;AAAA,OAClC;AAAA,IAGA,qBAAC,SAAI,WAAU,qCAEb;AAAA,0BAAC,SAAI,WAAU,2BACZ,qBAAW,IAAI,CAAC,QACf,oBAAC,YAAmB,WAAU,gBAAf,GAA4B,CAC5C,GACH;AAAA,MAGC,QAAQ,IAAI,CAAC,QAAQ,WACpB,oBAAC,SAAiB,WAAU,2BACzB,mBAAS,MAAM,GAAG,IAAI,CAAC,YACtB,oBAAC,YAAuB,WAAU,gBAAnB,OAAgC,CAChD,KAHO,MAIV,CACD;AAAA,OACH;AAAA,IAGA,qBAAC,SAAI,WAAU,qCACb;AAAA,0BAAC,YAAS,WAAU,YAAW;AAAA,MAC/B,qBAAC,SAAI,WAAU,cACb;AAAA,4BAAC,YAAS,WAAU,aAAY;AAAA,QAChC,oBAAC,YAAS,WAAU,aAAY;AAAA,SAClC;AAAA,OACF;AAAA,KACF;AAEJ;","names":["_"]}