AgentSkillsCN

zodipus-setup

安装并配置 Zodipus Prisma 生成器。在安装 zodipus、设置生成器选项、配置输出路径、选择日期格式,或与 Next.js/Express/Fastify/tRPC 等框架集成时,均可使用此工具。

SKILL.md
--- frontmatter
name: zodipus-setup
description: Install and configure Zodipus Prisma generator. Use when installing zodipus, setting up generator options, configuring output paths, choosing date formats, or integrating with Next.js/Express/Fastify/tRPC.
license: MIT
metadata:
  author: zodipus
  version: "1.0.0"

Zodipus Setup

Complete guide for installing and configuring Zodipus.

When to Apply

  • User is installing zodipus for the first time
  • User asks about generator configuration options
  • User needs framework-specific setup (Next.js, Express, tRPC)
  • User wants to understand dateFormat, relationDepth, or other options
  • User is setting up a new Prisma project with Zod validation

Installation

bash
# npm
npm install zodipus zod

# pnpm
pnpm add zodipus zod

# yarn
yarn add zodipus zod

Requirements:

  • Node.js 18+
  • Prisma 6.0+
  • Zod 3.25.0+

Basic Configuration

Add to your schema.prisma:

prisma
generator client {
  provider = "prisma-client-js"
}

generator zodipus {
  provider = "zodipus"
  output   = "./generated"
}

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String?
  role      Role     @default(USER)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  posts     Post[]
}

model Post {
  id        String   @id @default(cuid())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  String
}

enum Role {
  USER
  ADMIN
}

Generate Schemas

bash
npx prisma generate

This creates:

code
generated/
├── enums.ts              # RoleSchema
├── models.ts             # UserSchema, PostSchema
├── custom-schemas.ts     # Placeholder for @zodSchema
├── generated-relations.ts
└── generated-index.ts

Configuration Options

OptionTypeDefaultDescription
providerstringRequiredMust be "zodipus"
outputstringRequiredOutput directory for generated files
relationDepthstring"5"Maximum depth for nested relation extraction
dateFormatstring"coerce"DateTime handling: "coerce" or "string"
passthroughEnabledstring"false"Allow unknown keys in objects
debugstring"false"Enable verbose debug logging
zodImportstring"zod"Custom Zod import path

Date Format Options

dateFormat = "coerce" (Default)

Accepts multiple input types, converts to Date:

typescript
// All valid inputs:
UserSchema.parse({ createdAt: new Date() });           // Date object
UserSchema.parse({ createdAt: '2024-01-15T10:30:00Z' }); // ISO string
UserSchema.parse({ createdAt: 1705315800000 });        // Timestamp

Use when: Receiving data from various sources (APIs, databases, user input).

dateFormat = "string"

Requires strict ISO 8601 format:

typescript
// Only ISO strings accepted:
UserSchema.parse({ createdAt: '2024-01-15T10:30:00.000Z' }); // OK
UserSchema.parse({ createdAt: new Date() }); // Error!

Use when: Building strict APIs, need consistent date format.

Passthrough Mode

passthroughEnabled = "false" (Default)

Unknown keys are stripped:

typescript
const data = { id: '1', email: 'a@b.com', unknownField: 'ignored' };
const user = UserSchema.parse(data);
// user = { id: '1', email: 'a@b.com' } - unknownField removed

Use when: Sanitizing input, preventing data leakage.

passthroughEnabled = "true"

Unknown keys are preserved:

typescript
const data = { id: '1', email: 'a@b.com', extra: 'kept' };
const user = UserSchema.parse(data);
// user = { id: '1', email: 'a@b.com', extra: 'kept' }

Use when: Transforming data, need to preserve extra fields.

Relation Depth

Controls how deeply nested relations are extracted for the Query Engine:

prisma
generator zodipus {
  relationDepth = "10"  # Allow queries 10 levels deep
}

Default: 5 - Sufficient for most apps. Increase if you have deeply nested queries.

Common Configurations

Strict API Server

Best for REST/GraphQL APIs with strict validation:

prisma
generator zodipus {
  provider           = "zodipus"
  output             = "./src/generated/zodipus"
  passthroughEnabled = "false"
  dateFormat         = "string"
  relationDepth      = "5"
}

Flexible Data Pipeline

Best for ETL, migrations, or internal tools:

prisma
generator zodipus {
  provider           = "zodipus"
  output             = "./generated"
  passthroughEnabled = "true"
  dateFormat         = "coerce"
  relationDepth      = "8"
}

Minimal Setup

Quick start with sensible defaults:

prisma
generator zodipus {
  provider = "zodipus"
  output   = "./generated"
}

Framework Integration

Next.js App Router

typescript
// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { UserSchema } from '@/generated';
import { prisma } from '@/lib/prisma';

export async function POST(request: NextRequest) {
  const body = await request.json();

  const result = UserSchema.omit({ id: true, createdAt: true, updatedAt: true })
    .safeParse(body);

  if (!result.success) {
    return NextResponse.json({ errors: result.error.flatten() }, { status: 400 });
  }

  const user = await prisma.user.create({ data: result.data });
  return NextResponse.json(UserSchema.parse(user));
}

Express.js

typescript
// routes/users.ts
import { Router } from 'express';
import { UserSchema } from '../generated';
import { prisma } from '../lib/prisma';

const router = Router();

router.post('/', async (req, res) => {
  const CreateUserSchema = UserSchema.omit({ id: true, createdAt: true, updatedAt: true });
  const result = CreateUserSchema.safeParse(req.body);

  if (!result.success) {
    return res.status(400).json({ errors: result.error.flatten() });
  }

  const user = await prisma.user.create({ data: result.data });
  res.json(UserSchema.parse(user));
});

export default router;

tRPC

typescript
// server/routers/user.ts
import { router, publicProcedure } from '../trpc';
import { UserSchema } from '../../generated';
import { prisma } from '../../lib/prisma';

export const userRouter = router({
  create: publicProcedure
    .input(UserSchema.omit({ id: true, createdAt: true, updatedAt: true }))
    .mutation(async ({ input }) => {
      const user = await prisma.user.create({ data: input });
      return UserSchema.parse(user);
    }),

  getById: publicProcedure
    .input(z.object({ id: z.string() }))
    .query(async ({ input }) => {
      const user = await prisma.user.findUnique({ where: { id: input.id } });
      return user ? UserSchema.parse(user) : null;
    }),
});

Verification

After setup, verify everything works:

typescript
// test-setup.ts
import { UserSchema, RoleSchema } from './generated';
import { createRegistry } from 'zodipus/queryEngine';
import { models, modelRelations } from './generated/generated-index';

// Test schema parsing
const user = UserSchema.parse({
  id: 'test-id',
  email: 'test@example.com',
  name: null,
  role: 'USER',
  createdAt: new Date(),
  updatedAt: new Date(),
});
console.log('Schema validation:', user);

// Test Query Engine
const registry = createRegistry({ models, relations: modelRelations });
const userQuery = registry.createQuery('user');
console.log('Query Engine:', userQuery({ select: { id: true } }).query);

Troubleshooting Setup

"Cannot find module './generated'"

Run npx prisma generate after adding the generator.

TypeScript errors after generation

Ensure your tsconfig includes the output directory:

json
{
  "include": ["src/**/*", "generated/**/*"]
}

ESM/CJS conflicts

Zodipus outputs CommonJS. If using ESM, ensure your bundler handles the conversion.

For detailed options, see references/GENERATOR-OPTIONS.md.