safe-actions-state
Version:
A lightweight, type-safe utility for Next.js server & client actions with built-in authentication and RBAC(role based access control) checks, Zod validation, auto retries if server action fails, and real-time toast feedback out of the box. Just write your
69 lines (63 loc) • 2.17 kB
TypeScript
import { z } from 'zod';
import * as react from 'react';
type FieldErrors<T> = {
[K in keyof T]?: string[];
};
type ActionState<TInput, TOutput> = {
fieldErrors?: FieldErrors<TInput>;
error?: string;
data?: TOutput;
} | void;
type SessionObject = {
authenticated: boolean;
role?: string;
};
type PublicAction = {
isPrivate: false;
};
type PrivateAction = {
isPrivate: true;
};
type RoleBasedAction = {
isPrivate: true;
allowedRoles: string[];
};
type ActionType = PublicAction | PrivateAction | RoleBasedAction;
type ActionWithInputs<TInput, TOutput> = {
withInputs: true;
handler: (validatedData: TInput) => Promise<ActionState<TInput, TOutput>>;
schema: z.Schema<TInput>;
};
type ActionWithoutInputs<TOutput> = {
withInputs: false;
handler: () => Promise<ActionState<undefined, TOutput>>;
};
type Action<TInput, TOutput> = ActionWithInputs<TInput, TOutput> | ActionWithoutInputs<TOutput>;
type SafeActionProps<TInput, TOutput> = {
action: Action<TInput, TOutput>;
actionType: ActionType;
};
declare const createSafeAction: <TInput, TOutput>({ action, actionType, }: SafeActionProps<TInput, TOutput>) => (data: TInput) => Promise<ActionState<TInput, TOutput>>;
type SafeActionType<TInput, TOutput> = (data: TInput) => Promise<ActionState<TInput, TOutput>>;
type UseActionOptions<TOutput> = {
retries?: number;
onStart?: () => void;
onSuccess?: (data?: TOutput) => void;
onError?: (error: string) => void;
onComplete?: () => void;
toastMessages?: {
loading: string;
success: string;
};
};
declare const useSafeAction: <TInput, TOutput>(serverAction: SafeActionType<TInput, TOutput>, options?: UseActionOptions<TOutput>) => {
clientAction: (input: TInput) => Promise<void>;
abortAction: () => void | undefined;
error: string | undefined;
data: TOutput | undefined;
isPending: boolean;
fieldErrors: FieldErrors<TInput> | undefined;
setFieldErrors: react.Dispatch<react.SetStateAction<FieldErrors<TInput> | undefined>>;
};
export { createSafeAction, useSafeAction };
export type { SafeActionType, SessionObject, UseActionOptions };