New server action factory is out!
Type-safe factories for Next.js
Fast, flexible, framework validation agnostic factories for creating server actions, route handlers, page and layout Server Components.
'use server'import { object, string, datelike } from 'decoders'import { createSafeServerAction } from '@sugardarius/anzen'import { auth } from '~/lib/auth'import { db } from '~/lib/db'export const createThread = createSafeServerAction( { id: 'create-thread-action', input: object({ spaceId: string, createdAt: datelike, comment: object({ createdAt: datelike, content: string, }), }), authorize: async ({ input }) => { const session = await auth() if (!session.user) { throw new Error('user is not authenticated') } if (!session.access.includes(input.spaceId)) { throw new Error('user has not access') } return { user: session.user } }, }, async ({ auth, input, id }) => { const inserted = await db.createThread({ thread: { ...input, authorId: auth.user.id }, }) return { inserted, actionId: id } })import { object, string, number } from 'decoders'import { createSafeRouteHandler } from '@sugardarius/anzen'import { auth } from '~/lib/auth'export const POST = createSafeRouteHandler( { authorize: async ({ req }) => { const session = await auth.getSession(req) if (!session) { return new Response(null, { status: 401 }) } return { user: session.user } }, }, async ({ auth, body }, req): Promise<Response> => { return Response.json({ user: auth.user, body }, { status: 200 }) })import { unauthorized } from 'next/navigation'import { string } from 'decoders'import { createSafePageServerComponent } from '@sugardarius/anzen/server-components'import { auth } from '~/lib/auth'import { getAccount } from '~/lib/db'import { AccountSummary } from '~/components/account-summary'export default createSafePageServerComponent( { authorize: async ({ segments }) => { const session = await auth.getSession() if (!session) { unauthorized() } return { user: session.user } }, segments: { accountId: string, }, }, async ({ auth, segments }) => { const account = await getAccount({ id: segments.accountId }) return <AccountSummary user={auth.user} account={account} /> })import { unauthorized } from 'next/navigation'import { string } from 'decoders'import { createSafeLayoutServerComponent } from '@sugardarius/anzen/server-components'import { auth } from '~/lib/auth'import { getAccount } from '~/lib/db'import { AccountHeader } from '~/components/account-header'export default createSafeLayoutServerComponent( { authorize: async ({ segments }) => { const session = await auth.getSession() if (!session) { unauthorized() } return { user: session.user } }, segments: { accountId: string, }, }, async ({ auth, segments, children }) => { const account = await getAccount({ id: segments.accountId }) return ( <div> <AccountHeader user={auth.user} accountId={segments.accountId} /> {children} </div> ) })Why Anzen?
Anzen means "safe" in Japanese. Build secure, type-safe Next.js APIs with confidence.
🔧
Framework validation agnostic
Use a validation library supporting Standard Schema.
🧠
Focused functionalities
Use only the features you need.
🧹
Clean and flexible API
Make it your own.
🔒
Type-safe
Full TypeScript inference.
🌱
Dependency free
Only Next.js is required as a peer dependency.
🪶
Lightweight
Your bundle is safe.
Framework validation agnostic
Use any validation library that implements the Standard Schema interface. Mix and match as needed.