zodipus 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,424 @@
1
+ # Zodipus
2
+
3
+ > **Zodipus: solves your schema tragedies.**
4
+
5
+ A powerful Prisma generator that automatically creates:
6
+ 1. **Clean Zod model schemas** (without relations) from your Prisma schema
7
+ 2. **Enum schemas** with TypeScript types
8
+ 3. **Relation metadata** for query engines and GraphQL resolvers
9
+ 4. **Custom schema support** for complex JSON fields
10
+ 5. **Query Engine** for composable, runtime-validated Prisma queries
11
+
12
+ ## The Problem: Prisma Types vs. Zod Types
13
+
14
+ Prisma and Zod generate **incompatible types**, especially for JSON fields and enums:
15
+
16
+ ```typescript
17
+ import { z } from 'zod';
18
+
19
+ const user = await prisma.user.findFirst();
20
+ // Prisma type: { settings: JsonValue, role: $Enums.UserRole, ... }
21
+
22
+ function processUser(data: z.infer<typeof UserSchema>) {
23
+ // Zod type: { settings: { theme: 'light' | 'dark', ... }, role: 'USER' | 'ADMIN', ... }
24
+ }
25
+
26
+ // āŒ TypeScript ERROR:
27
+ // Type 'JsonValue' is not assignable to type '{ theme?: "light" | "dark" | ... }'
28
+ // Type '$Enums.UserRole' is not assignable to type '"USER" | "ADMIN" | "MODERATOR"'
29
+ processUser(user);
30
+ ```
31
+
32
+ **Why types are incompatible:**
33
+ - **JSON fields**: Prisma uses generic `JsonValue`, but Zod schemas (via `@zodSchema`) define specific structures
34
+ - **Enums**: Prisma generates `$Enums.UserRole`, while Zod uses literal unions `"USER" | "ADMIN"`
35
+ - **Runtime validation**: Even if types matched, Prisma data is not validated — malformed JSON or invalid values can slip through
36
+
37
+ ## The Solution: Query Engine
38
+
39
+ Zodipus's **Query Engine** creates composable Prisma queries that automatically validate results:
40
+
41
+ ```typescript
42
+ import { createRegistry } from 'zodipus/queryEngine';
43
+ import { models, modelRelations } from './generated/generated-index';
44
+
45
+ const registry = createRegistry({ models, relations: modelRelations });
46
+ const userQuery = registry.createQuery('user');
47
+
48
+ // Build a type-safe query with relations
49
+ const query = userQuery({
50
+ select: { id: true, email: true, name: true },
51
+ posts: { select: { title: true, published: true } },
52
+ });
53
+
54
+ // Execute with Prisma
55
+ const users = await prisma.user.findMany(query.query);
56
+
57
+ // āœ… Validate and get properly typed results
58
+ const validatedUsers = query.array().parse(users);
59
+ // Type: { id: string, email: string, name: string | null, posts: { title: string, published: boolean }[] }[]
60
+
61
+ // Now safely pass to functions expecting validated data
62
+ processUsers(validatedUsers); // āœ… Guaranteed valid!
63
+ ```
64
+
65
+
66
+
67
+ ## Installation
68
+
69
+ ```bash
70
+ # Using npm
71
+ npm install -D zodipus
72
+
73
+ # Using yarn
74
+ yarn add -D zodipus
75
+
76
+ # Using pnpm
77
+ pnpm add -D zodipus
78
+ ```
79
+
80
+ ## Quick Start
81
+
82
+ ### 1. Add generator to your Prisma schema
83
+
84
+ ```prisma
85
+ generator zodipus {
86
+ provider = "zodipus"
87
+ output = "./generated"
88
+ relationDepth = "5"
89
+ }
90
+
91
+ model User {
92
+ id String @id @default(uuid())
93
+ email String @unique
94
+ name String?
95
+ role Role
96
+ posts Post[]
97
+ createdAt DateTime @default(now())
98
+ updatedAt DateTime @updatedAt
99
+ }
100
+
101
+ enum Role {
102
+ USER
103
+ ADMIN
104
+ }
105
+
106
+ model Post {
107
+ id String @id @default(uuid())
108
+ title String
109
+ content String?
110
+ published Boolean @default(false)
111
+ author User @relation(fields: [authorId], references: [id])
112
+ authorId String
113
+
114
+ /// @zodSchema PostMetadataSchema
115
+ metadata Json?
116
+
117
+ createdAt DateTime @default(now())
118
+ updatedAt DateTime @updatedAt
119
+ }
120
+ ```
121
+
122
+ ### 2. Run Prisma generate
123
+
124
+ ```bash
125
+ pnpm prisma generate
126
+ ```
127
+
128
+ ### 3. Use generated schemas
129
+
130
+ ```typescript
131
+ import { UserSchema, RoleSchema, PostSchema } from './generated';
132
+
133
+ // Parse and validate data
134
+ const user = UserSchema.parse({
135
+ id: '123',
136
+ email: 'user@example.com',
137
+ role: 'ADMIN',
138
+ createdAt: new Date(),
139
+ updatedAt: new Date()
140
+ });
141
+
142
+ // Use enums
143
+ const role = RoleSchema.parse('ADMIN');
144
+ ```
145
+
146
+ ## Features
147
+
148
+ ### Clean Zod Schemas
149
+
150
+ Generate schemas containing only scalar fields - no relation clutter:
151
+
152
+ ```typescript
153
+ export const UserSchema = z.object({
154
+ id: z.string(),
155
+ email: z.string(),
156
+ name: z.string().optional().nullable(),
157
+ role: RoleSchema,
158
+ createdAt: z.coerce.date(),
159
+ updatedAt: z.coerce.date()
160
+ });
161
+ ```
162
+
163
+ ### Custom JSON Field Schemas
164
+
165
+ Add type-safe validation for JSON fields using `@zodSchema` annotations:
166
+
167
+ ```prisma
168
+ model Post {
169
+ /// @zodSchema PostMetadataSchema
170
+ metadata Json?
171
+ }
172
+ ```
173
+
174
+ Then define in `generated/custom-schemas.ts`:
175
+
176
+ ```typescript
177
+ export const PostMetadataSchema = z.object({
178
+ tags: z.array(z.string()),
179
+ views: z.number(),
180
+ featured: z.boolean().optional(),
181
+ });
182
+ ```
183
+
184
+ ### Relation Metadata
185
+
186
+ Extracted automatically for building query engines:
187
+
188
+ ```typescript
189
+ const relations = {
190
+ user: {
191
+ posts: {
192
+ type: "post" as const,
193
+ isArray: true,
194
+ relations: { /* nested */ }
195
+ }
196
+ }
197
+ } as const;
198
+ ```
199
+
200
+ ## Query Engine Integration
201
+
202
+ Zodipus includes a powerful Query Engine that works seamlessly with your generated schemas:
203
+
204
+ ```typescript
205
+ import { createRegistry } from 'zodipus/queryEngine';
206
+ import { models, modelRelations } from './generated/generated-index';
207
+
208
+ // Create registry
209
+ const registry = createRegistry({
210
+ models,
211
+ relations: modelRelations,
212
+ });
213
+
214
+ // Create query builders
215
+ export const userQuery = registry.createQuery('user');
216
+ export const postQuery = registry.createQuery('post');
217
+
218
+ // Use with Prisma
219
+ const query = userQuery({
220
+ select: { id: true, email: true, name: true },
221
+ posts: {
222
+ select: { title: true, published: true },
223
+ },
224
+ });
225
+
226
+ // Execute and validate
227
+ const users = await prisma.user.findMany(query.query);
228
+ const validated = query.array().parse(users);
229
+ ```
230
+
231
+ **Features:**
232
+ - āœ… Complete compile-time type safety
233
+ - āœ… Runtime validation with Zod
234
+ - āœ… Automatic relation handling
235
+ - āœ… Nested query support
236
+ - āœ… Selective validation for performance
237
+
238
+ See [Query Engine Documentation](./queryEngine.md) for complete API reference and examples.
239
+
240
+ ## Configuration
241
+
242
+ Add options to your Prisma generator configuration:
243
+
244
+ ```prisma
245
+ generator zodipus {
246
+ provider = "zodipus"
247
+ output = "./generated"
248
+ relationDepth = "5"
249
+ dateFormat = "coerce" // or "string"
250
+ passthroughEnabled = "false" // or "true"
251
+ debug = "false" // or "true"
252
+ }
253
+ ```
254
+
255
+ ### Options
256
+
257
+ | Option | Type | Default | Description |
258
+ |--------|------|---------|-------------|
259
+ | `provider` | string | Required | Set to `"zodipus"` |
260
+ | `output` | string | Required | Output directory for generated files |
261
+ | `relationDepth` | string | `"5"` | Maximum depth for nested relations |
262
+ | `dateFormat` | string | `"coerce"` | DateTime handling: `"coerce"` uses `z.coerce.date()`, `"string"` uses `z.string().datetime()` |
263
+ | `passthroughEnabled` | string | `"false"` | When `"true"`, objects allow extra keys (passthrough mode). When `"false"` (default), unknown keys are stripped. |
264
+ | `debug` | string | `"false"` | Enable debug logging during generation |
265
+
266
+ ### DateTime Format
267
+
268
+ Choose how DateTime fields are validated:
269
+
270
+ - **`coerce` (default)**: Uses `z.coerce.date()` - accepts Date objects, ISO strings, and timestamps
271
+ - **`string`**: Uses `z.string().datetime()` - only accepts ISO 8601 datetime strings
272
+
273
+ ```prisma
274
+ // dateFormat = "coerce" (default)
275
+ generator zodipus {
276
+ dateFormat = "coerce"
277
+ }
278
+ // Generates: createdAt: z.coerce.date()
279
+
280
+ // dateFormat = "string"
281
+ generator zodipus {
282
+ dateFormat = "string"
283
+ }
284
+ // Generates: createdAt: z.string().datetime()
285
+ ```
286
+
287
+ ### Passthrough Mode
288
+
289
+ Control how objects handle extra properties:
290
+
291
+ - **`false` (default)**: Strict mode - unknown keys are stripped during parsing
292
+ - **`true`**: Passthrough mode - unknown keys are preserved
293
+
294
+ ```prisma
295
+ // passthroughEnabled = "false" (default)
296
+ generator zodipus {
297
+ passthroughEnabled = "false"
298
+ }
299
+ // Generates: z.object({ ... })
300
+
301
+ // passthroughEnabled = "true"
302
+ generator zodipus {
303
+ passthroughEnabled = "true"
304
+ }
305
+ // Generates: z.object({ ... }).passthrough()
306
+ ```
307
+
308
+ ## Generated Files
309
+
310
+ ```
311
+ generated/
312
+ ā”œā”€ā”€ enums.ts # Prisma enums as Zod schemas
313
+ ā”œā”€ā”€ models.ts # Clean model schemas
314
+ ā”œā”€ā”€ custom-schemas.ts # Custom JSON field schemas
315
+ ā”œā”€ā”€ generated-relations.ts # Relation metadata
316
+ └── generated-index.ts # Exports
317
+ ```
318
+
319
+ ## Examples
320
+
321
+ ### API Validation
322
+
323
+ ```typescript
324
+ import { UserSchema } from './generated';
325
+
326
+ app.post('/users', (req, res) => {
327
+ const user = UserSchema.parse(req.body);
328
+ await db.user.create({ data: user });
329
+ });
330
+ ```
331
+
332
+ ### Partial Updates
333
+
334
+ ```typescript
335
+ const UpdateUserSchema = UserSchema.partial();
336
+ const updates = UpdateUserSchema.parse(req.body);
337
+ ```
338
+
339
+ ## API Reference
340
+
341
+ ### Main Exports (`zodipus`)
342
+
343
+ | Export | Type | Description |
344
+ |--------|------|-------------|
345
+ | `createRegistry` | Function | Creates a query registry for type-safe Prisma queries |
346
+
347
+ ### Query Engine (`zodipus/queryEngine`)
348
+
349
+ | Export | Type | Description |
350
+ |--------|------|-------------|
351
+ | `createRegistry(config)` | Function | Creates query registry with models and relations |
352
+ | `ModelRegistry` | Type | Generic type for model schema map |
353
+ | `ModelRelations` | Type | Generic type for relation metadata |
354
+ | `RelationConfig` | Type | Configuration for a single relation |
355
+ | `QueryExecutor` | Type | Return type of query builders |
356
+ | `SafeParseResult<T>` | Type | Result of `.safeParse()` operations |
357
+
358
+ #### `createRegistry(config)`
359
+
360
+ ```typescript
361
+ function createRegistry<TModels, TRelations>(config: {
362
+ models: TModels;
363
+ relations: TRelations;
364
+ }): {
365
+ createQuery: (model: keyof TModels) => QueryBuilder;
366
+ };
367
+ ```
368
+
369
+ #### `QueryExecutor`
370
+
371
+ ```typescript
372
+ interface QueryExecutor<T> {
373
+ query: { select: ... } | { include: ... }; // Pass to Prisma
374
+ parse(data: unknown): T; // Throws on invalid
375
+ safeParse(data: unknown): SafeParseResult<T>; // Returns {success, data/error}
376
+ array(): {
377
+ parse(data: unknown[]): T[];
378
+ safeParse(data: unknown[]): SafeParseResult<T[]>;
379
+ };
380
+ }
381
+ ```
382
+
383
+ ### Errors (`zodipus/errors`)
384
+
385
+ | Export | Type | Description |
386
+ |--------|------|-------------|
387
+ | `ZodipusError` | Class | Base error class |
388
+ | `ZodipusValidationError` | Class | Thrown when validation fails |
389
+ | `ZodipusGeneratorError` | Class | Thrown during schema generation |
390
+ | `ValidationErrorContext` | Type | Context included in validation errors |
391
+
392
+ #### `ZodipusValidationError`
393
+
394
+ ```typescript
395
+ class ZodipusValidationError extends ZodipusError {
396
+ context: {
397
+ model: string; // Model being validated
398
+ field?: string; // Field that failed
399
+ expected?: string; // Expected type/value
400
+ received?: string; // Received type/value
401
+ path?: (string | number)[]; // Path to field
402
+ };
403
+ }
404
+ ```
405
+
406
+ ### Generated Files
407
+
408
+ | File | Exports |
409
+ |------|---------|
410
+ | `models.ts` | `UserSchema`, `PostSchema`, etc. (Zod schemas for each model) |
411
+ | `enums.ts` | `RoleSchema`, `StatusSchema`, etc. (Zod schemas for enums) |
412
+ | `generated-relations.ts` | `modelRelations` (relation metadata for Query Engine) |
413
+ | `generated-index.ts` | Re-exports all above + `models` namespace |
414
+ | `custom-schemas.ts` | Your custom JSON field schemas (created once, not overwritten) |
415
+
416
+ ### CLI
417
+
418
+ ```bash
419
+ # Inspect schema structure
420
+ zodipus inspect <schema.prisma> [--models] [--enums] [--relations] [--json]
421
+
422
+ # Generate with dry-run
423
+ zodipus generate <schema.prisma> [--dry-run]
424
+ ```
package/dist/cli.cjs ADDED
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var child_process = require('child_process');
5
+ var path = require('path');
6
+ var commander = require('commander');
7
+
8
+ var program = new commander.Command();
9
+ program.name("zodipus").description("Zodipus: solves your schema tragedies").version("0.1.0");
10
+ function runPrismaGenerate(schemaPath, env) {
11
+ return new Promise((resolvePromise, reject) => {
12
+ const resolvedPath = path.resolve(process.cwd(), schemaPath);
13
+ console.log("\n\u{1F680} Running Zodipus via Prisma Generator...");
14
+ console.log(`\u{1F4C4} Schema: ${resolvedPath}
15
+ `);
16
+ const child = child_process.spawn(
17
+ "pnpm dlx",
18
+ [
19
+ "prisma",
20
+ "generate",
21
+ "--schema",
22
+ resolvedPath,
23
+ "--generator",
24
+ "zodipus"
25
+ // Only run our generator
26
+ ],
27
+ {
28
+ stdio: "inherit",
29
+ env: {
30
+ ...process.env,
31
+ ...env
32
+ },
33
+ shell: true
34
+ }
35
+ );
36
+ child.on("close", (code) => {
37
+ if (code === 0) {
38
+ resolvePromise();
39
+ } else {
40
+ reject(new Error(`Prisma generate failed with exit code ${code}`));
41
+ }
42
+ });
43
+ child.on("error", (err) => {
44
+ reject(err);
45
+ });
46
+ });
47
+ }
48
+ program.command("inspect").description("Inspect a Prisma schema and show its structure").argument("<schema>", "Path to the Prisma schema file").option("-m, --models", "Show only models").option("-e, --enums", "Show only enums").option("-r, --relations", "Show only relations").option("--json", "Output as JSON").action(async (schemaPath, options) => {
49
+ const flags = [];
50
+ if (options.models) flags.push("models");
51
+ if (options.enums) flags.push("enums");
52
+ if (options.relations) flags.push("relations");
53
+ try {
54
+ await runPrismaGenerate(schemaPath, {
55
+ ZODIPUS_CMD: "inspect",
56
+ ZODIPUS_INSPECT_FLAGS: flags.join(","),
57
+ ZODIPUS_INSPECT_JSON: options.json ? "true" : "false"
58
+ });
59
+ } catch (error) {
60
+ console.error("\n\u274C Inspect failed:", error instanceof Error ? error.message : error);
61
+ process.exit(1);
62
+ }
63
+ });
64
+ program.command("generate").description("Generate Zod schemas from a Prisma schema").argument("<schema>", "Path to the Prisma schema file").option("-o, --output <dir>", "Output directory (defaults to schema config)").option("--dry-run", "Preview output without writing files").action(async (schemaPath, options) => {
65
+ try {
66
+ if (options.output) {
67
+ console.warn(
68
+ "\u26A0\uFE0F Note: --output flag is currently ignored by the wrapper. Configure output in your schema.prisma file."
69
+ );
70
+ }
71
+ await runPrismaGenerate(schemaPath, {
72
+ ZODIPUS_CMD: "generate",
73
+ ZODIPUS_DRY_RUN: options.dryRun ? "true" : "false"
74
+ });
75
+ } catch (error) {
76
+ console.error("\n\u274C Generation failed:", error instanceof Error ? error.message : error);
77
+ process.exit(1);
78
+ }
79
+ });
80
+ program.parse();
81
+ //# sourceMappingURL=cli.cjs.map
82
+ //# sourceMappingURL=cli.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts"],"names":["Command","resolve","spawn"],"mappings":"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","file":"cli.cjs","sourcesContent":["#!/usr/bin/env node\n/**\n * Zodipus CLI\n *\n * Command-line interface for schema inspection and generation.\n * Wraps `prisma generate` with special environment variables to trigger\n * inspection or dry-run modes within the native generator execution.\n */\n\nimport { spawn } from 'node:child_process';\nimport { resolve } from 'node:path';\nimport { Command } from 'commander';\n\nconst program = new Command();\n\nprogram.name('zodipus').description('Zodipus: solves your schema tragedies').version('0.1.0');\n\n/**\n * Execute prisma generate with custom env vars\n */\nfunction runPrismaGenerate(schemaPath: string, env: Record<string, string>): Promise<void> {\n return new Promise((resolvePromise, reject) => {\n const resolvedPath = resolve(process.cwd(), schemaPath);\n console.log('\\nšŸš€ Running Zodipus via Prisma Generator...');\n console.log(`šŸ“„ Schema: ${resolvedPath}\\n`);\n\n const child = spawn(\n 'pnpm dlx',\n [\n 'prisma',\n 'generate',\n '--schema',\n resolvedPath,\n '--generator',\n 'zodipus', // Only run our generator\n ],\n {\n stdio: 'inherit',\n env: {\n ...process.env,\n ...env,\n },\n shell: true,\n }\n );\n\n child.on('close', (code) => {\n if (code === 0) {\n resolvePromise();\n } else {\n reject(new Error(`Prisma generate failed with exit code ${code}`));\n }\n });\n\n child.on('error', (err) => {\n reject(err);\n });\n });\n}\n\n/**\n * Inspect command - shows models, enums, and relations from a Prisma schema\n */\nprogram\n .command('inspect')\n .description('Inspect a Prisma schema and show its structure')\n .argument('<schema>', 'Path to the Prisma schema file')\n .option('-m, --models', 'Show only models')\n .option('-e, --enums', 'Show only enums')\n .option('-r, --relations', 'Show only relations')\n .option('--json', 'Output as JSON')\n .action(async (schemaPath: string, options) => {\n const flags: string[] = [];\n if (options.models) flags.push('models');\n if (options.enums) flags.push('enums');\n if (options.relations) flags.push('relations');\n\n try {\n await runPrismaGenerate(schemaPath, {\n ZODIPUS_CMD: 'inspect',\n ZODIPUS_INSPECT_FLAGS: flags.join(','),\n ZODIPUS_INSPECT_JSON: options.json ? 'true' : 'false',\n });\n } catch (error) {\n console.error('\\nāŒ Inspect failed:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n });\n\n/**\n * Generate command with --dry-run support\n */\nprogram\n .command('generate')\n .description('Generate Zod schemas from a Prisma schema')\n .argument('<schema>', 'Path to the Prisma schema file')\n .option('-o, --output <dir>', 'Output directory (defaults to schema config)')\n .option('--dry-run', 'Preview output without writing files')\n .action(async (schemaPath: string, options) => {\n try {\n if (options.output) {\n console.warn(\n 'āš ļø Note: --output flag is currently ignored by the wrapper. Configure output in your schema.prisma file.'\n );\n }\n\n await runPrismaGenerate(schemaPath, {\n ZODIPUS_CMD: 'generate',\n ZODIPUS_DRY_RUN: options.dryRun ? 'true' : 'false',\n });\n } catch (error) {\n console.error('\\nāŒ Generation failed:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n });\n\nprogram.parse();\n"]}
package/dist/cli.d.cts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ // src/errors.ts
4
+ var ZodipusError = class extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "ZodipusError";
8
+ if (Error.captureStackTrace) {
9
+ Error.captureStackTrace(this, this.constructor);
10
+ }
11
+ }
12
+ };
13
+ var ZodipusValidationError = class extends ZodipusError {
14
+ context;
15
+ constructor(message, context) {
16
+ const contextInfo = [
17
+ `Model: ${context.model}`,
18
+ context.field ? `Field: ${context.field}` : null,
19
+ context.expected ? `Expected: ${context.expected}` : null,
20
+ context.received ? `Received: ${context.received}` : null,
21
+ context.path?.length ? `Path: ${context.path.join(".")}` : null
22
+ ].filter(Boolean).join(", ");
23
+ super(`${message} (${contextInfo})`);
24
+ this.name = "ZodipusValidationError";
25
+ this.context = context;
26
+ }
27
+ };
28
+ var ZodipusGeneratorError = class extends ZodipusError {
29
+ schemaPath;
30
+ modelName;
31
+ constructor(message, options) {
32
+ const contextParts = [
33
+ options?.schemaPath ? `Schema: ${options.schemaPath}` : null,
34
+ options?.modelName ? `Model: ${options.modelName}` : null
35
+ ].filter(Boolean);
36
+ const fullMessage = contextParts.length ? `${message} (${contextParts.join(", ")})` : message;
37
+ super(fullMessage);
38
+ this.name = "ZodipusGeneratorError";
39
+ this.schemaPath = options?.schemaPath;
40
+ this.modelName = options?.modelName;
41
+ }
42
+ };
43
+
44
+ exports.ZodipusError = ZodipusError;
45
+ exports.ZodipusGeneratorError = ZodipusGeneratorError;
46
+ exports.ZodipusValidationError = ZodipusValidationError;
47
+ //# sourceMappingURL=errors.cjs.map
48
+ //# sourceMappingURL=errors.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts"],"names":[],"mappings":";;;AAUO,IAAM,YAAA,GAAN,cAA2B,KAAA,CAAM;AAAA,EACtC,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,cAAA;AAEZ,IAAA,IAAI,MAAM,iBAAA,EAAmB;AAC3B,MAAA,KAAA,CAAM,iBAAA,CAAkB,IAAA,EAAM,IAAA,CAAK,WAAW,CAAA;AAAA,IAChD;AAAA,EACF;AACF;AAgCO,IAAM,sBAAA,GAAN,cAAqC,YAAA,CAAa;AAAA,EAC9C,OAAA;AAAA,EAET,WAAA,CAAY,SAAiB,OAAA,EAAiC;AAC5D,IAAA,MAAM,WAAA,GAAc;AAAA,MAClB,CAAA,OAAA,EAAU,QAAQ,KAAK,CAAA,CAAA;AAAA,MACvB,OAAA,CAAQ,KAAA,GAAQ,CAAA,OAAA,EAAU,OAAA,CAAQ,KAAK,CAAA,CAAA,GAAK,IAAA;AAAA,MAC5C,OAAA,CAAQ,QAAA,GAAW,CAAA,UAAA,EAAa,OAAA,CAAQ,QAAQ,CAAA,CAAA,GAAK,IAAA;AAAA,MACrD,OAAA,CAAQ,QAAA,GAAW,CAAA,UAAA,EAAa,OAAA,CAAQ,QAAQ,CAAA,CAAA,GAAK,IAAA;AAAA,MACrD,OAAA,CAAQ,MAAM,MAAA,GAAS,CAAA,MAAA,EAAS,QAAQ,IAAA,CAAK,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,GAAK;AAAA,KAC7D,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,IAAI,CAAA;AAEZ,IAAA,KAAA,CAAM,CAAA,EAAG,OAAO,CAAA,EAAA,EAAK,WAAW,CAAA,CAAA,CAAG,CAAA;AACnC,IAAA,IAAA,CAAK,IAAA,GAAO,wBAAA;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AACF;AAKO,IAAM,qBAAA,GAAN,cAAoC,YAAA,CAAa;AAAA,EAC7C,UAAA;AAAA,EACA,SAAA;AAAA,EAET,WAAA,CAAY,SAAiB,OAAA,EAAuD;AAClF,IAAA,MAAM,YAAA,GAAe;AAAA,MACnB,OAAA,EAAS,UAAA,GAAa,CAAA,QAAA,EAAW,OAAA,CAAQ,UAAU,CAAA,CAAA,GAAK,IAAA;AAAA,MACxD,OAAA,EAAS,SAAA,GAAY,CAAA,OAAA,EAAU,OAAA,CAAQ,SAAS,CAAA,CAAA,GAAK;AAAA,KACvD,CAAE,OAAO,OAAO,CAAA;AAEhB,IAAA,MAAM,WAAA,GAAc,YAAA,CAAa,MAAA,GAAS,CAAA,EAAG,OAAO,KAAK,YAAA,CAAa,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA,GAAM,OAAA;AAEtF,IAAA,KAAA,CAAM,WAAW,CAAA;AACjB,IAAA,IAAA,CAAK,IAAA,GAAO,uBAAA;AACZ,IAAA,IAAA,CAAK,aAAa,OAAA,EAAS,UAAA;AAC3B,IAAA,IAAA,CAAK,YAAY,OAAA,EAAS,SAAA;AAAA,EAC5B;AACF","file":"errors.cjs","sourcesContent":["/**\n * Custom error classes for Zodipus\n *\n * These errors provide better context for debugging validation\n * and generation issues.\n */\n\n/**\n * Base error class for all Zodipus errors\n */\nexport class ZodipusError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ZodipusError';\n // Maintains proper stack trace for where error was thrown (V8 engines)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Context for validation errors\n */\nexport interface ValidationErrorContext {\n /** The model being validated */\n model: string;\n /** The field that failed validation (if applicable) */\n field?: string;\n /** The expected type or value */\n expected?: string;\n /** The received type or value */\n received?: string;\n /** The path to the field in nested objects */\n path?: (string | number)[];\n}\n\n/**\n * Error thrown when data validation fails\n *\n * @example\n * ```typescript\n * throw new ZodipusValidationError('Invalid data type', {\n * model: 'User',\n * field: 'email',\n * expected: 'string',\n * received: 'number',\n * path: ['user', 'email'],\n * });\n * ```\n */\nexport class ZodipusValidationError extends ZodipusError {\n readonly context: ValidationErrorContext;\n\n constructor(message: string, context: ValidationErrorContext) {\n const contextInfo = [\n `Model: ${context.model}`,\n context.field ? `Field: ${context.field}` : null,\n context.expected ? `Expected: ${context.expected}` : null,\n context.received ? `Received: ${context.received}` : null,\n context.path?.length ? `Path: ${context.path.join('.')}` : null,\n ]\n .filter(Boolean)\n .join(', ');\n\n super(`${message} (${contextInfo})`);\n this.name = 'ZodipusValidationError';\n this.context = context;\n }\n}\n\n/**\n * Error thrown during schema generation\n */\nexport class ZodipusGeneratorError extends ZodipusError {\n readonly schemaPath?: string;\n readonly modelName?: string;\n\n constructor(message: string, options?: { schemaPath?: string; modelName?: string }) {\n const contextParts = [\n options?.schemaPath ? `Schema: ${options.schemaPath}` : null,\n options?.modelName ? `Model: ${options.modelName}` : null,\n ].filter(Boolean);\n\n const fullMessage = contextParts.length ? `${message} (${contextParts.join(', ')})` : message;\n\n super(fullMessage);\n this.name = 'ZodipusGeneratorError';\n this.schemaPath = options?.schemaPath;\n this.modelName = options?.modelName;\n }\n}\n"]}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Custom error classes for Zodipus
3
+ *
4
+ * These errors provide better context for debugging validation
5
+ * and generation issues.
6
+ */
7
+ /**
8
+ * Base error class for all Zodipus errors
9
+ */
10
+ declare class ZodipusError extends Error {
11
+ constructor(message: string);
12
+ }
13
+ /**
14
+ * Context for validation errors
15
+ */
16
+ interface ValidationErrorContext {
17
+ /** The model being validated */
18
+ model: string;
19
+ /** The field that failed validation (if applicable) */
20
+ field?: string;
21
+ /** The expected type or value */
22
+ expected?: string;
23
+ /** The received type or value */
24
+ received?: string;
25
+ /** The path to the field in nested objects */
26
+ path?: (string | number)[];
27
+ }
28
+ /**
29
+ * Error thrown when data validation fails
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * throw new ZodipusValidationError('Invalid data type', {
34
+ * model: 'User',
35
+ * field: 'email',
36
+ * expected: 'string',
37
+ * received: 'number',
38
+ * path: ['user', 'email'],
39
+ * });
40
+ * ```
41
+ */
42
+ declare class ZodipusValidationError extends ZodipusError {
43
+ readonly context: ValidationErrorContext;
44
+ constructor(message: string, context: ValidationErrorContext);
45
+ }
46
+ /**
47
+ * Error thrown during schema generation
48
+ */
49
+ declare class ZodipusGeneratorError extends ZodipusError {
50
+ readonly schemaPath?: string;
51
+ readonly modelName?: string;
52
+ constructor(message: string, options?: {
53
+ schemaPath?: string;
54
+ modelName?: string;
55
+ });
56
+ }
57
+
58
+ export { type ValidationErrorContext, ZodipusError, ZodipusGeneratorError, ZodipusValidationError };