Actions serveur type-safe avec authentification, autorisation d'organisation et gestion d'erreurs
Le module safe-actions.ts fournit des actions serveur type-safe avec authentification, autorisation et gestion d'erreurs via next-safe-action.
action - Actions publiquesClient de base pour les actions publiques qui ne requierent pas d'authentification.
import { action } from "@/lib/actions/safe-actions";
export const subscribeNewsletter = action
.inputSchema(
z.object({
email: z.string().email(),
name: z.string().optional(),
}),
)
.action(async ({ parsedInput: { email, name } }) => {
await addToNewsletter(email, name);
return { subscribed: true };
});
authAction - Actions authentifieesRequiert une session utilisateur valide. Fournit ctx.user dans le handler.
import { authAction } from "@/lib/actions/safe-actions";
export const updateProfile = authAction
.inputSchema(
z.object({
name: z.string().min(1),
bio: z.string().optional(),
}),
)
.action(async ({ parsedInput: { name, bio }, ctx: { user } }) => {
orgAction - Actions d'organisationRequiert l'appartenance a une organisation avec des verifications de roles/permissions optionnelles. Fournit ctx.org dans le handler.
import { orgAction } from "@/lib/actions/safe-actions";
// Avec permissions
export const inviteUser = orgAction
.metadata({ permissions: { users: ["create", "invite"] } })
.inputSchema(
z.object({
email: z.string().email(),
role: z.enum(["member", "admin"]),
}),
)
.action(async ({ parsedInput: {
adminAction - Actions reservees aux adminsRequiert que l'utilisateur ait le role admin. Fournit ctx.user dans le handler.
import { adminAction } from "@/lib/actions/safe-actions";
export const updateSubscriptionPlan = adminAction
.inputSchema(
z.object({
organizationId: z.string(),
planName: z.string(),
}),
)
.action(
async ({ parsedInput: { organizationId, planName }, ctx: { user } }) => {
await updateOrgPlan(organizationId, planName);
Tous les clients utilisent un handler d'erreurs partage qui :
ApplicationError au clientUtilisez resolveActionResult pour integrer aux formulaires :
import { resolveActionResult } from "@/lib/actions/actions-utils";
import { updateProfile } from "./profile.action";
const form = useForm({
schema: ProfileSchema,
defaultValues: { name: "", bio: "" },
onSubmit: async (values) => {
const result = await resolveActionResult(updateProfile(values));
// result est type, leve une erreur en cas d'echec
},
});
Les fichiers d'actions serveur doivent se terminer par .action.ts :
user.action.tsdashboard.action.tsorganization.action.ts