UNPKG

next-safe-action-query

Version:

Type-safe server actions with built-in validation for Next.js

78 lines (77 loc) 2.17 kB
"use client"; import { useQuery } from "@tanstack/react-query"; class SafeActionError extends Error { constructor(message, type, details) { super(message); this.type = type; this.details = details; this.name = "SafeActionError"; } } function useSafeActionQuery(queryKey, action, options) { const { actionInput, onServerError, onValidationErrors, onNetworkError, ...queryOptions } = options; return useQuery({ queryKey, queryFn: async () => { try { const result = await action(actionInput); if (result?.serverError) { onServerError?.(result.serverError); throw new SafeActionError(result.serverError, "server"); } if (result?.validationErrors) { const errors = result.validationErrors._errors ?? []; onValidationErrors?.(errors); throw new SafeActionError( errors.join(", ") || "Validation failed", "validation", result.validationErrors ); } if (result?.data === void 0 || result?.data === null) { throw new SafeActionError("No data returned from action", "server"); } return result.data; } catch (error) { if (error instanceof SafeActionError) { throw error; } const networkError = error instanceof Error ? error : new Error("Unknown error occurred"); onNetworkError?.(networkError); throw new SafeActionError( `Network error: ${networkError.message}`, "network", networkError ); } }, retry: (failureCount, error) => { if (error instanceof SafeActionError && error.type === "validation") { return false; } if (error instanceof SafeActionError && error.type === "server") { return false; } return failureCount < 3; }, // Set reasonable defaults staleTime: 30 * 1e3, // 30 seconds default throwOnError: false, // Return errors as state by default ...queryOptions }); } export { SafeActionError, useSafeActionQuery }; //# sourceMappingURL=index.js.map