{"version":3,"sources":["../../src/hooks/use-server-action.ts","../../src/next/errors/redirect.ts","../../src/next/errors/http-access-fallback.ts","../../src/next/errors/index.ts","../../src/hooks/use-optimistic-action.ts","../../src/hooks/use-form-action.ts","../../src/hooks/toast-restorer.tsx"],"sourcesContent":["import { useCallback, useState, useTransition } from \"react\";\nimport { useRouter } from \"next/navigation\";\nimport { toast } from \"sonner\";\nimport type { ServerAction, ActionResult, ServerActionResponse } from \"../types\";\nimport { isNextNavigationError } from \"../next/errors\";\n\nexport interface UseServerActionOptions<TOutput> {\n  onSuccess?: (data: TOutput) => void | Promise<void>;\n  onError?: (error: ActionResult<TOutput>) => void | Promise<void>;\n  \n  successMessage?: string | ((data: TOutput) => string);\n  errorMessage?: string | ((error: ActionResult<TOutput>) => string);\n  showSuccessToast?: boolean;\n  showErrorToast?: boolean;\n  \n  redirectOnAuthError?: boolean;\n  preventRedirect?: boolean;\n  redirectDelay?: number;\n}\n\nexport interface UseServerActionReturn<TInput, TOutput> {\n  execute: TInput extends void \n    ? () => Promise<ActionResult<TOutput>>\n    : (input: TInput) => Promise<ActionResult<TOutput>>;\n  \n  result: ActionResult<TOutput> | undefined;\n  isExecuting: boolean;\n  isRedirecting: boolean;\n  hasSucceeded: boolean;\n  hasErrored: boolean;\n  \n  reset: () => void;\n}\n\n// Overload for void actions\nexport function useServerAction<TOutput>(\n  action: ServerAction<void, TOutput>,\n  options?: UseServerActionOptions<TOutput>\n): UseServerActionReturn<void, TOutput>;\n\n// Overload for actions with input\nexport function useServerAction<TInput, TOutput>(\n  action: ServerAction<TInput, TOutput>,\n  options?: UseServerActionOptions<TOutput>\n): UseServerActionReturn<TInput, TOutput>;\n\n// Implementation\nexport function useServerAction<TInput, TOutput>(\n  action: ServerAction<TInput, TOutput>,\n  options: UseServerActionOptions<TOutput> = {}\n): UseServerActionReturn<TInput, TOutput> {\n  const router = useRouter();\n  const [result, setResult] = useState<ActionResult<TOutput>>();\n  const [isExecuting, setIsExecuting] = useState(false);\n  const [isRedirecting, setIsRedirecting] = useState(false);\n  const [, startTransition] = useTransition();\n  \n  const {\n    onSuccess,\n    onError,\n    successMessage,\n    errorMessage,\n    showSuccessToast = false,\n    showErrorToast = true,\n    redirectOnAuthError = true,\n    preventRedirect = false,\n    redirectDelay = 0,\n  } = options;\n  \n  const hasSucceeded = !!result?.data;\n  const hasErrored = !!result?.serverError || !!result?.validationErrors || !!result?.fetchError;\n  \n  const reset = useCallback(() => {\n    setResult(undefined);\n    setIsRedirecting(false);\n  }, []);\n\n  // Internal execute function without isExecuting state management\n  const executeInternal = useCallback(\n    async (input?: TInput): Promise<ActionResult<TOutput>> => {\n      try {\n        const response = await (input === undefined \n          ? (action as () => Promise<ServerActionResponse<TOutput>>)()\n          : (action as (input: TInput) => Promise<ServerActionResponse<TOutput>>)(input));\n        \n        let actionResult: ActionResult<TOutput>;\n        \n        if (response.success) {\n          actionResult = { data: response.data };\n          \n          if (process.env.NODE_ENV === 'development') {\n            console.log('[useServerAction] Success response:', response);\n            console.log('[useServerAction] Has redirect?', !!response.redirect);\n          }\n          \n          if (showSuccessToast && successMessage) {\n            const message = typeof successMessage === \"function\" \n              ? successMessage(response.data) \n              : successMessage;\n            toast.success(message);\n          }\n          \n          await onSuccess?.(response.data);\n          \n          // Handle redirect if present in response\n          if (response.redirect && !preventRedirect) {\n            setIsRedirecting(true);\n            const redirectConfig = typeof response.redirect === 'string'\n              ? { url: response.redirect }\n              : response.redirect;\n            \n            const delay = redirectConfig.delay ?? redirectDelay;\n            \n            setTimeout(() => {\n              if (redirectConfig.replace) {\n                router.replace(redirectConfig.url);\n              } else {\n                router.push(redirectConfig.url);\n              }\n              // Don't reset isRedirecting - the component will unmount anyway\n            }, delay);\n          }\n          \n        } else if (!response.success && response.error) {\n          actionResult = {\n            serverError: response.error,\n            validationErrors: response.error.fields,\n          };\n          \n          // Debug logging\n          if (process.env.NODE_ENV === 'development') {\n            console.log('[useServerAction] Error response:', response.error);\n            console.log('[useServerAction] Should redirect?', response.error.shouldRedirect);\n            console.log('[useServerAction] Redirect to:', response.error.redirectTo);\n          }\n          \n          if (redirectOnAuthError && response.error.shouldRedirect) {\n            // Handle toast before redirect\n            if (showErrorToast) {\n              const message = errorMessage \n                ? (typeof errorMessage === \"function\" \n                    ? errorMessage(actionResult) \n                    : errorMessage)\n                : response.error.message || \"An error occurred\";\n              \n              // Always save to localStorage for redirect cases\n              // This ensures compatibility with both current and future sonner versions\n              if (typeof window !== 'undefined') {\n                try {\n                  const storageKey = 'sonner-toasts';\n                  const existingToasts = JSON.parse(\n                    localStorage.getItem(storageKey) || '[]'\n                  );\n                  \n                  // Add our toast in the same format as the PR\n                  const persistentToast = {\n                    id: Date.now(),\n                    type: 'error',\n                    message,\n                    persistent: true,\n                    createdAt: Date.now()\n                  };\n                  \n                  existingToasts.push(persistentToast);\n                  localStorage.setItem(storageKey, JSON.stringify(existingToasts));\n                } catch (err) {\n                  console.error('Failed to persist toast:', err);\n                }\n              }\n              \n              // Always show the toast (with persistent if supported)\n              (toast.error as any)(message, { persistent: true });\n            }\n            \n            setIsRedirecting(true);\n            router.push(response.error.redirectTo || \"/login\");\n            return actionResult;\n          }\n          \n          if (showErrorToast) {\n            const message = errorMessage \n              ? (typeof errorMessage === \"function\" \n                  ? errorMessage(actionResult) \n                  : errorMessage)\n              : response.error.message || \"An error occurred\";\n            toast.error(message);\n          }\n          \n          await onError?.(actionResult);\n        } else {\n          actionResult = { fetchError: \"Unexpected response format\" };\n        }\n        \n        setResult(actionResult);\n        return actionResult;\n        \n      } catch (error) {\n        // Check if this is a Next.js navigation error that should be re-thrown\n        if (isNextNavigationError(error)) {\n          // Re-throw navigation errors to let Next.js handle them\n          throw error;\n        }\n        \n        const fetchError = error instanceof Error ? error.message : \"Network error\";\n        const actionResult: ActionResult<TOutput> = { fetchError };\n        \n        setResult(actionResult);\n        \n        if (showErrorToast) {\n          toast.error(fetchError);\n        }\n        \n        await onError?.(actionResult);\n        return actionResult;\n      }\n    },\n    [action, router, showSuccessToast, successMessage, showErrorToast, errorMessage, redirectOnAuthError, onSuccess, onError]\n  );\n\n  const execute = useCallback(\n    (...args: TInput extends void ? [] : [input: TInput]): Promise<ActionResult<TOutput>> => {\n      // ✅ Set isExecuting immediately (urgent update) to prevent spam clicks\n      setIsExecuting(true);\n\n      return new Promise((resolve) => {\n        startTransition(async () => {\n          try {\n            // ✅ Use executeInternal which doesn't manage isExecuting state\n            const result = await executeInternal(args[0] as TInput);\n            resolve(result);\n          } catch (error) {\n            // Handle any unexpected errors\n            const fetchError = error instanceof Error ? error.message : \"Unexpected error\";\n            resolve({ fetchError });\n          } finally {\n            // ✅ Clear isExecuting after operation completes\n            setIsExecuting(false);\n          }\n        });\n      });\n    },\n    [executeInternal]\n  ) as TInput extends void \n    ? () => Promise<ActionResult<TOutput>>\n    : (input: TInput) => Promise<ActionResult<TOutput>>;\n  \n  return {\n    execute,\n    result,\n    isExecuting,\n    isRedirecting,\n    hasSucceeded,\n    hasErrored,\n    reset,\n  };\n}\n\n","// Comes from: https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/redirect-error.ts\n\nenum RedirectStatusCode {\n\tSeeOther = 303,\n\tTemporaryRedirect = 307,\n\tPermanentRedirect = 308,\n}\n\nconst REDIRECT_ERROR_CODE = \"NEXT_REDIRECT\";\n\nenum RedirectType {\n\tpush = \"push\",\n\treplace = \"replace\",\n}\n\nexport type RedirectError = Error & {\n\tdigest: `${typeof REDIRECT_ERROR_CODE};${RedirectType};${string};${RedirectStatusCode};`;\n};\n\n/**\n * Checks an error to determine if it's an error generated by the\n * `redirect(url)` helper.\n *\n * @param error the error that may reference a redirect error\n * @returns true if the error is a redirect error\n */\nexport function isRedirectError(error: unknown): error is RedirectError {\n\tif (typeof error !== \"object\" || error === null || !(\"digest\" in error) || typeof error.digest !== \"string\") {\n\t\treturn false;\n\t}\n\n\tconst digest = error.digest.split(\";\");\n\tconst [errorCode, type] = digest;\n\tconst destination = digest.slice(2, -2).join(\";\");\n\tconst status = digest.at(-2);\n\n\tconst statusCode = Number(status);\n\n\treturn (\n\t\terrorCode === REDIRECT_ERROR_CODE &&\n\t\t(type === \"replace\" || type === \"push\") &&\n\t\ttypeof destination === \"string\" &&\n\t\t!isNaN(statusCode) &&\n\t\tstatusCode in RedirectStatusCode\n\t);\n}","// Comes from https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/http-access-fallback/http-access-fallback.ts\n\nconst HTTPAccessErrorStatus = {\n\tNOT_FOUND: 404,\n\tFORBIDDEN: 403,\n\tUNAUTHORIZED: 401,\n};\n\nconst ALLOWED_CODES = new Set(Object.values(HTTPAccessErrorStatus));\n\nconst HTTP_ERROR_FALLBACK_ERROR_CODE = \"NEXT_HTTP_ERROR_FALLBACK\";\n\nexport type HTTPAccessFallbackError = Error & {\n\tdigest: `${typeof HTTP_ERROR_FALLBACK_ERROR_CODE};${string}`;\n};\n\n/**\n * Checks an error to determine if it's an error generated by\n * the HTTP navigation APIs `notFound()`, `forbidden()` or `unauthorized()`.\n *\n * @param error the error that may reference a HTTP access error\n * @returns true if the error is a HTTP access error\n */\nexport function isHTTPAccessFallbackError(error: unknown): error is HTTPAccessFallbackError {\n\tif (typeof error !== \"object\" || error === null || !(\"digest\" in error) || typeof error.digest !== \"string\") {\n\t\treturn false;\n\t}\n\tconst [prefix, httpStatus] = error.digest.split(\";\");\n\n\treturn prefix === HTTP_ERROR_FALLBACK_ERROR_CODE && ALLOWED_CODES.has(Number(httpStatus));\n}\n\nexport function getAccessFallbackHTTPStatus(error: HTTPAccessFallbackError): number {\n\tconst httpStatus = error.digest.split(\";\")[1];\n\treturn Number(httpStatus);\n}","import { isRedirectError } from \"./redirect\";\nimport { isHTTPAccessFallbackError, getAccessFallbackHTTPStatus } from \"./http-access-fallback\";\n\nexport { isRedirectError } from \"./redirect\";\nexport type { RedirectError } from \"./redirect\";\n\nexport { isHTTPAccessFallbackError, getAccessFallbackHTTPStatus } from \"./http-access-fallback\";\nexport type { HTTPAccessFallbackError } from \"./http-access-fallback\";\n\n/**\n * Checks if the error is a navigation error that should be re-thrown\n * This includes redirect errors and HTTP access errors (notFound, forbidden, unauthorized)\n */\nexport function isNextNavigationError(error: unknown): boolean {\n\treturn isRedirectError(error) || isHTTPAccessFallbackError(error);\n}\n\n/**\n * Checks if the error is a notFound error\n * Note: Next.js implements notFound() using HTTP_ERROR_FALLBACK with status 404,\n * not as a separate error type like NEXT_REDIRECT\n */\nexport function isNotFoundError(error: unknown): boolean {\n\treturn isHTTPAccessFallbackError(error) && getAccessFallbackHTTPStatus(error as any) === 404;\n}","import { useOptimistic, useTransition } from \"react\";\nimport { useServerAction, type UseServerActionOptions } from \"./use-server-action\";\nimport type { ServerAction, ActionResult } from \"../types\";\n\nexport interface UseOptimisticActionOptions<TInput, TOutput, TOptimistic> extends UseServerActionOptions<TOutput> {\n  /**\n   * Function to update the optimistic state\n   */\n  updateFn: TInput extends void \n    ? (current: TOptimistic) => TOptimistic\n    : (current: TOptimistic, input: TInput) => TOptimistic;\n}\n\nexport interface UseOptimisticActionReturn<TInput, TOutput, TOptimistic> {\n  /**\n   * The optimistic state\n   */\n  optimisticState: TOptimistic;\n  \n  /**\n   * Execute the action with optimistic update\n   */\n  execute: TInput extends void \n    ? () => Promise<ActionResult<TOutput>>\n    : (input: TInput) => Promise<ActionResult<TOutput>>;\n  \n  /**\n   * Loading state\n   */\n  isExecuting: boolean;\n  \n  /**\n   * Success state\n   */\n  hasSucceeded: boolean;\n  \n  /**\n   * Error state\n   */\n  hasErrored: boolean;\n  \n  /**\n   * Last result\n   */\n  result: ActionResult<TOutput> | undefined;\n  \n  /**\n   * Reset state\n   */\n  reset: () => void;\n}\n\n/**\n * Hook for server actions with optimistic updates\n * \n * @example\n * ```typescript\n * const { optimisticState, execute } = useOptimisticAction(\n *   currentTodos,\n *   addTodoAction,\n *   {\n *     updateFn: (todos, newTodo) => [...todos, newTodo],\n *     onSuccess: (savedTodo) => {\n *       // Update with server response if needed\n *     }\n *   }\n * );\n * ```\n */\nexport function useOptimisticAction<TInput, TOutput, TOptimistic>(\n  initialState: TOptimistic,\n  action: ServerAction<TInput, TOutput>,\n  options: UseOptimisticActionOptions<TInput, TOutput, TOptimistic>\n): UseOptimisticActionReturn<TInput, TOutput, TOptimistic> {\n  const [optimisticState, addOptimisticUpdate] = useOptimistic(\n    initialState,\n    options.updateFn\n  );\n  \n  const [, startTransition] = useTransition();\n  \n  // Extract updateFn from options to pass the rest to useServerAction\n  const { updateFn: _, ...serverActionOptions } = options;\n  \n  const {\n    execute: executeAction,\n    isExecuting,\n    hasSucceeded,\n    hasErrored,\n    result,\n    reset\n  } = useServerAction(action, serverActionOptions);\n  \n  const execute = (async (input?: TInput): Promise<ActionResult<TOutput>> => {\n    // Apply optimistic update\n    startTransition(() => {\n      if (input !== undefined) {\n        addOptimisticUpdate(input);\n      } else {\n        addOptimisticUpdate(undefined as any);\n      }\n    });\n    \n    // Execute the server action\n    return executeAction(input as any);\n  }) as any;\n  \n  return {\n    optimisticState,\n    execute,\n    isExecuting,\n    hasSucceeded,\n    hasErrored,\n    result,\n    reset\n  };\n}","import { useActionState, useEffect, useTransition, useRef, useState } from \"react\";\nimport { useRouter } from \"next/navigation\";\nimport type { UseFormProps, UseFormReturn, Path, FieldValues, DefaultValues } from \"react-hook-form\";\nimport { useForm } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { toast } from \"sonner\";\nimport type { z } from \"zod\";\nimport type { ServerActionResponse, ServerActionError, RedirectConfig } from \"../types\";\n\nexport interface UseFormActionOptions<TFieldValues extends FieldValues, TOutput> {\n  // Required - the server action to execute (form action format)\n  action: (prevState: ServerActionResponse<TOutput>, formData: FormData) => Promise<ServerActionResponse<TOutput>>;\n  \n  // Optional Zod schema for validation\n  schema?: z.ZodTypeAny;\n  \n  // React Hook Form options\n  defaultValues?: DefaultValues<TFieldValues>;\n  mode?: UseFormProps<TFieldValues>[\"mode\"];\n  \n  // Transform function if you need custom FormData creation\n  transformData?: (data: TFieldValues) => FormData;\n  \n  // Callbacks\n  onSuccess?: (data: TOutput) => void | Promise<void>;\n  onError?: (error: ServerActionError) => void;\n  \n  // Behavior options\n  resetOnSuccess?: boolean;\n  showSuccessToast?: boolean | string | ((data: TOutput) => string);\n  showErrorToast?: boolean | string | ((error: ServerActionError) => string);\n  \n  // Redirect options (same as useServerAction)\n  preventRedirect?: boolean;\n  redirectDelay?: number;\n}\n\nexport interface UseFormActionReturn<TFieldValues extends FieldValues, TOutput> {\n  // React Hook Form instance\n  form: UseFormReturn<TFieldValues>;\n  \n  // Submit handler (pre-bound with handleSubmit)\n  onSubmit: (e?: React.BaseSyntheticEvent) => void;\n  \n  // Loading state (combines isPending and isTransitioning)\n  isSubmitting: boolean;\n  \n  // Redirecting state (true when redirect is in progress)\n  isRedirecting: boolean;\n  \n  // The current action state\n  actionState: ServerActionResponse<TOutput>;\n  \n  // Utilities\n  reset: () => void;\n  \n  // Raw handlers if needed\n  handleSubmit: (data: TFieldValues) => Promise<void>;\n}\n\nfunction isSuccessResponse<T>(response: ServerActionResponse<T>): response is { success: true; data: T; redirect?: string | RedirectConfig } {\n  return response.success === true;\n}\n\nfunction objectToFormData(obj: any): FormData {\n  const formData = new FormData();\n  \n  Object.entries(obj).forEach(([key, value]) => {\n    if (value !== undefined && value !== null) {\n      if (value instanceof File || value instanceof Blob) {\n        formData.append(key, value);\n      } else if (Array.isArray(value)) {\n        value.forEach((item) => formData.append(`${key}[]`, String(item)));\n      } else if (typeof value === \"object\") {\n        formData.append(key, JSON.stringify(value));\n      } else {\n        formData.append(key, String(value));\n      }\n    }\n  });\n  \n  return formData;\n}\n\nexport function useFormAction<TFieldValues extends FieldValues = FieldValues, TOutput = void>({\n  action,\n  schema,\n  defaultValues,\n  mode = \"onChange\",\n  transformData,\n  onSuccess,\n  onError,\n  resetOnSuccess = false,\n  showSuccessToast = false,\n  showErrorToast = true,\n  preventRedirect = false,\n  redirectDelay = 0,\n}: UseFormActionOptions<TFieldValues, TOutput>): UseFormActionReturn<TFieldValues, TOutput> {\n  const router = useRouter();\n  const [isRedirecting, setIsRedirecting] = useState(false);\n  \n  // Store callbacks in refs to prevent effect re-runs\n  const onSuccessRef = useRef(onSuccess);\n  const onErrorRef = useRef(onError);\n  const showSuccessToastRef = useRef(showSuccessToast);\n  const showErrorToastRef = useRef(showErrorToast);\n  \n  // Update refs when callbacks change\n  useEffect(() => {\n    onSuccessRef.current = onSuccess;\n    onErrorRef.current = onError;\n    showSuccessToastRef.current = showSuccessToast;\n    showErrorToastRef.current = showErrorToast;\n  });\n  \n  // 1. Setup form with React Hook Form\n  const form = useForm<TFieldValues>({\n    resolver: schema ? (zodResolver as any)(schema) : undefined,\n    defaultValues,\n    mode,\n  } as UseFormProps<TFieldValues>);\n  \n  // 2. Setup server action state with useActionState\n  const initialState: ServerActionResponse<TOutput> = { success: true, data: undefined as TOutput };\n  const [actionState, formAction, isPending] = useActionState(action, initialState);\n  const [isTransitioning, startTransition] = useTransition();\n  \n  // 3. Handle server errors and success\n  useEffect(() => {\n    // Skip initial state\n    if (actionState.success === true && actionState.data === undefined) {\n      return;\n    }\n    \n    // Reset redirecting state if we're processing a new action\n    setIsRedirecting(false);\n    \n    // Keep track of timeout for cleanup\n    let timeoutId: NodeJS.Timeout | undefined;\n    \n    if (!isSuccessResponse(actionState) && actionState.error) {\n      const { error } = actionState;\n      \n      // Map field errors to form\n      if (error.fields) {\n        Object.entries(error.fields).forEach(([field, messages]) => {\n          if (Array.isArray(messages) && messages.length > 0) {\n            form.setError(field as Path<TFieldValues>, {\n              type: \"server\",\n              message: messages[0],\n            });\n          }\n        });\n      }\n      \n      // Single field error\n      if (error.field && error.message && !error.fields) {\n        form.setError(error.field as Path<TFieldValues>, {\n          type: \"server\",\n          message: error.message,\n        });\n      }\n      \n      // Global error (no specific field)\n      if (error.message && !error.field && !error.fields) {\n        const showToast = showErrorToastRef.current;\n        if (showToast) {\n          const message = typeof showToast === \"function\" \n            ? showToast(error)\n            : typeof showToast === \"string\"\n            ? showToast\n            : error.message;\n          toast.error(message);\n        }\n        \n        // Also set on root for inline display\n        form.setError(\"root\", {\n          type: \"server\",\n          message: error.message,\n        });\n      }\n      \n      // Call error callback\n      onErrorRef.current?.(error);\n    }\n    \n    // Handle success\n    if (isSuccessResponse(actionState) && actionState.data !== undefined) {\n      const showToast = showSuccessToastRef.current;\n      if (showToast) {\n        const message = typeof showToast === \"function\"\n          ? showToast(actionState.data)\n          : typeof showToast === \"string\"\n          ? showToast\n          : \"Success!\";\n        toast.success(message);\n      }\n      \n      if (resetOnSuccess) {\n        form.reset();\n      }\n      \n      // Call success callback first\n      onSuccessRef.current?.(actionState.data);\n      \n      // Handle redirect if present in response - delay to ensure state updates complete\n      if (actionState.redirect && !preventRedirect) {\n        setIsRedirecting(true);\n        const redirectConfig = typeof actionState.redirect === 'string'\n          ? { url: actionState.redirect }\n          : actionState.redirect;\n        \n        const delay = redirectConfig.delay ?? redirectDelay;\n        \n        timeoutId = setTimeout(() => {\n          if (redirectConfig.replace) {\n            router.replace(redirectConfig.url);\n          } else {\n            router.push(redirectConfig.url);\n          }\n          // Don't reset isRedirecting - the component will unmount anyway\n        }, delay || 100); // Add small delay by default\n      }\n    }\n    \n    // Always return cleanup function\n    return () => {\n      if (timeoutId) {\n        clearTimeout(timeoutId);\n      }\n    };\n  }, [actionState]); // Minimal dependencies - only actionState\n  \n  // 4. Submit handler\n  const handleSubmit = async (data: TFieldValues): Promise<void> => {\n    // Clear any previous errors\n    form.clearErrors();\n    \n    // Transform to FormData\n    const formData = transformData \n      ? transformData(data)\n      : objectToFormData(data);\n    \n    // Execute with transition for better UX\n    startTransition(() => {\n      formAction(formData);\n    });\n  };\n  \n  // 5. Combined loading state\n  const isSubmitting = isPending || isTransitioning;\n  \n  // 6. Pre-bound submit handler\n  const onSubmit = (e?: React.BaseSyntheticEvent): void => {\n    e?.preventDefault();\n    void form.handleSubmit(handleSubmit)(e!);\n  };\n  \n  return {\n    form,\n    onSubmit,\n    isSubmitting,\n    isRedirecting,\n    actionState,\n    reset: form.reset,\n    handleSubmit,\n  };\n}","\"use client\";\n\nimport { useEffect } from \"react\";\nimport { toast } from \"sonner\";\n\nexport function ToastRestorer() {\n  useEffect(() => {\n    // Only run on client side\n    if (typeof window === \"undefined\") return;\n    \n    const storageKey = \"sonner-toasts\";\n    \n    try {\n      const storedToasts = localStorage.getItem(storageKey);\n      \n      if (storedToasts) {\n        const persistentToasts = JSON.parse(storedToasts);\n        \n        if (Array.isArray(persistentToasts) && persistentToasts.length > 0) {\n          // Clear the storage immediately to prevent duplicate toasts\n          localStorage.removeItem(storageKey);\n          \n          // Filter out old toasts (older than 30 seconds)\n          const recentToasts = persistentToasts.filter(\n            (t: any) => Date.now() - (t.createdAt || 0) < 30000\n          );\n          \n          // Restore toasts with staggered animation like in the PR\n          recentToasts.forEach((persistedToast: any, index: number) => {\n            // Skip loading toasts as per the PR implementation\n            if (persistedToast.type === \"loading\") return;\n            \n            setTimeout(() => {\n              const toastFunction = toast[persistedToast.type as keyof typeof toast];\n              \n              if (typeof toastFunction === \"function\") {\n                // Check if current sonner supports persistent\n                if (toastFunction.length >= 2) {\n                  // Use persistent if available\n                  (toastFunction as any)(persistedToast.message, { \n                    persistent: true,\n                    id: persistedToast.id \n                  });\n                } else {\n                  // Fallback to normal toast\n                  toastFunction(persistedToast.message);\n                }\n              }\n            }, index * 150); // Staggered delay like in the PR\n          });\n        }\n      }\n    } catch (error) {\n      console.error(\"Failed to restore toasts:\", error);\n      // Clean up on error\n      localStorage.removeItem(storageKey);\n    }\n  }, []);\n  \n  return null;\n}"],"mappings":"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","names":["RedirectStatusCode","result","useTransition","useTransition","useTransition","useState","useRouter","toast","useEffect","toast"]}