zodvex 0.2.5 → 0.3.2
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 +319 -7
- package/dist/index.d.ts +177 -66
- package/dist/index.js +122 -21
- package/dist/index.js.map +1 -1
- package/package.json +4 -16
- package/src/__type-tests__/infer-returns.ts +154 -0
- package/src/__type-tests__/zodTable-inference.ts +476 -0
- package/src/custom.ts +15 -6
- package/src/ids.ts +8 -8
- package/src/registry.ts +171 -0
- package/src/tables.ts +238 -30
- package/src/types.ts +10 -22
- package/src/wrappers.ts +2 -2
package/README.md
CHANGED
|
@@ -18,6 +18,13 @@ Type-safe Convex functions with Zod schemas. Preserve Convex's optional/nullable
|
|
|
18
18
|
- [Form Validation](#form-validation)
|
|
19
19
|
- [API Reference](#api-reference)
|
|
20
20
|
- [Advanced Usage](#advanced-usage)
|
|
21
|
+
- [Custom Context Builders](#custom-context-builders)
|
|
22
|
+
- [Date Handling](#date-handling)
|
|
23
|
+
- [Return Type Helpers](#return-type-helpers)
|
|
24
|
+
- [Working with Large Schemas](#working-with-large-schemas)
|
|
25
|
+
- [Polymorphic Tables with Unions](#polymorphic-tables-with-unions)
|
|
26
|
+
- [AI SDK Compatibility](#ai-sdk-compatibility)
|
|
27
|
+
- [Migration Guide](./MIGRATION.md)
|
|
21
28
|
|
|
22
29
|
## Installation
|
|
23
30
|
|
|
@@ -441,27 +448,94 @@ export const updateProfile = authMutation({
|
|
|
441
448
|
|
|
442
449
|
### Date Handling
|
|
443
450
|
|
|
444
|
-
|
|
451
|
+
zodvex automatically converts dates between JavaScript `Date` objects and Convex timestamps when using `z.date()` in your schemas.
|
|
452
|
+
|
|
453
|
+
#### Automatic Conversion (Recommended)
|
|
454
|
+
|
|
455
|
+
Use `z.date()` for automatic handling - no manual conversion needed:
|
|
445
456
|
|
|
446
457
|
```ts
|
|
447
458
|
const eventShape = {
|
|
448
459
|
title: z.string(),
|
|
449
460
|
startDate: z.date(),
|
|
450
|
-
endDate: z.date().nullable()
|
|
461
|
+
endDate: z.date().nullable(),
|
|
462
|
+
createdAt: z.date().optional()
|
|
451
463
|
}
|
|
452
464
|
|
|
453
465
|
export const Events = zodTable('events', eventShape)
|
|
454
466
|
|
|
467
|
+
// In your function - dates work seamlessly
|
|
455
468
|
export const createEvent = zm({
|
|
456
469
|
args: eventShape,
|
|
457
|
-
handler: async (ctx,
|
|
458
|
-
//
|
|
459
|
-
//
|
|
460
|
-
|
|
470
|
+
handler: async (ctx, { startDate, endDate, title }) => {
|
|
471
|
+
// startDate and endDate are already Date objects!
|
|
472
|
+
console.log(startDate.toISOString()) // ✅ Works
|
|
473
|
+
|
|
474
|
+
// Automatically converted to timestamps for storage
|
|
475
|
+
return await ctx.db.insert('events', { title, startDate, endDate })
|
|
461
476
|
}
|
|
462
477
|
})
|
|
478
|
+
|
|
479
|
+
// On the frontend - just pass Date objects
|
|
480
|
+
const createEvent = useMutation(api.events.createEvent)
|
|
481
|
+
await createEvent({
|
|
482
|
+
title: 'My Event',
|
|
483
|
+
startDate: new Date('2024-01-01'),
|
|
484
|
+
endDate: new Date('2024-01-02')
|
|
485
|
+
})
|
|
486
|
+
// ✅ No manual conversion needed!
|
|
463
487
|
```
|
|
464
488
|
|
|
489
|
+
**How it works:**
|
|
490
|
+
- **Args**: Timestamps from client → automatically decoded to `Date` objects
|
|
491
|
+
- **Returns**: `Date` objects from handler → automatically encoded to timestamps
|
|
492
|
+
- **Storage**: Dates are stored as `v.float64()` (Convex doesn't have a native Date type)
|
|
493
|
+
|
|
494
|
+
#### Manual String Dates (Alternative)
|
|
495
|
+
|
|
496
|
+
If you prefer working with ISO strings instead of Date objects, use `z.string()`:
|
|
497
|
+
|
|
498
|
+
```ts
|
|
499
|
+
// ❌ Using z.string() means NO automatic conversion
|
|
500
|
+
const schema = {
|
|
501
|
+
birthday: z.string() // Stored as ISO string
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
export const updateUser = zm({
|
|
505
|
+
args: schema,
|
|
506
|
+
handler: async (ctx, { birthday }) => {
|
|
507
|
+
// birthday is a string, you must manually parse
|
|
508
|
+
const date = new Date(birthday) // Manual conversion
|
|
509
|
+
await ctx.db.insert('users', { birthday })
|
|
510
|
+
}
|
|
511
|
+
})
|
|
512
|
+
|
|
513
|
+
// On frontend - manual conversion
|
|
514
|
+
await updateUser({
|
|
515
|
+
birthday: new Date().toISOString() // Must manually convert
|
|
516
|
+
})
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
**When to use which:**
|
|
520
|
+
- ✅ **`z.date()`** - When you want automatic conversion and type-safe Date objects (recommended)
|
|
521
|
+
- ⚠️ **`z.string()`** - When you need ISO strings for display/formatting (requires manual parsing)
|
|
522
|
+
|
|
523
|
+
#### Edge Case: Date/Number Unions
|
|
524
|
+
|
|
525
|
+
If you need a field that accepts both dates and numbers (rare), use explicit transforms:
|
|
526
|
+
|
|
527
|
+
```ts
|
|
528
|
+
// Edge case: field that can be a date OR a timestamp
|
|
529
|
+
const flexibleDate = z.union([
|
|
530
|
+
z.date(),
|
|
531
|
+
z.number().transform(ts => new Date(ts))
|
|
532
|
+
])
|
|
533
|
+
|
|
534
|
+
// Most apps don't need this - fields are either dates OR numbers, not both
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
**Note:** In real-world schemas, mixing dates and numbers in unions is uncommon. Design your data model so fields have a single type.
|
|
538
|
+
|
|
465
539
|
### Return Type Helpers
|
|
466
540
|
|
|
467
541
|
```ts
|
|
@@ -501,6 +575,243 @@ const UserUpdate = safePick(User, {
|
|
|
501
575
|
})
|
|
502
576
|
```
|
|
503
577
|
|
|
578
|
+
### Polymorphic Tables with Unions
|
|
579
|
+
|
|
580
|
+
zodvex fully supports polymorphic tables using discriminated unions! Use `zodTable()` directly with union schemas:
|
|
581
|
+
|
|
582
|
+
```ts
|
|
583
|
+
import { zodTable, zid } from 'zodvex'
|
|
584
|
+
import { z } from 'zod'
|
|
585
|
+
|
|
586
|
+
// Define your discriminated union schema
|
|
587
|
+
const shapeSchema = z.union([
|
|
588
|
+
z.object({
|
|
589
|
+
kind: z.literal('circle'),
|
|
590
|
+
cx: z.number(),
|
|
591
|
+
cy: z.number(),
|
|
592
|
+
r: z.number()
|
|
593
|
+
}),
|
|
594
|
+
z.object({
|
|
595
|
+
kind: z.literal('rectangle'),
|
|
596
|
+
x: z.number(),
|
|
597
|
+
y: z.number(),
|
|
598
|
+
width: z.number(),
|
|
599
|
+
height: z.number()
|
|
600
|
+
}),
|
|
601
|
+
z.object({
|
|
602
|
+
kind: z.literal('path'),
|
|
603
|
+
path: z.string()
|
|
604
|
+
})
|
|
605
|
+
])
|
|
606
|
+
|
|
607
|
+
// Define the table - zodTable() accepts unions!
|
|
608
|
+
export const Shapes = zodTable('shapes', shapeSchema)
|
|
609
|
+
|
|
610
|
+
// Use in schema
|
|
611
|
+
export default defineSchema({
|
|
612
|
+
shapes: Shapes.table
|
|
613
|
+
})
|
|
614
|
+
|
|
615
|
+
// docArray automatically includes system fields for each variant
|
|
616
|
+
export const getShapes = zq({
|
|
617
|
+
args: {},
|
|
618
|
+
returns: Shapes.docArray, // ✅ Each variant has _id and _creationTime
|
|
619
|
+
handler: async (ctx) => ctx.db.query('shapes').collect()
|
|
620
|
+
})
|
|
621
|
+
|
|
622
|
+
// Create with type-safe discriminated unions
|
|
623
|
+
export const createShape = zm({
|
|
624
|
+
args: shapeSchema,
|
|
625
|
+
handler: async (ctx, shape) => {
|
|
626
|
+
// shape is discriminated - TypeScript knows the fields based on `kind`
|
|
627
|
+
return await ctx.db.insert('shapes', shape)
|
|
628
|
+
}
|
|
629
|
+
})
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
#### Union Table Helpers
|
|
633
|
+
|
|
634
|
+
Union tables provide different helpers than object tables:
|
|
635
|
+
|
|
636
|
+
```ts
|
|
637
|
+
const Shapes = zodTable('shapes', shapeSchema)
|
|
638
|
+
|
|
639
|
+
// Available properties:
|
|
640
|
+
Shapes.table // TableDefinition for schema
|
|
641
|
+
Shapes.tableName // 'shapes'
|
|
642
|
+
Shapes.schema // Original union schema
|
|
643
|
+
Shapes.validator // Convex validator (union)
|
|
644
|
+
Shapes.docArray // Array schema with system fields added to each variant
|
|
645
|
+
Shapes.withSystemFields() // Returns union with _id and _creationTime on each variant
|
|
646
|
+
|
|
647
|
+
// NOT available (specific to object tables):
|
|
648
|
+
// Shapes.shape - unions don't have a fixed shape
|
|
649
|
+
// Shapes.zDoc - use withSystemFields() instead
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
#### Advanced Union Patterns
|
|
653
|
+
|
|
654
|
+
**Shared base schema:**
|
|
655
|
+
|
|
656
|
+
```ts
|
|
657
|
+
const baseShape = z.object({
|
|
658
|
+
color: z.string(),
|
|
659
|
+
strokeWidth: z.number()
|
|
660
|
+
})
|
|
661
|
+
|
|
662
|
+
const shapeSchema = z.union([
|
|
663
|
+
baseShape.extend({
|
|
664
|
+
kind: z.literal('circle'),
|
|
665
|
+
radius: z.number()
|
|
666
|
+
}),
|
|
667
|
+
baseShape.extend({
|
|
668
|
+
kind: z.literal('rectangle'),
|
|
669
|
+
width: z.number(),
|
|
670
|
+
height: z.number()
|
|
671
|
+
})
|
|
672
|
+
])
|
|
673
|
+
|
|
674
|
+
export const Shapes = zodTable('shapes', shapeSchema)
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
**Using z.discriminatedUnion:**
|
|
678
|
+
|
|
679
|
+
```ts
|
|
680
|
+
const shapeSchema = z.discriminatedUnion('kind', [
|
|
681
|
+
z.object({ kind: z.literal('circle'), r: z.number() }),
|
|
682
|
+
z.object({ kind: z.literal('rectangle'), w: z.number(), h: z.number() })
|
|
683
|
+
])
|
|
684
|
+
|
|
685
|
+
export const Shapes = zodTable('shapes', shapeSchema)
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
**When to use discriminated unions:**
|
|
689
|
+
- Polymorphic data (e.g., different shape types, notification variants)
|
|
690
|
+
- Tables with multiple distinct subtypes sharing common fields
|
|
691
|
+
- Event sourcing patterns with different event types
|
|
692
|
+
- When you need type-safe variant handling in TypeScript
|
|
693
|
+
|
|
694
|
+
**Learn more:**
|
|
695
|
+
- [Convex Polymorphic Data](https://docs.convex.dev/database/types#polymorphic-types)
|
|
696
|
+
- [Zod Discriminated Unions](https://zod.dev/discriminated-unions)
|
|
697
|
+
|
|
698
|
+
### AI SDK Compatibility
|
|
699
|
+
|
|
700
|
+
zodvex schemas are fully compatible with [Vercel's AI SDK](https://sdk.vercel.ai/docs), including `zid` for Convex IDs.
|
|
701
|
+
|
|
702
|
+
#### Using with AI SDK
|
|
703
|
+
|
|
704
|
+
```ts
|
|
705
|
+
import { generateObject } from 'ai'
|
|
706
|
+
import { openai } from '@ai-sdk/openai'
|
|
707
|
+
import { z } from 'zod'
|
|
708
|
+
import { zid } from 'zodvex'
|
|
709
|
+
|
|
710
|
+
const userSchema = z.object({
|
|
711
|
+
id: zid('users'), // ✅ Works with AI SDK
|
|
712
|
+
name: z.string(),
|
|
713
|
+
email: z.string().email(),
|
|
714
|
+
age: z.number().int(),
|
|
715
|
+
teamId: zid('teams').optional()
|
|
716
|
+
})
|
|
717
|
+
|
|
718
|
+
const result = await generateObject({
|
|
719
|
+
model: openai('gpt-4'),
|
|
720
|
+
schema: userSchema,
|
|
721
|
+
prompt: 'Generate a sample user profile'
|
|
722
|
+
})
|
|
723
|
+
|
|
724
|
+
// result.object is fully typed and validated
|
|
725
|
+
console.log(result.object.id) // Type: GenericId<'users'>
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
#### Why It Works
|
|
729
|
+
|
|
730
|
+
AI SDK requires schemas to be serializable (no `.transform()` or `.brand()`). zodvex's `zid` uses type-level branding instead of runtime transforms, making it compatible:
|
|
731
|
+
|
|
732
|
+
```ts
|
|
733
|
+
// zodvex approach (compatible)
|
|
734
|
+
zid('users') // String validator with type assertion → GenericId<'users'>
|
|
735
|
+
|
|
736
|
+
// Not compatible (using transforms)
|
|
737
|
+
z.string().transform(s => s as GenericId<'users'>) // ❌ AI SDK rejects
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
#### Schemas with Custom Transforms
|
|
741
|
+
|
|
742
|
+
If you have schemas with custom `.transform()` or `.pipe()`, AI SDK may reject them. For complex transformations, consider:
|
|
743
|
+
|
|
744
|
+
**Option 1: Separate schemas**
|
|
745
|
+
```ts
|
|
746
|
+
// For AI SDK (no transforms)
|
|
747
|
+
const aiUserSchema = z.object({
|
|
748
|
+
createdAt: z.string() // ISO string
|
|
749
|
+
})
|
|
750
|
+
|
|
751
|
+
// For internal use (with transforms)
|
|
752
|
+
const internalUserSchema = z.object({
|
|
753
|
+
createdAt: z.string().transform(s => new Date(s))
|
|
754
|
+
})
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
**Option 2: Use zodvex's JSON Schema helper**
|
|
758
|
+
```ts
|
|
759
|
+
import { toJSONSchema } from 'zodvex'
|
|
760
|
+
|
|
761
|
+
const schema = z.object({
|
|
762
|
+
userId: zid('users'),
|
|
763
|
+
createdAt: z.date(),
|
|
764
|
+
name: z.string()
|
|
765
|
+
})
|
|
766
|
+
|
|
767
|
+
// Automatically handles zid and z.date() for JSON Schema generation
|
|
768
|
+
const jsonSchema = toJSONSchema(schema)
|
|
769
|
+
// Use with AI SDK or other JSON Schema consumers
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
The `toJSONSchema` helper automatically handles zodvex-managed types:
|
|
773
|
+
- `zid('tableName')` → `{ type: "string", format: "convex-id:tableName" }`
|
|
774
|
+
- `z.date()` → `{ type: "string", format: "date-time" }`
|
|
775
|
+
|
|
776
|
+
For custom overrides, use `zodvexJSONSchemaOverride` directly:
|
|
777
|
+
```ts
|
|
778
|
+
import { zodvexJSONSchemaOverride, composeOverrides } from 'zodvex'
|
|
779
|
+
|
|
780
|
+
const jsonSchema = z.toJSONSchema(schema, {
|
|
781
|
+
unrepresentable: 'any',
|
|
782
|
+
override: composeOverrides(myCustomOverride, zodvexJSONSchemaOverride)
|
|
783
|
+
})
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
## zodvex vs convex-helpers/zod4
|
|
787
|
+
|
|
788
|
+
Convex officially supports Zod 4 via `convex-helpers/server/zod4`. zodvex builds on those primitives to provide a batteries-included, opinionated solution.
|
|
789
|
+
|
|
790
|
+
**Use convex-helpers if you want:**
|
|
791
|
+
- Low-level control over encoding/decoding
|
|
792
|
+
- Explicit Zod codecs for all conversions
|
|
793
|
+
- Minimal abstractions
|
|
794
|
+
- Both Zod 3 and 4 support in one package
|
|
795
|
+
|
|
796
|
+
**Use zodvex if you want:**
|
|
797
|
+
- Automatic date handling (no manual codecs needed)
|
|
798
|
+
- Table helpers with `.table`, `.zDoc`, `.docArray`, `.shape`
|
|
799
|
+
- Builder pattern API for consistent function definitions
|
|
800
|
+
- Codec abstraction with `.pick()` for subsets
|
|
801
|
+
- Turnkey developer experience
|
|
802
|
+
|
|
803
|
+
**Key differences:**
|
|
804
|
+
|
|
805
|
+
| Feature | zodvex | convex-helpers/zod4 |
|
|
806
|
+
|---------|--------|---------------------|
|
|
807
|
+
| Date conversion | Automatic with `z.date()` | Manual `z.codec()` required |
|
|
808
|
+
| Table helpers | `zodTable()` with helpers | Not provided |
|
|
809
|
+
| Builder pattern | `zQueryBuilder()`, etc. | Not provided |
|
|
810
|
+
| Codec abstraction | `convexCodec()` with `.pick()` | Not provided |
|
|
811
|
+
| Philosophy | Batteries-included | Minimal primitives |
|
|
812
|
+
|
|
813
|
+
Both are valid choices - zodvex trades some explicitness for significantly better ergonomics.
|
|
814
|
+
|
|
504
815
|
## Why zodvex?
|
|
505
816
|
|
|
506
817
|
- **Correct optional/nullable semantics** - Preserves Convex's distinction
|
|
@@ -508,7 +819,8 @@ const UserUpdate = safePick(User, {
|
|
|
508
819
|
- `.nullable()` → `v.union(T, v.null())` (required but can be null)
|
|
509
820
|
- Both → `v.optional(v.union(T, v.null()))`
|
|
510
821
|
- **Superior type safety** - Builders provide better type inference than wrapper functions
|
|
511
|
-
- **
|
|
822
|
+
- **Automatic date handling** - `Date` ↔ timestamp conversion happens transparently
|
|
823
|
+
- **Table helpers** - `zodTable()` provides `.zDoc`, `.docArray`, and `.shape` for DRY schemas
|
|
512
824
|
- **End-to-end validation** - Same schema from database to frontend forms
|
|
513
825
|
|
|
514
826
|
## Compatibility
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Customization } from 'convex-helpers/server/customFunctions';
|
|
2
2
|
export { customCtx } from 'convex-helpers/server/customFunctions';
|
|
3
3
|
import * as convex_server from 'convex/server';
|
|
4
|
-
import { RegisteredQuery, RegisteredMutation, RegisteredAction, DefaultFunctionArgs, FunctionVisibility, ArgsArrayToObject, GenericDataModel, QueryBuilder, GenericQueryCtx } from 'convex/server';
|
|
4
|
+
import { RegisteredQuery, RegisteredMutation, RegisteredAction, DefaultFunctionArgs, FunctionVisibility, ArgsArrayToObject, GenericDataModel, QueryBuilder, GenericQueryCtx, defineTable } from 'convex/server';
|
|
5
5
|
import * as convex_values from 'convex/values';
|
|
6
6
|
import { VAny, VOptional, VUnion, VId, GenericId, VString, VFloat64, VInt64, VBoolean, VNull, VArray, VObject, VLiteral, VRecord, PropertyValidators } from 'convex/values';
|
|
7
7
|
import { z } from 'zod';
|
|
8
|
-
import
|
|
8
|
+
import { Table } from 'convex-helpers/server';
|
|
9
9
|
|
|
10
10
|
type IsZid<T> = T extends {
|
|
11
11
|
_tableName: infer _TableName extends string;
|
|
@@ -61,8 +61,11 @@ declare const registryHelpers: {
|
|
|
61
61
|
/**
|
|
62
62
|
* Create a Zod validator for a Convex Id
|
|
63
63
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
64
|
+
* Compatible with AI SDK and other tools that don't support transforms.
|
|
65
|
+
* Uses type-level branding instead of runtime transforms for GenericId<T> compatibility.
|
|
66
|
+
*
|
|
67
|
+
* @param tableName - The Convex table name for this ID
|
|
68
|
+
* @returns A Zod string validator typed as GenericId<TableName>
|
|
66
69
|
*/
|
|
67
70
|
declare function zid<TableName extends string>(tableName: TableName): z.ZodType<GenericId<TableName>> & {
|
|
68
71
|
_tableName: TableName;
|
|
@@ -75,8 +78,8 @@ declare function getObjectShape(obj: any): Record<string, any>;
|
|
|
75
78
|
type InferArgs<A> = A extends z.ZodObject<infer S> ? z.infer<z.ZodObject<S>> : A extends Record<string, z.ZodTypeAny> ? {
|
|
76
79
|
[K in keyof A]: z.infer<A[K]>;
|
|
77
80
|
} : A extends z.ZodTypeAny ? z.infer<A> : Record<string, never>;
|
|
78
|
-
type InferReturns<R> = R extends z.
|
|
79
|
-
type InferHandlerReturns<R> = R extends z.
|
|
81
|
+
type InferReturns<R> = R extends z.ZodType<any, any, any> ? z.output<R> : R extends undefined ? any : R;
|
|
82
|
+
type InferHandlerReturns<R> = R extends z.ZodType<any, any, any> ? z.input<R> : any;
|
|
80
83
|
/**
|
|
81
84
|
* Extract the visibility type from a Convex builder function
|
|
82
85
|
*/
|
|
@@ -343,7 +346,133 @@ type BaseCodec = {
|
|
|
343
346
|
declare function registerBaseCodec(codec: BaseCodec): void;
|
|
344
347
|
declare function findBaseCodec(schema: any): BaseCodec | undefined;
|
|
345
348
|
declare function isDateSchema(schema: any): boolean;
|
|
349
|
+
/**
|
|
350
|
+
* Checks if a schema is a zid (Convex ID) schema by looking at its description.
|
|
351
|
+
* zid schemas are marked with "convexId:{tableName}" in their description.
|
|
352
|
+
*/
|
|
353
|
+
declare function isZidSchema(schema: z.ZodTypeAny): boolean;
|
|
354
|
+
/**
|
|
355
|
+
* Extracts the table name from a zid schema's description.
|
|
356
|
+
* Returns undefined if not a zid schema.
|
|
357
|
+
*/
|
|
358
|
+
declare function getZidTableName(schema: z.ZodTypeAny): string | undefined;
|
|
359
|
+
/**
|
|
360
|
+
* Context object passed to the JSON Schema override function.
|
|
361
|
+
* Uses 'any' types for compatibility with Zod's internal types.
|
|
362
|
+
*/
|
|
363
|
+
interface JSONSchemaOverrideContext {
|
|
364
|
+
zodSchema: any;
|
|
365
|
+
jsonSchema: any;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Override function for z.toJSONSchema that handles zodvex-managed types.
|
|
369
|
+
*
|
|
370
|
+
* Handles:
|
|
371
|
+
* - zid schemas: Converts to { type: "string" } with convexId format
|
|
372
|
+
* - z.date(): Converts to { type: "string", format: "date-time" }
|
|
373
|
+
*
|
|
374
|
+
* @example
|
|
375
|
+
* ```ts
|
|
376
|
+
* import { z } from 'zod'
|
|
377
|
+
* import { zid, zodvexJSONSchemaOverride } from 'zodvex'
|
|
378
|
+
*
|
|
379
|
+
* const schema = z.object({
|
|
380
|
+
* userId: zid('users'),
|
|
381
|
+
* name: z.string()
|
|
382
|
+
* })
|
|
383
|
+
*
|
|
384
|
+
* const jsonSchema = z.toJSONSchema(schema, {
|
|
385
|
+
* unrepresentable: 'any',
|
|
386
|
+
* override: zodvexJSONSchemaOverride
|
|
387
|
+
* })
|
|
388
|
+
* // => { type: "object", properties: { userId: { type: "string" }, name: { type: "string" } } }
|
|
389
|
+
* ```
|
|
390
|
+
*/
|
|
391
|
+
declare function zodvexJSONSchemaOverride(ctx: JSONSchemaOverrideContext): void;
|
|
392
|
+
/**
|
|
393
|
+
* Composes multiple JSON Schema override functions into one.
|
|
394
|
+
* Overrides run in order - first override runs first.
|
|
395
|
+
*
|
|
396
|
+
* @example
|
|
397
|
+
* ```ts
|
|
398
|
+
* import { composeOverrides, zodvexJSONSchemaOverride } from 'zodvex'
|
|
399
|
+
*
|
|
400
|
+
* const myOverride = (ctx) => {
|
|
401
|
+
* if (ctx.zodSchema.description?.startsWith('myType:')) {
|
|
402
|
+
* ctx.jsonSchema.type = 'string'
|
|
403
|
+
* ctx.jsonSchema.format = 'my-format'
|
|
404
|
+
* }
|
|
405
|
+
* }
|
|
406
|
+
*
|
|
407
|
+
* // User's override runs first, then zodvex's
|
|
408
|
+
* z.toJSONSchema(schema, {
|
|
409
|
+
* unrepresentable: 'any',
|
|
410
|
+
* override: composeOverrides(myOverride, zodvexJSONSchemaOverride)
|
|
411
|
+
* })
|
|
412
|
+
* ```
|
|
413
|
+
*/
|
|
414
|
+
declare function composeOverrides(...overrides: Array<((ctx: JSONSchemaOverrideContext) => void) | undefined>): (ctx: JSONSchemaOverrideContext) => void;
|
|
415
|
+
/**
|
|
416
|
+
* Options for toJSONSchema, matching Zod's interface.
|
|
417
|
+
*/
|
|
418
|
+
interface ToJSONSchemaOptions {
|
|
419
|
+
target?: 'draft-4' | 'draft-7' | 'draft-2020-12' | 'openapi-3.0';
|
|
420
|
+
unrepresentable?: 'throw' | 'any';
|
|
421
|
+
cycles?: 'ref' | 'throw';
|
|
422
|
+
reused?: 'ref' | 'inline';
|
|
423
|
+
io?: 'input' | 'output';
|
|
424
|
+
override?: (ctx: JSONSchemaOverrideContext) => void;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Converts a Zod schema to JSON Schema with zodvex-aware overrides.
|
|
428
|
+
*
|
|
429
|
+
* This is a convenience wrapper around z.toJSONSchema that automatically
|
|
430
|
+
* handles zodvex-managed types like zid and dates.
|
|
431
|
+
*
|
|
432
|
+
* @example
|
|
433
|
+
* ```ts
|
|
434
|
+
* import { zid, toJSONSchema } from 'zodvex'
|
|
435
|
+
*
|
|
436
|
+
* const schema = z.object({
|
|
437
|
+
* userId: zid('users'),
|
|
438
|
+
* createdAt: z.date(),
|
|
439
|
+
* name: z.string()
|
|
440
|
+
* })
|
|
441
|
+
*
|
|
442
|
+
* const jsonSchema = toJSONSchema(schema)
|
|
443
|
+
* // Works with AI SDK's generateObject, etc.
|
|
444
|
+
* ```
|
|
445
|
+
*/
|
|
446
|
+
declare function toJSONSchema<T extends z.ZodTypeAny>(schema: T, options?: ToJSONSchemaOptions): Record<string, any>;
|
|
346
447
|
|
|
448
|
+
/**
|
|
449
|
+
* Helper type for Convex system fields added to documents
|
|
450
|
+
*/
|
|
451
|
+
type SystemFields<TableName extends string> = {
|
|
452
|
+
_id: ReturnType<typeof zid<TableName>>;
|
|
453
|
+
_creationTime: z.ZodNumber;
|
|
454
|
+
};
|
|
455
|
+
/**
|
|
456
|
+
* Maps over union options, extending each ZodObject variant with system fields.
|
|
457
|
+
* Non-object variants are preserved as-is.
|
|
458
|
+
*/
|
|
459
|
+
type MapSystemFields<TableName extends string, Options extends readonly z.ZodTypeAny[]> = {
|
|
460
|
+
[K in keyof Options]: Options[K] extends z.ZodObject<infer Shape extends z.ZodRawShape> ? z.ZodObject<Shape & SystemFields<TableName>> : Options[K];
|
|
461
|
+
};
|
|
462
|
+
/**
|
|
463
|
+
* Adds Convex system fields (_id, _creationTime) to a Zod schema.
|
|
464
|
+
*
|
|
465
|
+
* For object schemas: extends with system fields
|
|
466
|
+
* For union schemas: adds system fields to each variant
|
|
467
|
+
*
|
|
468
|
+
* @param tableName - The Convex table name
|
|
469
|
+
* @param schema - The Zod schema (object or union)
|
|
470
|
+
* @returns Schema with system fields added
|
|
471
|
+
*/
|
|
472
|
+
declare function addSystemFields<TableName extends string, Shape extends z.ZodRawShape>(tableName: TableName, schema: z.ZodObject<Shape>): z.ZodObject<Shape & SystemFields<TableName>>;
|
|
473
|
+
declare function addSystemFields<TableName extends string, Options extends readonly z.ZodTypeAny[]>(tableName: TableName, schema: z.ZodUnion<Options>): z.ZodUnion<MapSystemFields<TableName, Options>>;
|
|
474
|
+
declare function addSystemFields<TableName extends string, Options extends readonly z.ZodObject<z.ZodRawShape>[], Discriminator extends string>(tableName: TableName, schema: z.ZodDiscriminatedUnion<Options, Discriminator>): z.ZodDiscriminatedUnion<MapSystemFields<TableName, Options>, Discriminator>;
|
|
475
|
+
declare function addSystemFields<TableName extends string, S extends z.ZodTypeAny>(tableName: TableName, schema: S): S;
|
|
347
476
|
declare function zodDoc<TableName extends string, Shape extends z.ZodRawShape, Schema extends z.ZodObject<Shape>>(tableName: TableName, schema: Schema): z.ZodObject<Shape & {
|
|
348
477
|
_id: ReturnType<typeof zid<TableName>>;
|
|
349
478
|
_creationTime: z.ZodNumber;
|
|
@@ -357,21 +486,23 @@ declare function zodDocOrNull<TableName extends string, Shape extends z.ZodRawSh
|
|
|
357
486
|
_creationTime: z.ZodNumber;
|
|
358
487
|
}, z.core.$strip>, z.ZodNull]>;
|
|
359
488
|
/**
|
|
360
|
-
* Defines a Convex table using
|
|
489
|
+
* Defines a Convex table using either:
|
|
490
|
+
* - A raw Zod shape (an object mapping field names to Zod types)
|
|
491
|
+
* - A Zod union schema (for polymorphic tables)
|
|
361
492
|
*
|
|
362
|
-
*
|
|
493
|
+
* For object shapes, this function intentionally accepts a raw shape instead of a ZodObject instance.
|
|
363
494
|
* Accepting raw shapes allows TypeScript to infer field types more accurately and efficiently,
|
|
364
495
|
* leading to better type inference and performance throughout the codebase.
|
|
365
|
-
*
|
|
366
|
-
*
|
|
496
|
+
*
|
|
497
|
+
* For union schemas, this enables polymorphic tables with discriminated unions.
|
|
367
498
|
*
|
|
368
499
|
* Returns the Table definition along with Zod schemas for documents and arrays.
|
|
369
500
|
*
|
|
370
501
|
* @param name - The table name
|
|
371
|
-
* @param
|
|
372
|
-
* @returns A Table with attached shape,
|
|
502
|
+
* @param schemaOrShape - Either a raw object shape or a Zod union schema
|
|
503
|
+
* @returns A Table with attached helpers (shape, schema, zDoc, docArray, withSystemFields)
|
|
373
504
|
*
|
|
374
|
-
* @example
|
|
505
|
+
* @example Object shape
|
|
375
506
|
* ```ts
|
|
376
507
|
* const Users = zodTable('users', {
|
|
377
508
|
* name: z.string(),
|
|
@@ -388,65 +519,45 @@ declare function zodDocOrNull<TableName extends string, Shape extends z.ZodRawSh
|
|
|
388
519
|
* { returns: Users.docArray }
|
|
389
520
|
* )
|
|
390
521
|
* ```
|
|
522
|
+
*
|
|
523
|
+
* @example Union schema (polymorphic table)
|
|
524
|
+
* ```ts
|
|
525
|
+
* const shapeSchema = z.union([
|
|
526
|
+
* z.object({ kind: z.literal('circle'), r: z.number() }),
|
|
527
|
+
* z.object({ kind: z.literal('rectangle'), width: z.number() })
|
|
528
|
+
* ])
|
|
529
|
+
*
|
|
530
|
+
* const Shapes = zodTable('shapes', shapeSchema)
|
|
531
|
+
*
|
|
532
|
+
* // Use in schema
|
|
533
|
+
* export default defineSchema({ shapes: Shapes.table })
|
|
534
|
+
*
|
|
535
|
+
* // Use for return types with system fields
|
|
536
|
+
* export const getShapes = zQuery(query, {},
|
|
537
|
+
* async (ctx) => ctx.db.query('shapes').collect(),
|
|
538
|
+
* { returns: Shapes.docArray }
|
|
539
|
+
* )
|
|
540
|
+
* ```
|
|
391
541
|
*/
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
table: convex_server.TableDefinition<convex_values.VObject<convex_server.Expand<{ [Property_1 in { [Property in keyof ConvexValidatorFromZodFieldsAuto<Shape>]: ConvexValidatorFromZodFieldsAuto<Shape>[Property]["isOptional"] extends "optional" ? Property : never; }[keyof Shape]]?: Exclude<convex_values.Infer<ConvexValidatorFromZodFieldsAuto<Shape>[Property_1]>, undefined> | undefined; } & { [Property_2_1 in Exclude<keyof Shape, { [Property_2 in keyof ConvexValidatorFromZodFieldsAuto<Shape>]: ConvexValidatorFromZodFieldsAuto<Shape>[Property_2]["isOptional"] extends "optional" ? Property_2 : never; }[keyof Shape]>]: convex_values.Infer<ConvexValidatorFromZodFieldsAuto<Shape>[Property_2_1]>; }>, ConvexValidatorFromZodFieldsAuto<Shape>, "required", { [Property_3 in keyof ConvexValidatorFromZodFieldsAuto<Shape>]: Property_3 | `${Property_3 & string}.${ConvexValidatorFromZodFieldsAuto<Shape>[Property_3]["fieldPaths"]}`; }[keyof Shape] & string>, {}, {}, {}>;
|
|
395
|
-
doc: convex_values.VObject<convex_server.Expand<{ [Property_5 in (convex_helpers.Expand<ConvexValidatorFromZodFieldsAuto<Shape> & {
|
|
396
|
-
_id: convex_values.VId<GenericId<TableName>, "required">;
|
|
397
|
-
_creationTime: convex_values.VFloat64<number, "required">;
|
|
398
|
-
}> extends infer T_1 extends Record<string, convex_values.GenericValidator> ? { [Property_4 in keyof T_1]: T_1[Property_4]["isOptional"] extends "optional" ? Property_4 : never; } : never)[keyof convex_helpers.Expand<ConvexValidatorFromZodFieldsAuto<Shape> & {
|
|
399
|
-
_id: convex_values.VId<GenericId<TableName>, "required">;
|
|
400
|
-
_creationTime: convex_values.VFloat64<number, "required">;
|
|
401
|
-
}>]]?: Exclude<convex_values.Infer<convex_helpers.Expand<ConvexValidatorFromZodFieldsAuto<Shape> & {
|
|
402
|
-
_id: convex_values.VId<GenericId<TableName>, "required">;
|
|
403
|
-
_creationTime: convex_values.VFloat64<number, "required">;
|
|
404
|
-
}>[Property_5]>, undefined> | undefined; } & { [Property_1_1 in Exclude<keyof convex_helpers.Expand<ConvexValidatorFromZodFieldsAuto<Shape> & {
|
|
405
|
-
_id: convex_values.VId<GenericId<TableName>, "required">;
|
|
406
|
-
_creationTime: convex_values.VFloat64<number, "required">;
|
|
407
|
-
}>, (convex_helpers.Expand<ConvexValidatorFromZodFieldsAuto<Shape> & {
|
|
408
|
-
_id: convex_values.VId<GenericId<TableName>, "required">;
|
|
409
|
-
_creationTime: convex_values.VFloat64<number, "required">;
|
|
410
|
-
}> extends infer T_2 extends Record<string, convex_values.GenericValidator> ? { [Property_4_1 in keyof T_2]: T_2[Property_4_1]["isOptional"] extends "optional" ? Property_4_1 : never; } : never)[keyof convex_helpers.Expand<ConvexValidatorFromZodFieldsAuto<Shape> & {
|
|
411
|
-
_id: convex_values.VId<GenericId<TableName>, "required">;
|
|
412
|
-
_creationTime: convex_values.VFloat64<number, "required">;
|
|
413
|
-
}>]>]: convex_values.Infer<convex_helpers.Expand<ConvexValidatorFromZodFieldsAuto<Shape> & {
|
|
414
|
-
_id: convex_values.VId<GenericId<TableName>, "required">;
|
|
415
|
-
_creationTime: convex_values.VFloat64<number, "required">;
|
|
416
|
-
}>[Property_1_1]>; }>, convex_helpers.Expand<ConvexValidatorFromZodFieldsAuto<Shape> & {
|
|
417
|
-
_id: convex_values.VId<GenericId<TableName>, "required">;
|
|
418
|
-
_creationTime: convex_values.VFloat64<number, "required">;
|
|
419
|
-
}>, "required", (convex_helpers.Expand<ConvexValidatorFromZodFieldsAuto<Shape> & {
|
|
420
|
-
_id: convex_values.VId<GenericId<TableName>, "required">;
|
|
421
|
-
_creationTime: convex_values.VFloat64<number, "required">;
|
|
422
|
-
}> extends infer T_3 extends convex_values.PropertyValidators ? { [Property_2_1_1 in keyof T_3]: Property_2_1_1 | `${Property_2_1_1 & string}.${T_3[Property_2_1_1]["fieldPaths"]}`; } : never)[keyof convex_helpers.Expand<ConvexValidatorFromZodFieldsAuto<Shape> & {
|
|
423
|
-
_id: convex_values.VId<GenericId<TableName>, "required">;
|
|
424
|
-
_creationTime: convex_values.VFloat64<number, "required">;
|
|
425
|
-
}>]>;
|
|
426
|
-
withoutSystemFields: ConvexValidatorFromZodFieldsAuto<Shape>;
|
|
427
|
-
withSystemFields: convex_helpers.Expand<ConvexValidatorFromZodFieldsAuto<Shape> & {
|
|
428
|
-
_id: convex_values.VId<GenericId<TableName>, "required">;
|
|
429
|
-
_creationTime: convex_values.VFloat64<number, "required">;
|
|
430
|
-
}>;
|
|
431
|
-
systemFields: {
|
|
432
|
-
_id: convex_values.VId<GenericId<TableName>, "required">;
|
|
433
|
-
_creationTime: convex_values.VFloat64<number, "required">;
|
|
434
|
-
};
|
|
435
|
-
_id: convex_values.VId<GenericId<TableName>, "required">;
|
|
436
|
-
} & {
|
|
542
|
+
type AddSystemFieldsResult<TableName extends string, Schema extends z.ZodTypeAny> = Schema extends z.ZodObject<infer Shape extends z.ZodRawShape> ? z.ZodObject<Shape & SystemFields<TableName>> : Schema extends z.ZodUnion<infer Options extends readonly z.ZodTypeAny[]> ? z.ZodUnion<MapSystemFields<TableName, Options>> : Schema extends z.ZodDiscriminatedUnion<infer Options extends readonly z.ZodObject<z.ZodRawShape>[], infer Disc extends string> ? z.ZodDiscriminatedUnion<MapSystemFields<TableName, Options>, Disc> : Schema;
|
|
543
|
+
declare function zodTable<TableName extends string, Shape extends Record<string, z.ZodTypeAny>>(name: TableName, shape: Shape): ReturnType<typeof Table<ConvexValidatorFromZodFieldsAuto<Shape>, TableName>> & {
|
|
437
544
|
shape: Shape;
|
|
438
545
|
zDoc: z.ZodObject<Shape & {
|
|
439
546
|
_id: ReturnType<typeof zid<TableName>>;
|
|
440
547
|
_creationTime: z.ZodNumber;
|
|
441
548
|
}>;
|
|
442
|
-
docArray: z.ZodArray<z.ZodObject<
|
|
443
|
-
|
|
444
|
-
}> & {
|
|
445
|
-
_id: z.ZodType<GenericId<TableName>, unknown, z.core.$ZodTypeInternals<GenericId<TableName>, unknown>> & {
|
|
446
|
-
_tableName: TableName;
|
|
447
|
-
};
|
|
549
|
+
docArray: z.ZodArray<z.ZodObject<Shape & {
|
|
550
|
+
_id: ReturnType<typeof zid<TableName>>;
|
|
448
551
|
_creationTime: z.ZodNumber;
|
|
449
|
-
}
|
|
552
|
+
}>>;
|
|
553
|
+
};
|
|
554
|
+
declare function zodTable<TableName extends string, Schema extends z.ZodTypeAny>(name: TableName, schema: Schema): {
|
|
555
|
+
table: ReturnType<typeof defineTable>;
|
|
556
|
+
tableName: TableName;
|
|
557
|
+
validator: ReturnType<typeof zodToConvex<Schema>>;
|
|
558
|
+
schema: Schema;
|
|
559
|
+
docArray: z.ZodArray<AddSystemFieldsResult<TableName, Schema>>;
|
|
560
|
+
withSystemFields: () => AddSystemFieldsResult<TableName, Schema>;
|
|
450
561
|
};
|
|
451
562
|
|
|
452
563
|
declare function pick<T extends Record<string, any>, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>;
|
|
@@ -486,4 +597,4 @@ declare function safePick(schema: z.ZodObject<any>, mask: Mask): z.ZodObject<any
|
|
|
486
597
|
*/
|
|
487
598
|
declare function safeOmit(schema: z.ZodObject<any>, mask: Mask): z.ZodObject<any>;
|
|
488
599
|
|
|
489
|
-
export { type ConvexCodec, type ConvexValidatorFromZod, type ConvexValidatorFromZodFieldsAuto, type CustomBuilder, type ExtractCtx, type ExtractVisibility, type InferArgs, type InferHandlerReturns, type InferReturns, type PreserveReturnType, type Zid, type ZodToConvexArgs, type ZodValidator, convexCodec, customFnBuilder, findBaseCodec, formatZodIssues, fromConvexJS, getObjectShape, handleZodValidationError, isDateSchema, makeUnion, mapDateFieldToNumber, pick, pickShape, registerBaseCodec, registryHelpers, returnsAs, safeOmit, safePick, toConvexJS, zActionBuilder, zCustomAction, zCustomActionBuilder, zCustomMutation, zCustomMutationBuilder, zCustomQuery, zCustomQueryBuilder, zMutationBuilder, zPaginated, zQueryBuilder, zid, zodDoc, zodDocOrNull, zodTable, zodToConvex, zodToConvexFields };
|
|
600
|
+
export { type ConvexCodec, type ConvexValidatorFromZod, type ConvexValidatorFromZodFieldsAuto, type CustomBuilder, type ExtractCtx, type ExtractVisibility, type InferArgs, type InferHandlerReturns, type InferReturns, type JSONSchemaOverrideContext, type PreserveReturnType, type ToJSONSchemaOptions, type Zid, type ZodToConvexArgs, type ZodValidator, addSystemFields, composeOverrides, convexCodec, customFnBuilder, findBaseCodec, formatZodIssues, fromConvexJS, getObjectShape, getZidTableName, handleZodValidationError, isDateSchema, isZidSchema, makeUnion, mapDateFieldToNumber, pick, pickShape, registerBaseCodec, registryHelpers, returnsAs, safeOmit, safePick, toConvexJS, toJSONSchema, zActionBuilder, zCustomAction, zCustomActionBuilder, zCustomMutation, zCustomMutationBuilder, zCustomQuery, zCustomQueryBuilder, zMutationBuilder, zPaginated, zQueryBuilder, zid, zodDoc, zodDocOrNull, zodTable, zodToConvex, zodToConvexFields, zodvexJSONSchemaOverride };
|