Files
myeasycms-v2/.claude/skills/server-action-builder/reference.md
Giancarlo Buomprisco 7ebff31475 Next.js Supabase V3 (#463)
Version 3 of the kit:
- Radix UI replaced with Base UI (using the Shadcn UI patterns)
- next-intl replaces react-i18next
- enhanceAction deprecated; usage moved to next-safe-action
- main layout now wrapped with [locale] path segment
- Teams only mode
- Layout updates
- Zod v4
- Next.js 16.2
- Typescript 6
- All other dependencies updated
- Removed deprecated Edge CSRF
- Dynamic Github Action runner
2026-03-24 13:40:38 +08:00

180 lines
4.1 KiB
Markdown

# Server Action Reference
## enhanceAction API
```typescript
import { enhanceAction } from '@kit/next/actions';
export const myAction = enhanceAction(
async function (data, user) {
// data: validated input (typed from schema)
// user: authenticated user object (if auth: true)
return { success: true, data: result };
},
{
auth: true, // Require authentication (default: false)
schema: ZodSchema, // Zod schema for validation (optional)
},
);
```
### Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `auth` | `boolean` | `false` | Require authenticated user |
| `schema` | `ZodSchema` | - | Zod schema for input validation |
### Handler Parameters
| Parameter | Type | Description |
|-----------|--------------------|------------------------------------|
| `data` | `z.output<Schema>` | Validated input data |
| `user` | `User` | Authenticated user (if auth: true) |
## enhanceRouteHandler API
```typescript
import { enhanceRouteHandler } from '@kit/next/routes';
import { NextResponse } from 'next/server';
export const POST = enhanceRouteHandler(
async function ({ body, user, request }) {
// body: validated request body
// user: authenticated user (if auth: true)
// request: original NextRequest
return NextResponse.json({ success: true });
},
{
auth: true,
schema: ZodSchema,
},
);
export const GET = enhanceRouteHandler(
async function ({ user, request }) {
const url = new URL(request.url);
const param = url.searchParams.get('param');
return NextResponse.json({ data: result });
},
{
auth: true,
},
);
```
## Common Zod Patterns
```typescript
import * as z from 'zod';
// Basic schema
export const CreateItemSchema = z.object({
name: z.string().min(1, 'Name is required'),
description: z.string().optional(),
accountId: z.string().uuid('Invalid account ID'),
});
// With transforms
export const SearchSchema = z.object({
query: z.string().trim().min(1),
page: z.coerce.number().int().positive().default(1),
limit: z.coerce.number().int().min(1).max(100).default(10),
});
// With refinements
export const DateRangeSchema = z.object({
startDate: z.coerce.date(),
endDate: z.coerce.date(),
}).refine(
(data) => data.endDate > data.startDate,
{ message: 'End date must be after start date' }
);
// Enum values
export const StatusSchema = z.object({
status: z.enum(['active', 'inactive', 'pending']),
});
```
## Revalidation
```typescript
import { revalidatePath } from 'next/cache';
import { revalidateTag } from 'next/cache';
// Revalidate specific path
revalidatePath('/home/[account]/items');
// Revalidate with dynamic segment
revalidatePath(`/home/${accountSlug}/items`);
// Revalidate by tag
revalidateTag('items');
```
## Redirect
```typescript
import { redirect } from 'next/navigation';
// Redirect after action
redirect('/success');
// Redirect with dynamic path
redirect(`/home/${accountSlug}/items/${itemId}`);
```
## Logging
```typescript
import { getLogger } from '@kit/shared/logger';
const logger = await getLogger();
// Context object for all logs
const ctx = {
name: 'action-name',
userId: user.id,
accountId: data.accountId,
};
// Log levels
logger.info(ctx, 'Starting operation');
logger.warn({ ...ctx, warning: 'details' }, 'Warning message');
logger.error({ ...ctx, error }, 'Operation failed');
```
## Supabase Clients
```typescript
// Standard client (RLS enforced)
import { getSupabaseServerClient } from '@kit/supabase/server-client';
const client = getSupabaseServerClient();
// Admin client (bypasses RLS - use sparingly)
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
const adminClient = getSupabaseServerAdminClient();
```
## Error Handling
```typescript
import { isRedirectError } from 'next/dist/client/components/redirect-error';
try {
await operation();
redirect('/success');
} catch (error) {
if (!isRedirectError(error)) {
// Handle actual error
logger.error({ error }, 'Operation failed');
throw error;
}
throw error; // Re-throw redirect
}
```