fluent-convex 0.12.2 → 0.13.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 +114 -253
- package/dist/ConvexBuilderWithFunctionKind.d.ts +1 -1
- package/dist/ConvexBuilderWithFunctionKind.d.ts.map +1 -1
- package/dist/ConvexBuilderWithFunctionKind.js.map +1 -1
- package/package.json +2 -1
- package/src/ConvexBuilderWithFunctionKind.ts +13 -3
- package/src/builder-core.test-d.ts +17 -0
package/README.md
CHANGED
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
# Fluent Convex
|
|
4
4
|
|
|
5
|
-
A fluent
|
|
5
|
+
A fluent builder for Convex functions with composable middleware, reusable chains, and plugin support. Inspired by [oRPC](https://orpc.unnoq.com/).
|
|
6
6
|
|
|
7
|
-
**[Live Docs & Interactive Showcase](https://friendly-zebra-716.convex.site)**
|
|
7
|
+
**[Live Docs & Interactive Showcase](https://friendly-zebra-716.convex.site)** — every feature with live demos and real source code.
|
|
8
|
+
|
|
9
|
+
[](https://youtu.be/oFqWtLBSgk8)
|
|
8
10
|
|
|
9
11
|
## Features
|
|
10
12
|
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **Plugin system**
|
|
16
|
-
- **Extensible** - Build your own plugins with the `_clone()` factory pattern ([docs](https://friendly-zebra-716.convex.site/custom-plugins))
|
|
17
|
-
- **Works with Convex** - Built on top of Convex's function system
|
|
13
|
+
- **Composable middleware** — authentication, logging, error handling with onion-style composition ([docs](https://friendly-zebra-716.convex.site/middleware))
|
|
14
|
+
- **Reusable chains** — define logic once, call it directly from other handlers (no extra function invocation), register it multiple ways ([docs](https://friendly-zebra-716.convex.site/reusable-chains))
|
|
15
|
+
- **Fluent API** — clean chainable syntax for queries, mutations, and actions ([docs](https://friendly-zebra-716.convex.site/basics))
|
|
16
|
+
- **Full type inference** — middleware context flows through the entire chain
|
|
17
|
+
- **Plugin system** — extend with plugins like `fluent-convex/zod` for Zod schema validation ([docs](https://friendly-zebra-716.convex.site/zod-plugin))
|
|
18
18
|
|
|
19
19
|
## Installation
|
|
20
20
|
|
|
@@ -26,8 +26,6 @@ npm install fluent-convex
|
|
|
26
26
|
|
|
27
27
|
> For a complete walkthrough with live demos, see the **[Getting Started guide](https://friendly-zebra-716.convex.site/)**.
|
|
28
28
|
|
|
29
|
-
**Important:** All functions must end with `.public()` or `.internal()` to be registered with Convex.
|
|
30
|
-
|
|
31
29
|
```ts
|
|
32
30
|
import { createBuilder } from "fluent-convex";
|
|
33
31
|
import { v } from "convex/values";
|
|
@@ -35,85 +33,83 @@ import type { DataModel } from "./_generated/dataModel";
|
|
|
35
33
|
|
|
36
34
|
const convex = createBuilder<DataModel>();
|
|
37
35
|
|
|
38
|
-
// Simple query
|
|
39
36
|
export const listNumbers = convex
|
|
40
37
|
.query()
|
|
41
38
|
.input({ count: v.number() })
|
|
42
|
-
.handler(async (
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
.order("desc")
|
|
46
|
-
.take(input.count);
|
|
47
|
-
|
|
48
|
-
return { numbers: numbers.map((n) => n.value) };
|
|
39
|
+
.handler(async (ctx, args) => {
|
|
40
|
+
const rows = await ctx.db.query("numbers").order("desc").take(args.count);
|
|
41
|
+
return rows.map((r) => r.value);
|
|
49
42
|
})
|
|
50
|
-
.public();
|
|
43
|
+
.public();
|
|
44
|
+
```
|
|
51
45
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
46
|
+
Everything starts with `createBuilder<DataModel>()`. From there, chain `.query()` / `.mutation()` / `.action()`, add `.input()` and `.handler()`, and finalize with `.public()` or `.internal()` to register the function with Convex.
|
|
47
|
+
|
|
48
|
+
## Middleware
|
|
49
|
+
|
|
50
|
+
> See the **[Middleware docs](https://friendly-zebra-716.convex.site/middleware)** for detailed examples.
|
|
58
51
|
|
|
52
|
+
Middleware wraps your handlers with reusable logic. It uses an onion model: `next()` executes the rest of the chain including the handler, so middleware can run code before and after.
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
const authMiddleware = convex.query().createMiddleware(async (ctx, next) => {
|
|
56
|
+
const identity = await ctx.auth.getUserIdentity();
|
|
57
|
+
if (!identity) throw new Error("Unauthorized");
|
|
59
58
|
return next({
|
|
60
|
-
...
|
|
61
|
-
user: {
|
|
62
|
-
id: identity.subject,
|
|
63
|
-
name: identity.name ?? "Unknown",
|
|
64
|
-
},
|
|
59
|
+
...ctx,
|
|
60
|
+
user: { id: identity.subject, name: identity.name ?? "Unknown" },
|
|
65
61
|
});
|
|
66
62
|
});
|
|
67
63
|
|
|
68
|
-
export const
|
|
64
|
+
export const listNumbersProtected = convex
|
|
69
65
|
.query()
|
|
70
66
|
.use(authMiddleware)
|
|
71
67
|
.input({ count: v.number() })
|
|
72
|
-
.handler(async (
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
.order("desc")
|
|
76
|
-
.take(input.count);
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
viewer: context.user.name, // user is available from middleware!
|
|
80
|
-
numbers: numbers.map((n) => n.value),
|
|
81
|
-
};
|
|
68
|
+
.handler(async (ctx, args) => {
|
|
69
|
+
const rows = await ctx.db.query("numbers").order("desc").take(args.count);
|
|
70
|
+
return { viewer: ctx.user.name, numbers: rows.map((r) => r.value) };
|
|
82
71
|
})
|
|
83
72
|
.public();
|
|
84
73
|
```
|
|
85
74
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
> See the **[Validation docs](https://friendly-zebra-716.convex.site/validation)** for a side-by-side comparison of all three approaches with live demos.
|
|
75
|
+
### Cross-function-type middleware
|
|
89
76
|
|
|
90
|
-
|
|
77
|
+
Because `authMiddleware` above was created with `.query().createMiddleware()`, its input context is `QueryCtx` — so it can't be used on mutations or actions (`ActionCtx` lacks `db`, causing a type error). For middleware that only needs properties shared across all function types (like `auth`), use `$context` to declare exactly what the middleware requires:
|
|
91
78
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
79
|
+
```ts
|
|
80
|
+
import type { Auth } from "convex/server";
|
|
81
|
+
|
|
82
|
+
// Works with queries, mutations, AND actions
|
|
83
|
+
const authMiddleware = convex
|
|
84
|
+
.$context<{ auth: Auth }>()
|
|
85
|
+
.createMiddleware(async (ctx, next) => {
|
|
86
|
+
const identity = await ctx.auth.getUserIdentity();
|
|
87
|
+
if (!identity) throw new Error("Unauthorized");
|
|
88
|
+
return next({
|
|
89
|
+
...ctx,
|
|
90
|
+
user: { id: identity.subject, name: identity.name ?? "Unknown" },
|
|
91
|
+
});
|
|
92
|
+
});
|
|
99
93
|
|
|
100
|
-
|
|
94
|
+
const authQuery = convex.query().use(authMiddleware);
|
|
95
|
+
const authMutation = convex.mutation().use(authMiddleware);
|
|
96
|
+
const authAction = convex.action().use(authMiddleware);
|
|
97
|
+
```
|
|
101
98
|
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
| Pattern | Input context | Use when |
|
|
100
|
+
| -------------------------------------------------------- | ------------------------ | ------------------------------------------------ |
|
|
101
|
+
| `convex.query().createMiddleware(fn)` | `QueryCtx` (has `db`) | Middleware that reads the database |
|
|
102
|
+
| `convex.createMiddleware(fn)` | `EmptyObject` | Middleware that needs no context at all |
|
|
103
|
+
| `convex.$context<{ auth: Auth }>().createMiddleware(fn)` | Exactly `{ auth: Auth }` | Middleware that needs specific shared properties |
|
|
104
104
|
|
|
105
105
|
## Reusable Chains & Callables
|
|
106
106
|
|
|
107
107
|
> See the **[Reusable Chains docs](https://friendly-zebra-716.convex.site/reusable-chains)** for full examples with live demos.
|
|
108
108
|
|
|
109
|
-
Because the builder is immutable, you can stop the chain at any point and reuse
|
|
110
|
-
|
|
111
|
-
1. **Call directly** from inside other handlers (no additional Convex function invocation)
|
|
112
|
-
2. **Register** as a standalone Convex endpoint
|
|
113
|
-
3. **Extend** with more middleware and register multiple ways
|
|
109
|
+
Because the builder is immutable, you can stop the chain at any point and reuse it. A builder with a `.handler()` but no `.public()` / `.internal()` is a **callable** — a fully-typed function you can invoke directly from other handlers without an extra Convex function call:
|
|
114
110
|
|
|
115
111
|
```ts
|
|
116
|
-
//
|
|
112
|
+
// Define a callable — not yet registered with Convex
|
|
117
113
|
const getNumbers = convex
|
|
118
114
|
.query()
|
|
119
115
|
.input({ count: v.number() })
|
|
@@ -122,29 +118,35 @@ const getNumbers = convex
|
|
|
122
118
|
return rows.map((r) => r.value);
|
|
123
119
|
});
|
|
124
120
|
|
|
125
|
-
//
|
|
121
|
+
// Register it as a public query
|
|
126
122
|
export const listNumbers = getNumbers.public();
|
|
127
123
|
|
|
128
|
-
//
|
|
124
|
+
// Call it directly from another handler — no extra function invocation
|
|
129
125
|
export const getNumbersWithTimestamp = convex
|
|
130
126
|
.query()
|
|
131
127
|
.input({ count: v.number() })
|
|
132
128
|
.handler(async (ctx, args) => {
|
|
133
|
-
const numbers = await getNumbers(ctx, args);
|
|
129
|
+
const numbers = await getNumbers(ctx, args);
|
|
134
130
|
return { numbers, fetchedAt: Date.now() };
|
|
135
131
|
})
|
|
136
132
|
.public();
|
|
137
133
|
|
|
138
|
-
//
|
|
134
|
+
// Register the same callable with different middleware
|
|
139
135
|
export const listNumbersProtected = getNumbers.use(authMiddleware).public();
|
|
140
136
|
export const listNumbersLogged = getNumbers.use(withLogging("logged")).public();
|
|
141
137
|
```
|
|
142
138
|
|
|
143
|
-
|
|
139
|
+
## Validation
|
|
140
|
+
|
|
141
|
+
> See the **[Validation docs](https://friendly-zebra-716.convex.site/validation)** for a side-by-side comparison with live demos.
|
|
144
142
|
|
|
145
|
-
|
|
143
|
+
`.input()` supports three flavors of validation:
|
|
146
144
|
|
|
147
|
-
|
|
145
|
+
1. **Property validators** — `{ count: v.number() }` (simplest)
|
|
146
|
+
2. **Object validators** — `v.object({ count: v.number() })` (with `.returns()` support)
|
|
147
|
+
3. **Zod schemas** — `z.object({ count: z.number().min(1) })` (via the Zod plugin)
|
|
148
|
+
|
|
149
|
+
## Zod Plugin (`fluent-convex/zod`)
|
|
148
150
|
|
|
149
151
|
> See the **[Zod Plugin docs](https://friendly-zebra-716.convex.site/zod-plugin)** for live demos including refinement validation.
|
|
150
152
|
|
|
@@ -154,76 +156,46 @@ The Zod plugin adds Zod schema support for `.input()` and `.returns()`, with **f
|
|
|
154
156
|
npm install zod convex-helpers
|
|
155
157
|
```
|
|
156
158
|
|
|
157
|
-
>
|
|
158
|
-
|
|
159
|
-
Usage:
|
|
159
|
+
> `zod` and `convex-helpers` are optional peer dependencies — only needed if you use this plugin.
|
|
160
160
|
|
|
161
161
|
```ts
|
|
162
|
-
import { createBuilder } from "fluent-convex";
|
|
163
162
|
import { WithZod } from "fluent-convex/zod";
|
|
164
163
|
import { z } from "zod";
|
|
165
|
-
import type { DataModel } from "./_generated/dataModel";
|
|
166
|
-
|
|
167
|
-
const convex = createBuilder<DataModel>();
|
|
168
164
|
|
|
169
165
|
export const listNumbers = convex
|
|
170
166
|
.query()
|
|
171
|
-
.extend(WithZod)
|
|
167
|
+
.extend(WithZod)
|
|
172
168
|
.input(
|
|
173
169
|
z.object({
|
|
174
|
-
count: z.number().int().min(1).max(100),
|
|
175
|
-
})
|
|
170
|
+
count: z.number().int().min(1).max(100),
|
|
171
|
+
}),
|
|
176
172
|
)
|
|
177
173
|
.returns(z.object({ numbers: z.array(z.number()) }))
|
|
178
|
-
.handler(async (
|
|
179
|
-
const numbers = await
|
|
174
|
+
.handler(async (ctx, args) => {
|
|
175
|
+
const numbers = await ctx.db.query("numbers").take(args.count);
|
|
180
176
|
return { numbers: numbers.map((n) => n.value) };
|
|
181
177
|
})
|
|
182
178
|
.public();
|
|
183
179
|
```
|
|
184
180
|
|
|
185
|
-
|
|
186
|
-
- **
|
|
187
|
-
- **
|
|
188
|
-
- **
|
|
189
|
-
- **Plain validators still work** - You can mix Zod and Convex validators in the same builder chain.
|
|
181
|
+
- **Full runtime validation** — Zod refinements are enforced server-side, before and after the handler
|
|
182
|
+
- **Structural conversion** — Zod schemas are automatically converted to Convex validators
|
|
183
|
+
- **Composable** — `.extend(WithZod)` preserves through `.use()`, `.input()`, and `.returns()` chains
|
|
184
|
+
- **Plain validators still work** — mix Zod and Convex validators in the same builder chain
|
|
190
185
|
|
|
191
|
-
##
|
|
186
|
+
## Custom Plugins
|
|
192
187
|
|
|
193
188
|
> See the **[Custom Plugins docs](https://friendly-zebra-716.convex.site/custom-plugins)** for a complete worked example with live demo.
|
|
194
189
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
### Writing a Plugin
|
|
198
|
-
|
|
199
|
-
The `_clone()` method is called internally by `.use()`, `.input()`, and `.returns()` to create new builder instances. By overriding it, your plugin's type is preserved through the entire builder chain.
|
|
190
|
+
Extend the builder by subclassing `ConvexBuilderWithFunctionKind` and overriding `_clone()`. This preserves your plugin's type through the entire builder chain:
|
|
200
191
|
|
|
201
192
|
```ts
|
|
202
193
|
import {
|
|
203
194
|
ConvexBuilderWithFunctionKind,
|
|
204
|
-
type GenericDataModel,
|
|
205
|
-
type FunctionType,
|
|
206
|
-
type Context,
|
|
207
|
-
type EmptyObject,
|
|
208
|
-
type ConvexArgsValidator,
|
|
209
|
-
type ConvexReturnsValidator,
|
|
210
195
|
type ConvexBuilderDef,
|
|
211
196
|
} from "fluent-convex";
|
|
212
197
|
|
|
213
|
-
class MyPlugin
|
|
214
|
-
TDataModel extends GenericDataModel = GenericDataModel,
|
|
215
|
-
TFunctionType extends FunctionType = FunctionType,
|
|
216
|
-
TCurrentContext extends Context = EmptyObject,
|
|
217
|
-
TArgsValidator extends ConvexArgsValidator | undefined = undefined,
|
|
218
|
-
TReturnsValidator extends ConvexReturnsValidator | undefined = undefined,
|
|
219
|
-
> extends ConvexBuilderWithFunctionKind<
|
|
220
|
-
TDataModel,
|
|
221
|
-
TFunctionType,
|
|
222
|
-
TCurrentContext,
|
|
223
|
-
TArgsValidator,
|
|
224
|
-
TReturnsValidator
|
|
225
|
-
> {
|
|
226
|
-
// Accept both builder instances (from .extend()) and raw defs (from _clone())
|
|
198
|
+
class MyPlugin extends ConvexBuilderWithFunctionKind {
|
|
227
199
|
constructor(builderOrDef: any) {
|
|
228
200
|
const def =
|
|
229
201
|
builderOrDef instanceof ConvexBuilderWithFunctionKind
|
|
@@ -232,12 +204,10 @@ class MyPlugin<
|
|
|
232
204
|
super(def);
|
|
233
205
|
}
|
|
234
206
|
|
|
235
|
-
// Override _clone() to preserve MyPlugin through the chain
|
|
236
207
|
protected _clone(def: ConvexBuilderDef<any, any, any>): any {
|
|
237
208
|
return new MyPlugin(def);
|
|
238
209
|
}
|
|
239
210
|
|
|
240
|
-
// Add custom methods
|
|
241
211
|
myCustomMethod(param: string) {
|
|
242
212
|
console.log("Custom method called with:", param);
|
|
243
213
|
return this;
|
|
@@ -245,175 +215,66 @@ class MyPlugin<
|
|
|
245
215
|
}
|
|
246
216
|
```
|
|
247
217
|
|
|
248
|
-
Usage
|
|
218
|
+
Usage — plugins compose with `.extend()`:
|
|
249
219
|
|
|
250
220
|
```ts
|
|
251
221
|
export const myQuery = convex
|
|
252
222
|
.query()
|
|
253
223
|
.extend(MyPlugin)
|
|
254
|
-
.
|
|
255
|
-
.use(authMiddleware) // .use() preserves MyPlugin type
|
|
256
|
-
.input({ count: v.number() })
|
|
257
|
-
.handler(async (ctx, input) => { ... })
|
|
258
|
-
.public();
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
### Composing Multiple Plugins
|
|
262
|
-
|
|
263
|
-
Plugins can be composed with `.extend()`:
|
|
264
|
-
|
|
265
|
-
```ts
|
|
266
|
-
export const myQuery = convex
|
|
267
|
-
.query()
|
|
268
|
-
.extend(MyPlugin)
|
|
269
|
-
.extend(WithZod) // WithZod overrides .input()/.returns() from MyPlugin
|
|
224
|
+
.extend(WithZod)
|
|
270
225
|
.myCustomMethod("hello")
|
|
271
226
|
.input(z.object({ count: z.number() }))
|
|
272
|
-
.handler(async (ctx,
|
|
273
|
-
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
## Flexible Method Ordering
|
|
277
|
-
|
|
278
|
-
The builder API is flexible about method ordering, allowing you to structure your code in the way that makes the most sense for your use case.
|
|
279
|
-
|
|
280
|
-
### Middleware After Handler
|
|
281
|
-
|
|
282
|
-
You can add middleware **after** defining the handler, which is useful when you want to wrap existing handlers with additional functionality:
|
|
283
|
-
|
|
284
|
-
```ts
|
|
285
|
-
export const getNumbers = convex
|
|
286
|
-
.query()
|
|
287
|
-
.input({ count: v.number() })
|
|
288
|
-
.handler(async (context, input) => {
|
|
289
|
-
return await context.db.query("numbers").take(input.count);
|
|
290
|
-
})
|
|
291
|
-
.use(authMiddleware) // Middleware added after handler
|
|
292
|
-
.public();
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
### Callable Builders
|
|
296
|
-
|
|
297
|
-
Before registering a function with `.public()` or `.internal()`, the builder is **callable** -- you can invoke it directly from other handlers (see [Reusable Chains](#reusable-chains--callables) above) or use it in tests:
|
|
298
|
-
|
|
299
|
-
```ts
|
|
300
|
-
// A callable (not yet registered)
|
|
301
|
-
const getDouble = convex
|
|
302
|
-
.query()
|
|
303
|
-
.input({ count: v.number() })
|
|
304
|
-
.handler(async (context, input) => {
|
|
305
|
-
return { doubled: input.count * 2 };
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
// Call it from another handler
|
|
309
|
-
export const tripled = convex
|
|
310
|
-
.query()
|
|
311
|
-
.input({ count: v.number() })
|
|
312
|
-
.handler(async (ctx, input) => {
|
|
313
|
-
const { doubled } = await getDouble(ctx, input);
|
|
314
|
-
return { tripled: doubled + input.count };
|
|
227
|
+
.handler(async (ctx, args) => {
|
|
228
|
+
/* ... */
|
|
315
229
|
})
|
|
316
230
|
.public();
|
|
317
|
-
|
|
318
|
-
// Or call it directly in tests
|
|
319
|
-
const mockContext = {} as any;
|
|
320
|
-
const result = await getDouble(mockContext, { count: 5 });
|
|
321
|
-
console.log(result); // { doubled: 10 }
|
|
322
|
-
|
|
323
|
-
// Register it when you also need it as a standalone endpoint
|
|
324
|
-
export const doubleNumber = getDouble.public();
|
|
325
231
|
```
|
|
326
232
|
|
|
327
|
-
|
|
233
|
+
## API Reference
|
|
328
234
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
235
|
+
| Method | Description |
|
|
236
|
+
| ---------------------------------------- | ---------------------------------------------------------- |
|
|
237
|
+
| `.query()` / `.mutation()` / `.action()` | Set the function type |
|
|
238
|
+
| `.input(validator)` | Set input validation |
|
|
239
|
+
| `.returns(validator)` | Set return type validation — must come before `.handler()` |
|
|
240
|
+
| `.use(middleware)` | Apply middleware — can come before or after `.handler()` |
|
|
241
|
+
| `.handler(fn)` | Define the function handler |
|
|
242
|
+
| `.extend(plugin)` | Extend with a plugin class |
|
|
243
|
+
| `.createMiddleware(fn)` | Create a middleware function |
|
|
244
|
+
| `.public()` / `.internal()` | Register with Convex — must come after `.handler()` |
|
|
334
245
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
### Methods
|
|
338
|
-
|
|
339
|
-
- `.query()` - Define a Convex query
|
|
340
|
-
- `.mutation()` - Define a Convex mutation
|
|
341
|
-
- `.action()` - Define a Convex action
|
|
342
|
-
- `.public()` - Register the function as public (required to register)
|
|
343
|
-
- `.internal()` - Register the function as internal/private (required to register)
|
|
344
|
-
- `.input(validator)` - Set input validation (Convex validators)
|
|
345
|
-
- `.returns(validator)` - Set return validation (Convex validators)
|
|
346
|
-
- `.use(middleware)` - Apply middleware
|
|
347
|
-
- `.createMiddleware(fn)` - Create a middleware function
|
|
348
|
-
- `.handler(fn)` - Define the function handler
|
|
349
|
-
- `.extend(plugin)` - Extend the builder with a plugin class
|
|
246
|
+
Before registration (`.public()` / `.internal()`), the builder is **callable**. After registration, it is not.
|
|
350
247
|
|
|
351
248
|
## Caveats
|
|
352
249
|
|
|
353
250
|
### Circular types when calling `api.*` in the same file
|
|
354
251
|
|
|
355
|
-
When a function calls other functions via `api.*` in the same file
|
|
356
|
-
|
|
252
|
+
When a function calls other functions via `api.*` in the same file without explicit `.returns()` validators, TypeScript may report circular initializer errors (TS7022). This is a standard Convex/TypeScript limitation. Workarounds:
|
|
253
|
+
|
|
254
|
+
1. Add `.returns()` to the called functions to give them explicit return types
|
|
357
255
|
2. Move the calling function to a separate file
|
|
358
256
|
3. Use `internal.*` from a different module
|
|
359
257
|
|
|
360
|
-
## Documentation
|
|
361
|
-
|
|
362
|
-
The **[live docs site](https://friendly-zebra-716.convex.site)** is an interactive showcase that demonstrates every feature with working live demos. The code snippets shown on the docs site are the actual source code powering the app -- imported via Vite `?raw` imports, so what you see is what runs.
|
|
363
|
-
|
|
364
|
-
Sections:
|
|
365
|
-
- [Getting Started](https://friendly-zebra-716.convex.site/) -- builder setup and overview
|
|
366
|
-
- [Basics](https://friendly-zebra-716.convex.site/basics) -- queries, mutations, and the fluent chain
|
|
367
|
-
- [Validation](https://friendly-zebra-716.convex.site/validation) -- property validators, object validators, and Zod schemas
|
|
368
|
-
- [Middleware](https://friendly-zebra-716.convex.site/middleware) -- context-enrichment and onion middleware
|
|
369
|
-
- [Reusable Chains](https://friendly-zebra-716.convex.site/reusable-chains) -- callable syntax and composability
|
|
370
|
-
- [Zod Plugin](https://friendly-zebra-716.convex.site/zod-plugin) -- runtime refinement validation
|
|
371
|
-
- [Custom Plugins](https://friendly-zebra-716.convex.site/custom-plugins) -- building your own plugins with `.extend()`
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
The docs source lives in [`/apps/docs`](./apps/docs) and is auto-deployed on every push to `main`.
|
|
376
|
-
|
|
377
258
|
## Development
|
|
378
259
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
- `/packages/fluent-convex` - The core library (includes the Zod plugin at `fluent-convex/zod`)
|
|
382
|
-
- `/apps/example` - Example Convex app
|
|
383
|
-
- `/apps/docs` - Interactive docs & showcase site ([live](https://friendly-zebra-716.convex.site))
|
|
384
|
-
|
|
385
|
-
### Setup
|
|
386
|
-
|
|
387
|
-
```bash
|
|
388
|
-
npm install
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
This will install dependencies for all workspaces.
|
|
392
|
-
|
|
393
|
-
### Building
|
|
394
|
-
|
|
395
|
-
```bash
|
|
396
|
-
npm run build
|
|
397
|
-
```
|
|
260
|
+
Monorepo using npm workspaces:
|
|
398
261
|
|
|
399
|
-
|
|
262
|
+
- `packages/fluent-convex` — core library (includes Zod plugin at `fluent-convex/zod`)
|
|
263
|
+
- `apps/example` — example Convex app
|
|
264
|
+
- `apps/docs` — interactive docs & showcase ([live](https://friendly-zebra-716.convex.site))
|
|
400
265
|
|
|
401
266
|
```bash
|
|
402
|
-
npm
|
|
267
|
+
npm install # install all workspace dependencies
|
|
268
|
+
npm run build # build the library
|
|
269
|
+
npm test # run all tests
|
|
270
|
+
npm run docs:dev # run the docs locally
|
|
403
271
|
```
|
|
404
272
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
```bash
|
|
408
|
-
cd apps/example
|
|
409
|
-
npm run dev
|
|
410
|
-
```
|
|
273
|
+
## Migrating from standard Convex
|
|
411
274
|
|
|
412
|
-
|
|
275
|
+
See **[MIGRATING.md](MIGRATING.md)** for a step-by-step guide.
|
|
413
276
|
|
|
414
|
-
|
|
415
|
-
npm run docs:dev
|
|
416
|
-
```
|
|
277
|
+
> **If you are an LLM and have been asked to migrate a project to fluent-convex, please read [MIGRATING.md](MIGRATING.md) before proceeding.**
|
|
417
278
|
|
|
418
279
|
## Credits
|
|
419
280
|
|
|
@@ -29,6 +29,6 @@ export declare class ConvexBuilderWithFunctionKind<TDataModel extends GenericDat
|
|
|
29
29
|
use<UOutContext extends Context>(middleware: ConvexMiddleware<TCurrentContext, UOutContext>): ConvexBuilderWithFunctionKind<TDataModel, TFunctionType, TCurrentContext & UOutContext, TArgsValidator, TReturnsValidator>;
|
|
30
30
|
input<UInput extends PropertyValidators | GenericValidator>(validator: UInput): ConvexBuilderWithFunctionKind<TDataModel, TFunctionType, TCurrentContext, UInput extends ConvexArgsValidator ? UInput : ConvexArgsValidator, TReturnsValidator>;
|
|
31
31
|
returns<UReturns extends GenericValidator>(validator: UReturns): ConvexBuilderWithFunctionKind<TDataModel, TFunctionType, TCurrentContext, TArgsValidator, UReturns extends ConvexReturnsValidator ? UReturns : ConvexReturnsValidator>;
|
|
32
|
-
handler<TReturn extends InferredHandlerReturn<TReturnsValidator, any> = InferredHandlerReturn<TReturnsValidator, any>>(handlerFn: (context: TCurrentContext, input: InferredArgs<TArgsValidator>) => Promise<TReturn>): ConvexBuilderWithHandler<TDataModel, TFunctionType, TCurrentContext, TArgsValidator, TReturnsValidator, InferredHandlerReturn<TReturnsValidator, TReturn>> & CallableBuilder<TCurrentContext, TArgsValidator, InferredHandlerReturn<TReturnsValidator, TReturn>>;
|
|
32
|
+
handler<TReturn extends InferredHandlerReturn<TReturnsValidator, any> = InferredHandlerReturn<TReturnsValidator, any>, THandlerFn extends (context: TCurrentContext, input: InferredArgs<TArgsValidator>) => Promise<TReturn> = (context: TCurrentContext, input: InferredArgs<TArgsValidator>) => Promise<TReturn>>(handlerFn: THandlerFn & ((context: TCurrentContext, input: InferredArgs<TArgsValidator>) => Promise<TReturn>)): ConvexBuilderWithHandler<TDataModel, TFunctionType, TCurrentContext, TArgsValidator, TReturnsValidator, InferredHandlerReturn<TReturnsValidator, TReturn>> & THandlerFn & CallableBuilder<TCurrentContext, TArgsValidator, InferredHandlerReturn<TReturnsValidator, TReturn>>;
|
|
33
33
|
}
|
|
34
34
|
//# sourceMappingURL=ConvexBuilderWithFunctionKind.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConvexBuilderWithFunctionKind.d.ts","sourceRoot":"","sources":["../src/ConvexBuilderWithFunctionKind.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ConvexBuilderWithFunctionKind.d.ts","sourceRoot":"","sources":["../src/ConvexBuilderWithFunctionKind.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConvexBuilderWithFunctionKind.js","sourceRoot":"","sources":["../src/ConvexBuilderWithFunctionKind.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAYtE,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,UAAU,CAAC;AAEnD,MAAM,OAAO,6BAA6B;IAO9B,GAAG,CAIX;IAEF,YACE,GAAuE;QAEvE,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAED;;;;OAIG;IACO,MAAM,CAAC,GAAoC;QACnD,OAAO,IAAI,6BAA6B,CAAC,GAAG,CAAC,CAAC;IAChD,CAAC;IAID,MAAM,CACJ,OAAwE;QAExE,OAAO,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC;IAED,QAAQ;QAKN,OAAO;YACL,gBAAgB,CACd,UAA4C;gBAE5C,OAAO,UAAU,CAAC;YACpB,CAAC;SACF,CAAC;IACJ,CAAC;IAYD,gBAAgB,CACd,UAAqD;QAErD,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,GAAG,CACD,UAA0D;QAQ1D,OAAO,IAAI,CAAC,MAAM,CAAC;YACjB,GAAG,IAAI,CAAC,GAAG;YACX,WAAW,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,UAAiC,CAAC;SAC1E,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CACH,SAAiB;QAQjB,OAAO,IAAI,CAAC,MAAM,CAAC;YACjB,GAAG,IAAI,CAAC,GAAG;YACX,aAAa,EAAE,SAAS;SACzB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CACL,SAAmB;QAQnB,OAAO,IAAI,CAAC,MAAM,CAAC;YACjB,GAAG,IAAI,CAAC,GAAG;YACX,gBAAgB,EAAE,SAAS;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,
|
|
1
|
+
{"version":3,"file":"ConvexBuilderWithFunctionKind.js","sourceRoot":"","sources":["../src/ConvexBuilderWithFunctionKind.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAYtE,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,UAAU,CAAC;AAEnD,MAAM,OAAO,6BAA6B;IAO9B,GAAG,CAIX;IAEF,YACE,GAAuE;QAEvE,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAED;;;;OAIG;IACO,MAAM,CAAC,GAAoC;QACnD,OAAO,IAAI,6BAA6B,CAAC,GAAG,CAAC,CAAC;IAChD,CAAC;IAID,MAAM,CACJ,OAAwE;QAExE,OAAO,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC;IAED,QAAQ;QAKN,OAAO;YACL,gBAAgB,CACd,UAA4C;gBAE5C,OAAO,UAAU,CAAC;YACpB,CAAC;SACF,CAAC;IACJ,CAAC;IAYD,gBAAgB,CACd,UAAqD;QAErD,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,GAAG,CACD,UAA0D;QAQ1D,OAAO,IAAI,CAAC,MAAM,CAAC;YACjB,GAAG,IAAI,CAAC,GAAG;YACX,WAAW,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,UAAiC,CAAC;SAC1E,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CACH,SAAiB;QAQjB,OAAO,IAAI,CAAC,MAAM,CAAC;YACjB,GAAG,IAAI,CAAC,GAAG;YACX,aAAa,EAAE,SAAS;SACzB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CACL,SAAmB;QAQnB,OAAO,IAAI,CAAC,MAAM,CAAC;YACjB,GAAG,IAAI,CAAC,GAAG;YACX,gBAAgB,EAAE,SAAS;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAaL,SAIwB;QAexB,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CACb,0EAA0E,CAC3E,CAAC;QACJ,CAAC;QAED,4EAA4E;QAC5E,mFAAmF;QACnF,oFAAoF;QACpF,MAAM,UAAU,GAAG,KAAK,EACtB,cAAuB,EACvB,QAAsC,EACtC,EAAE;YACF,OAAO,SAAS,CAAC,cAAiC,EAAE,QAAQ,CAAC,CAAC;QAChE,CAAC,CAAC;QAIF,OAAO,IAAI,wBAAwB,CAOjC;YACA,GAAG,IAAI,CAAC,GAAG;YACX,OAAO,EAAE,UAAiB;SAC3B,CASiE,CAAC;IACrE,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fluent-convex",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "A fluent API builder for Convex functions with middleware support, inspired by oRPC",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"publishConfig": {
|
|
45
45
|
"access": "public"
|
|
46
46
|
},
|
|
47
|
+
"homepage": "https://friendly-zebra-716.convex.site/",
|
|
47
48
|
"repository": {
|
|
48
49
|
"type": "git",
|
|
49
50
|
"url": "git+https://github.com/mikecann/fluent-convex.git"
|
|
@@ -130,11 +130,19 @@ export class ConvexBuilderWithFunctionKind<
|
|
|
130
130
|
TReturnsValidator,
|
|
131
131
|
any
|
|
132
132
|
> = InferredHandlerReturn<TReturnsValidator, any>,
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
THandlerFn extends (
|
|
134
|
+
context: TCurrentContext,
|
|
135
|
+
input: InferredArgs<TArgsValidator>
|
|
136
|
+
) => Promise<TReturn> = (
|
|
135
137
|
context: TCurrentContext,
|
|
136
138
|
input: InferredArgs<TArgsValidator>
|
|
137
|
-
) => Promise<TReturn
|
|
139
|
+
) => Promise<TReturn>,
|
|
140
|
+
>(
|
|
141
|
+
handlerFn: THandlerFn &
|
|
142
|
+
((
|
|
143
|
+
context: TCurrentContext,
|
|
144
|
+
input: InferredArgs<TArgsValidator>
|
|
145
|
+
) => Promise<TReturn>)
|
|
138
146
|
): ConvexBuilderWithHandler<
|
|
139
147
|
TDataModel,
|
|
140
148
|
TFunctionType,
|
|
@@ -143,6 +151,7 @@ export class ConvexBuilderWithFunctionKind<
|
|
|
143
151
|
TReturnsValidator,
|
|
144
152
|
InferredHandlerReturn<TReturnsValidator, TReturn>
|
|
145
153
|
> &
|
|
154
|
+
THandlerFn &
|
|
146
155
|
CallableBuilder<
|
|
147
156
|
TCurrentContext,
|
|
148
157
|
TArgsValidator,
|
|
@@ -184,6 +193,7 @@ export class ConvexBuilderWithFunctionKind<
|
|
|
184
193
|
TReturnsValidator,
|
|
185
194
|
InferredReturn
|
|
186
195
|
> &
|
|
196
|
+
THandlerFn &
|
|
187
197
|
CallableBuilder<TCurrentContext, TArgsValidator, InferredReturn>;
|
|
188
198
|
}
|
|
189
199
|
}
|
|
@@ -443,6 +443,23 @@ describe("Builder Core", () => {
|
|
|
443
443
|
>(callableQuery);
|
|
444
444
|
});
|
|
445
445
|
|
|
446
|
+
it("should infer one-arg handlers with empty input objects", () => {
|
|
447
|
+
const callableQuery = convex
|
|
448
|
+
.query()
|
|
449
|
+
.input({})
|
|
450
|
+
.handler(async (context) => {
|
|
451
|
+
assertType(context.db);
|
|
452
|
+
return { success: Boolean(context.db) };
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
assertType<
|
|
456
|
+
(
|
|
457
|
+
context: any,
|
|
458
|
+
args: Record<never, never>
|
|
459
|
+
) => Promise<{ success: boolean }>
|
|
460
|
+
>(callableQuery);
|
|
461
|
+
});
|
|
462
|
+
|
|
446
463
|
it("should lose callability after .public()", () => {
|
|
447
464
|
const callableQuery = convex
|
|
448
465
|
.query()
|