JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 143
  • Score
    100M100P100Q98017F
  • License MIT

Auto-generate type-safe tRPC routers from ZenStack V3 schemas

Package Exports

  • zenstack-trpc

Readme

zenstack-trpc

Auto-generate fully type-safe tRPC routers from ZenStack V3 schemas.

Features

  • Zero codegen - Router generated at runtime from schema metadata
  • Full type inference - Input AND output types from your ZenStack schema
  • Dynamic result typing - include/select options reflected in return types
  • Zod validation - Runtime input validation built-in
  • All CRUD operations - findMany, findUnique, create, update, delete, and more
  • Standard tRPC - Works with all tRPC adapters (HTTP, WebSocket, Next.js, etc.)

Installation

npm install zenstack-trpc @trpc/server @zenstackhq/orm zod
# or
pnpm add zenstack-trpc @trpc/server @zenstackhq/orm zod
# or
yarn add zenstack-trpc @trpc/server @zenstackhq/orm zod

Quick Start

1. Define your ZenStack schema

// schema.zmodel
model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String?
  posts     Post[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

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

2. Generate ZenStack artifacts

npx zenstack generate

3. Create the tRPC router

import { ZenStackClient } from "@zenstackhq/orm";
import { schema, SchemaType } from "./zenstack/schema.js";
import {
  createTRPC,
  createZenStackRouter,
  type Context,
  type TypedRouterCaller,
} from "zenstack-trpc";

// Create your database client
const db = new ZenStackClient(schema, {
  dialect: yourDialect, // Kysely dialect (SQLite, PostgreSQL, MySQL, etc.)
});

// Create tRPC instance
const t = createTRPC<Context>();

// Generate the router from your schema
const appRouter = createZenStackRouter(schema, t);

// Export for client usage
export type AppRouter = typeof appRouter;

4. Use the router

// Create a typed caller
const caller = appRouter.createCaller({ db }) as TypedRouterCaller<SchemaType>;

// All operations are fully typed!
const users = await caller.user.findMany();
//    ^? { id: string, email: string, name: string | null, ... }[]

// Include relations - return type automatically includes them
const usersWithPosts = await caller.user.findMany({
  include: { posts: true }
});
//    ^? { id: string, ..., posts: Post[] }[]

// Select specific fields
const emails = await caller.user.findMany({
  select: { id: true, email: true }
});
//    ^? { id: string, email: string }[]

// Create with full validation
const user = await caller.user.create({
  data: {
    email: "alice@example.com",
    name: "Alice",
  },
});

// Update with type-safe where clause
await caller.user.update({
  where: { id: user.id },
  data: { name: "Alice Smith" },
});

API Reference

createTRPC<Context>()

Creates a tRPC instance with the given context type.

import { createTRPC, type Context } from "zenstack-trpc";

const t = createTRPC<Context>();

createZenStackRouter(schema, t)

Generates a tRPC router from a ZenStack schema.

import { createZenStackRouter } from "zenstack-trpc";

const appRouter = createZenStackRouter(schema, t);

TypedRouterCaller<SchemaType>

Type helper for fully typed caller with dynamic input/output inference.

import type { TypedRouterCaller } from "zenstack-trpc";
import type { SchemaType } from "./zenstack/schema.js";

const caller = appRouter.createCaller({ db }) as TypedRouterCaller<SchemaType>;

TypedModelProcedures<Schema, Model>

Type helper for a single model's procedures.

import type { TypedModelProcedures } from "zenstack-trpc";

type UserProcedures = TypedModelProcedures<SchemaType, "User">;

Generated Router Structure

For each model in your schema, the following procedures are generated:

router
├── user
│   ├── findMany    (query)
│   ├── findUnique  (query)
│   ├── findFirst   (query)
│   ├── create      (mutation)
│   ├── createMany  (mutation)
│   ├── update      (mutation)
│   ├── updateMany  (mutation)
│   ├── upsert      (mutation)
│   ├── delete      (mutation)
│   ├── deleteMany  (mutation)
│   ├── count       (query)
│   ├── aggregate   (query)
│   └── groupBy     (query)
├── post
│   └── ... (same operations)

Using with tRPC Adapters

Standalone HTTP Server

import { createHTTPServer } from "@trpc/server/adapters/standalone";

const server = createHTTPServer({
  router: appRouter,
  createContext: () => ({ db }),
});

server.listen(3000);

Next.js App Router

// app/api/trpc/[trpc]/route.ts
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";

const handler = (req: Request) =>
  fetchRequestHandler({
    endpoint: "/api/trpc",
    req,
    router: appRouter,
    createContext: () => ({ db }),
  });

export { handler as GET, handler as POST };

Express

import express from "express";
import { createExpressMiddleware } from "@trpc/server/adapters/express";

const app = express();

app.use(
  "/trpc",
  createExpressMiddleware({
    router: appRouter,
    createContext: () => ({ db }),
  })
);

Advanced Usage

Custom Context

Extend the context with authentication or other data:

interface MyContext extends Context {
  db: any;
  userId?: string;
}

const t = createTRPC<MyContext>();
const appRouter = createZenStackRouter(schema, t);

// In your adapter
createContext: (opts) => ({
  db: getEnhancedDb(opts.req), // ZenStack enhanced client with access control
  userId: getUserFromRequest(opts.req),
});

Zod Schema Access

Access the generated Zod schemas for custom validation:

import {
  createModelSchemas,
  createWhereSchema,
  createCreateDataSchema,
} from "zenstack-trpc";

const userSchemas = createModelSchemas(schema, "User");
const whereSchema = createWhereSchema(schema, "User");

Requirements

  • Node.js >= 18
  • TypeScript >= 5.0
  • ZenStack V3 (@zenstackhq/orm >= 3.0.0)
  • tRPC >= 11.0.0
  • Zod >= 3.0.0

License

MIT