Events from Zod
document:docs/events/zodDefine an event once in TypeScript; the catalog, graph and service pages derive from it.
The recommended path for TypeScript teams. You define the schema once in code, and the plugin converts it to JSON Schema and generates the event folder.
pnpm add -D autocatalog-plugin-zodimport { defineEvent } from 'autocatalog-plugin-zod';import { z } from 'zod';
export default [ defineEvent( { domain: 'payments', team: 'Billing', producers: ['PaymentService'], consumers: ['LedgerService', 'NotificationService'], tags: ['pci', 'critical'], }, z.object({ id: z.string(), amount: z.number().positive(), currency: z.string(), completedAt: z.string().datetime(), }), ),];defineEvent returns the Zod schema unchanged and attaches the metadata to a
symbol. z.infer, .parse() and .safeParse() all keep working, so the same
object stays your runtime validator.
Metadata can also carry delivery, what consumers may rely on about arrival;
see Delivery.
Generate the event folder:
ac from-zod ./src/events/payment.ts --out ./eventsThat writes events/payments/PaymentCompleted/autocatalog.json with your
metadata, schema.json converted from Zod, examples, and a generated
index.mdx if you have not written narrative content yet.
Two export shapes
Section titled “Two export shapes”Compact shape, with identity encoded in the name:
export default [ { name: 'v1.payment.completed', description: 'Fires when a payment completes', schema: z.object({ id: z.string() }), example: { id: 'pay_1' }, },];v1.payment.completed splits into version: v1, id: payment.completed,
domain: payment.
Explicit shape — every field under your control:
export default [ { id: 'payment.completed', version: '1.0.0', name: 'Payment Completed', summary: 'Fires when a payment completes', domain: 'payments', producers: ['PaymentService'], schema: z.object({ id: z.string() }), examples: [{ name: 'success', data: { id: 'pay_1' } }], },];Both shapes work with defineEvent. Where both carry the same field, the
explicit one wins.
What survives the conversion
Section titled “What survives the conversion”The catalog’s interchange format is JSON Schema, not Zod. Constraints that JSON Schema can express — types, requiredness, enums, formats, numeric bounds — survive. Refinements and transforms that only exist at runtime do not, and are out of scope for the catalog on purpose: the catalog is a contract other languages read, not a second validator.
Running it in a scan
Section titled “Running it in a scan”ac scan can pick up Zod events as part of a whole-repository sweep, but
extracting them means evaluating repository code. That is opt-in:
ac scan . --out ./events --allow-code-executionResults merge by event id, and extracted Zod wins over inferred JSON Schema for the same id. See production operation for the isolation model that runtime plugins execute under.