zodvex 0.7.7-beta.0 → 0.7.7-beta.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 +55 -107
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +281 -68
- package/dist/cli/index.js.map +1 -1
- package/dist/client/index.js +5 -7
- package/dist/client/index.js.map +1 -1
- package/dist/codegen/index.js +240 -27
- package/dist/codegen/index.js.map +1 -1
- package/dist/core/index.js +58 -20
- package/dist/core/index.js.map +1 -1
- package/dist/index.js +58 -20
- package/dist/index.js.map +1 -1
- package/dist/internal/boundaryHelpers.d.ts +2 -15
- package/dist/internal/boundaryHelpers.d.ts.map +1 -1
- package/dist/internal/custom.d.ts.map +1 -1
- package/dist/internal/registry.d.ts +7 -2
- package/dist/internal/registry.d.ts.map +1 -1
- package/dist/internal/zx.d.ts.map +1 -1
- package/dist/internal/zxDateBrand.d.ts +5 -0
- package/dist/internal/zxDateBrand.d.ts.map +1 -0
- package/dist/legacy/index.js +27 -12
- package/dist/legacy/index.js.map +1 -1
- package/dist/mini/client/index.js +5 -7
- package/dist/mini/client/index.js.map +1 -1
- package/dist/mini/index.js +58 -20
- package/dist/mini/index.js.map +1 -1
- package/dist/mini/react/index.js +5 -7
- package/dist/mini/react/index.js.map +1 -1
- package/dist/mini/server/index.js +32 -19
- package/dist/mini/server/index.js.map +1 -1
- package/dist/public/cli/index.d.ts +1 -1
- package/dist/public/codegen/discover.d.ts.map +1 -1
- package/dist/public/codegen/discovery-hooks.d.ts +2 -1
- package/dist/public/codegen/discovery-hooks.d.ts.map +1 -1
- package/dist/public/codegen/extractCodec.d.ts.map +1 -1
- package/dist/public/codegen/tsconfigPaths.d.ts +41 -0
- package/dist/public/codegen/tsconfigPaths.d.ts.map +1 -0
- package/dist/public/codegen/zodToSource.d.ts.map +1 -1
- package/dist/react/index.js +5 -7
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.js +32 -19
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/index.ts +1 -1
- package/src/internal/boundaryHelpers.ts +19 -9
- package/src/internal/custom.ts +11 -2
- package/src/internal/db.ts +1 -1
- package/src/internal/mapping/types.ts +2 -2
- package/src/internal/registry.ts +50 -3
- package/src/internal/types.ts +2 -2
- package/src/internal/zx.ts +12 -9
- package/src/internal/zxDateBrand.ts +34 -0
- package/src/public/cli/index.ts +1 -1
- package/src/public/codegen/discover.ts +31 -5
- package/src/public/codegen/discovery-hooks.ts +73 -8
- package/src/public/codegen/extractCodec.ts +5 -11
- package/src/public/codegen/tsconfigPaths.ts +224 -0
- package/src/public/codegen/zodToSource.ts +5 -6
package/README.md
CHANGED
|
@@ -2,43 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
#### [Zod](https://zod.dev/) + [Convex](https://www.convex.dev/)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- [Why zodvex?](#why-zodvex)
|
|
12
|
-
- [Installation](#installation)
|
|
13
|
-
- [Quick Start](#quick-start)
|
|
14
|
-
- [Import Paths](#import-paths)
|
|
15
|
-
- [Features](#features)
|
|
16
|
-
- [Codec-Aware Database](#codec-aware-database)
|
|
17
|
-
- [Codegen & Client-Side Schema Sharing](#codegen--client-side-schema-sharing)
|
|
18
|
-
- [Using zodvex Without Codecs](#using-zodvex-without-codecs)
|
|
19
|
-
- [Supported Types](#supported-types)
|
|
20
|
-
- [Upgrading?](#upgrading)
|
|
21
|
-
- [API Reference](#api-reference)
|
|
22
|
-
- [Roadmap](#roadmap)
|
|
23
|
-
- [License](#license)
|
|
5
|
+
Use Zod v4 as your schema language for Convex — define your data once and use it end to end, with automatic validation and codecs at every boundary.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/zodvex)
|
|
8
|
+
[](https://github.com/panzacoder/zodvex/actions/workflows/ci.yml)
|
|
9
|
+
[](./LICENSE)
|
|
24
10
|
|
|
25
11
|
## Why zodvex?
|
|
26
12
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- **
|
|
30
|
-
|
|
13
|
+
**Your Zod schemas are the source of truth** — tables, function arguments, and return types defined once, used database to frontend. Two things make that real:
|
|
14
|
+
|
|
15
|
+
- **Functions run full Zod pipelines.** Your argument and return schemas execute as real Zod at runtime — refinements like `.min()` and `.email()`, transformations, codecs — not erased down to structural checks.
|
|
16
|
+
|
|
17
|
+
- **The database is Zod-validated, automatically.** `ctx.db` parses every read and encodes every write through your schemas: `.email()` holds at the row level where Convex's structural checks stop, and codecs live in the schema itself — handlers see `Date` objects and branded IDs while Convex stores plain values.
|
|
31
18
|
|
|
32
|
-
|
|
33
|
-
|---------|--------|---------------------|
|
|
34
|
-
| Codec-aware DB | `initZodvex` wraps `ctx.db` automatically | Manual |
|
|
35
|
-
| Date handling | `zx.date()` — automatic Date ↔ timestamp | Manual `z.codec()` |
|
|
36
|
-
| Typed IDs | `zx.id('table')` with type branding | Manual |
|
|
37
|
-
| Custom codecs | `zx.codec()` with auto-detection | Not provided |
|
|
38
|
-
| Client-safe models | `defineZodModel` (importable in React) | Not provided |
|
|
39
|
-
| Codegen | Optional typed hooks, boundary helpers | Not provided |
|
|
19
|
+
What you gain over Convex out of the box:
|
|
40
20
|
|
|
41
|
-
|
|
21
|
+
| | Convex | with zodvex |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| Type safety | end-to-end inference | same — driven by your Zod schemas |
|
|
24
|
+
| Runtime validation | structural checks | full Zod — refinements, transforms, codecs |
|
|
25
|
+
| End-to-end validation | per-function validators | one Zod schema — client, functions, and db access |
|
|
26
|
+
| Client calls | `useQuery(api.fn)` infers types | `useZodQuery(api.fn)` infers the runtime schema too — args encoded, results decoded (via codegen) |
|
|
27
|
+
| Dates & custom types | `number` timestamps | `Date` objects and custom codecs (`zx.date()`, `zx.codec()`) |
|
|
28
|
+
| Rows on read | as stored | parsed & decoded through your schema |
|
|
29
|
+
| Row-level rules & audit | build your own | `.withRules()` / `.audit()` on `ctx.db` |
|
|
30
|
+
|
|
31
|
+
All of it wired once with `initZodvex` — see [Features](#features).
|
|
42
32
|
|
|
43
33
|
## Installation
|
|
44
34
|
|
|
@@ -72,7 +62,9 @@ export const EventModel = defineZodModel('events', {
|
|
|
72
62
|
|
|
73
63
|
> `defineZodModel` is client-safe — you can import it in React.
|
|
74
64
|
|
|
75
|
-
### Step 2.
|
|
65
|
+
### Step 2. Wire it up
|
|
66
|
+
|
|
67
|
+
Two one-time files: build your Convex schema from your models, and create your function builders.
|
|
76
68
|
|
|
77
69
|
```ts
|
|
78
70
|
// convex/schema.ts
|
|
@@ -84,8 +76,6 @@ export default defineZodSchema({
|
|
|
84
76
|
})
|
|
85
77
|
```
|
|
86
78
|
|
|
87
|
-
### Step 3. Set up builders
|
|
88
|
-
|
|
89
79
|
```ts
|
|
90
80
|
// convex/functions.ts
|
|
91
81
|
import { initZodvex } from 'zodvex/server'
|
|
@@ -101,9 +91,9 @@ export const { zq, zm, za, ziq, zim, zia } = initZodvex(schema, {
|
|
|
101
91
|
})
|
|
102
92
|
```
|
|
103
93
|
|
|
104
|
-
`initZodvex` returns builders for all six Convex function types
|
|
94
|
+
`initZodvex` returns builders for all six Convex function types, with `ctx.db` wrapped for automatic codec encode/decode. You write these two files once and rarely touch them again.
|
|
105
95
|
|
|
106
|
-
### Step
|
|
96
|
+
### Step 3. Write functions
|
|
107
97
|
|
|
108
98
|
```ts
|
|
109
99
|
// convex/events.ts
|
|
@@ -114,7 +104,7 @@ import { EventModel } from './models'
|
|
|
114
104
|
|
|
115
105
|
export const list = zq({
|
|
116
106
|
args: {},
|
|
117
|
-
returns:
|
|
107
|
+
returns: zx.docArray(EventModel),
|
|
118
108
|
handler: async (ctx) => {
|
|
119
109
|
// Dates come back as Date objects, not numbers
|
|
120
110
|
return await ctx.db.query('events').collect()
|
|
@@ -136,39 +126,52 @@ export const create = zm({
|
|
|
136
126
|
})
|
|
137
127
|
```
|
|
138
128
|
|
|
139
|
-
> `zx.id('events')` is a typed
|
|
129
|
+
> `zx.id('events')` is a typed ID validator — branding only, no wire transform. `zx.date()` and `zx.codec()` are codecs. Details in [Features](#features).
|
|
140
130
|
|
|
141
131
|
See the full [quickstart example](./examples/quickstart/) for a runnable project.
|
|
142
132
|
|
|
143
133
|
## Import Paths
|
|
144
134
|
|
|
145
|
-
Four entry points:
|
|
135
|
+
Four primary entry points:
|
|
146
136
|
|
|
147
137
|
- **`zodvex`** — Client-safe full-Zod surface. Use in React components and shared code.
|
|
148
138
|
- **`zodvex/server`** — Server-only. Use in Convex functions and schema definitions.
|
|
149
139
|
- **`zodvex/mini`** — Client-safe zod/mini surface.
|
|
150
140
|
- **`zodvex/mini/server`** — Server-only zod/mini surface.
|
|
151
|
-
- **`zodvex/legacy`** — Deprecated runtime APIs kept only for migration.
|
|
152
141
|
|
|
153
|
-
|
|
142
|
+
Focused entrypoints — `zodvex/react`, `zodvex/client`, `zodvex/codegen` (and their `zodvex/mini` variants) — back the codegen workflow and are mostly consumed by generated code; see [Codegen](#codegen--client-side-schema-sharing).
|
|
143
|
+
|
|
144
|
+
Two deprecated paths remain for migration only:
|
|
145
|
+
|
|
146
|
+
- **`zodvex/legacy`** — Deprecated runtime APIs kept only for migration.
|
|
147
|
+
- **`zodvex/core`** — Deprecated compatibility alias for `zodvex`.
|
|
154
148
|
|
|
155
149
|
## Features
|
|
156
150
|
|
|
157
151
|
### Codec-Aware Database
|
|
158
152
|
|
|
159
|
-
`initZodvex` wraps `ctx.db` so reads decode automatically and writes encode automatically.
|
|
153
|
+
`initZodvex` wraps `ctx.db` so reads decode automatically and writes encode automatically. Codecs are opt-in per field — schemas without them get the same validation, typed IDs, and correct optional/nullable mapping through the exact same setup.
|
|
160
154
|
|
|
161
155
|
- **`zx.date()`** — Date ↔ timestamp codec. Stored as `v.float64()`, used as `Date` in handlers.
|
|
162
156
|
- **`zx.codec(wire, runtime, transforms)`** — Custom codecs for complex transformations (encryption, serialization, etc.).
|
|
163
|
-
- **`zx.id('table')`** — Typed Convex ID validator with `GenericId<T>` branding
|
|
157
|
+
- **`zx.id('table')`** — Typed Convex ID validator with `GenericId<T>` branding — no wire transform (not a codec).
|
|
164
158
|
|
|
165
159
|
Guides: [Custom Codecs](./docs/guide/custom-codecs.md), [Date Handling](./docs/guide/date-handling.md)
|
|
166
160
|
|
|
161
|
+
### Row-Level Rules & Audit
|
|
162
|
+
|
|
163
|
+
The same wrapped `ctx.db` carries per-row security and observability — both operating on decoded documents (`Date` objects, typed IDs), never wire values:
|
|
164
|
+
|
|
165
|
+
- **`.withRules(ruleCtx, rules)`** — gate and transform reads and writes per table (`read`, `insert`, `patch`, `replace`, `delete`), with an optional deny-by-default policy.
|
|
166
|
+
- **`.audit({ afterRead, afterWrite })`** — observe successful reads and writes; composes with `.withRules()`, so audit sees only what the rules allowed.
|
|
167
|
+
|
|
168
|
+
Guide: [Rules & Audit](./docs/guide/rules-and-audit.md)
|
|
169
|
+
|
|
167
170
|
### Codegen & Client-Side Schema Sharing
|
|
168
171
|
|
|
169
172
|
zodvex includes an optional CLI that generates typed client code:
|
|
170
173
|
|
|
171
|
-
- **Typed hooks** — `useZodQuery`, `useZodMutation`
|
|
174
|
+
- **Typed hooks** — `useZodQuery`, `useZodMutation`, generated into `convex/_zodvex/client` — import them from there; args are encoded and results decoded automatically
|
|
172
175
|
- **Boundary helpers** — `encodeArgs`, `decodeResult` for custom client integrations
|
|
173
176
|
- **Cross-function auto-codec** — `ctx.runQuery` / `ctx.runMutation` encode args + decode results, and `ctx.scheduler.runAfter` / `ctx.scheduler.runAt` encode args, via the registry. Pass natural decoded values; zodvex encodes them to wire at the call site.
|
|
174
177
|
|
|
@@ -183,20 +186,6 @@ zodvex dev # watch mode
|
|
|
183
186
|
|
|
184
187
|
Guides: [Codegen](./docs/guide/codegen.md) | Example: [examples/task-manager/](./examples/task-manager/)
|
|
185
188
|
|
|
186
|
-
### Using zodvex Without Codecs
|
|
187
|
-
|
|
188
|
-
`zodTable` and `zQueryBuilder` still work without `initZodvex`:
|
|
189
|
-
|
|
190
|
-
```ts
|
|
191
|
-
import { zodTable, zQueryBuilder } from 'zodvex/legacy'
|
|
192
|
-
import { query } from './_generated/server'
|
|
193
|
-
|
|
194
|
-
const Users = zodTable('users', { name: z.string() })
|
|
195
|
-
const zq = zQueryBuilder(query)
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
At this level, zodvex is roughly equivalent to convex-helpers. This is a valid stepping-stone, but the API is deprecated. When you're ready for codecs, see the [Quick Start](#quick-start) above.
|
|
199
|
-
|
|
200
189
|
## Supported Types
|
|
201
190
|
|
|
202
191
|
| Zod Type | Convex Validator |
|
|
@@ -217,52 +206,13 @@ At this level, zodvex is roughly equivalent to convex-helpers. This is a valid s
|
|
|
217
206
|
|
|
218
207
|
> **Note:** Native `z.date()` is **not supported** — use `zx.date()` instead. See [Date Handling](./docs/guide/date-handling.md) for details.
|
|
219
208
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
¹ Enum types in Zod v4 produce a slightly different TypeScript signature than manually created unions:
|
|
223
|
-
|
|
224
|
-
```typescript
|
|
225
|
-
// Manual union (precise tuple type)
|
|
226
|
-
const manual = v.union(v.literal('a'), v.literal('b'))
|
|
227
|
-
// Type: VUnion<"a" | "b", [VLiteral<"a", "required">, VLiteral<"b", "required">], "required", never>
|
|
228
|
-
|
|
229
|
-
// From Zod enum (array type)
|
|
230
|
-
const fromZod = zodToConvex(z.enum(['a', 'b']))
|
|
231
|
-
// Type: VUnion<"a" | "b", Array<VLiteral<"a" | "b", "required">>, "required", never>
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
**This difference is purely cosmetic with no functional impact:**
|
|
235
|
-
|
|
236
|
-
- Value types are identical (`"a" | "b"`)
|
|
237
|
-
- Runtime validation is identical
|
|
238
|
-
- Type safety for function arguments/returns is preserved
|
|
239
|
-
- Convex uses `T[number]` which works identically for both array and tuple types
|
|
209
|
+
¹ Enum unions carry a cosmetically different TypeScript signature than hand-written `v.union(v.literal(...))` calls — identical values, runtime validation, and type safety. Details: [Mapping Helpers](./docs/guide/mapping-helpers.md#zod-v4-enum-type-note).
|
|
240
210
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
**zx namespace types:**
|
|
244
|
-
|
|
245
|
-
```ts
|
|
246
|
-
import { zx } from 'zodvex'
|
|
247
|
-
|
|
248
|
-
// Convex IDs — typed validator, NOT a codec
|
|
249
|
-
zx.id('tableName') // → v.id('tableName')
|
|
250
|
-
zx.id('tableName').optional() // → v.optional(v.id('tableName'))
|
|
251
|
-
|
|
252
|
-
// Dates — codec (Date ↔ timestamp)
|
|
253
|
-
zx.date() // → v.float64() (timestamp)
|
|
254
|
-
zx.date().optional() // → v.optional(v.float64())
|
|
255
|
-
zx.date().nullable() // → v.union(v.float64(), v.null())
|
|
256
|
-
|
|
257
|
-
// Custom codecs
|
|
258
|
-
zx.codec(wireSchema, runtimeSchema, { encode, decode })
|
|
259
|
-
```
|
|
211
|
+
For zodvex's own types — `zx.id()`, `zx.date()`, `zx.codec()` — and exactly how they map to Convex validators, see [The zx Namespace](./docs/guide/zx-namespace.md).
|
|
260
212
|
|
|
261
213
|
## Upgrading?
|
|
262
214
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
Automated renames are available:
|
|
215
|
+
Read the [migration guide](./MIGRATION.md) for what changed in each release and why. Automated renames are available:
|
|
266
216
|
|
|
267
217
|
```bash
|
|
268
218
|
npx zodvex migrate ./convex # apply renames
|
|
@@ -273,7 +223,8 @@ npx zodvex migrate ./convex --dry-run # preview changes
|
|
|
273
223
|
|
|
274
224
|
- [The zx Namespace](./docs/guide/zx-namespace.md) — `zx.id()`, `zx.date()`, `zx.codec()`
|
|
275
225
|
- [Builders](./docs/guide/builders.md) — `initZodvex` and legacy builders
|
|
276
|
-
- [Custom Context](./docs/guide/custom-context.md) — `.withContext()`, `onSuccess`
|
|
226
|
+
- [Custom Context](./docs/guide/custom-context.md) — `.withContext()`, `defineContext`, `onSuccess`
|
|
227
|
+
- [Rules & Audit](./docs/guide/rules-and-audit.md) — `.withRules()`, `.audit()` on `ctx.db`
|
|
277
228
|
- [Custom Codecs](./docs/guide/custom-codecs.md) — `zx.codec()`, `decodeDoc`/`encodeDoc`
|
|
278
229
|
- [Date Handling](./docs/guide/date-handling.md) — `zx.date()` deep dive
|
|
279
230
|
- [Form Validation](./docs/guide/form-validation.md) — react-hook-form integration
|
|
@@ -288,10 +239,7 @@ npx zodvex migrate ./convex --dry-run # preview changes
|
|
|
288
239
|
|
|
289
240
|
## Roadmap
|
|
290
241
|
|
|
291
|
-
|
|
292
|
-
- Migration tooling: pre-0.5 → current zodvex
|
|
293
|
-
- Additional example projects (e.g., full-stack with React, codegen showcase)
|
|
294
|
-
- Per-feature READMEs in examples/task-manager/
|
|
242
|
+
See the [roadmap](./docs/roadmap.md) for where zodvex is heading — deploy-scale performance, ecosystem interop, and the model/namespace evolution.
|
|
295
243
|
|
|
296
244
|
## License
|
|
297
245
|
|
|
@@ -299,4 +247,4 @@ MIT
|
|
|
299
247
|
|
|
300
248
|
---
|
|
301
249
|
|
|
302
|
-
Built with ❤️
|
|
250
|
+
Built with ❤️ for the [Convex](https://www.convex.dev/) ecosystem. Thanks to [convex-helpers](https://github.com/get-convex/convex-helpers) for the early foundations.
|
package/dist/cli/index.d.ts
CHANGED