kitcn 0.0.1 → 0.12.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.
Files changed (93) hide show
  1. package/bin/intent.js +3 -0
  2. package/dist/aggregate/index.d.ts +388 -0
  3. package/dist/aggregate/index.js +37 -0
  4. package/dist/api-entry-BckXqaLb.js +66 -0
  5. package/dist/auth/client/index.d.ts +37 -0
  6. package/dist/auth/client/index.js +217 -0
  7. package/dist/auth/config/index.d.ts +45 -0
  8. package/dist/auth/config/index.js +24 -0
  9. package/dist/auth/generated/index.d.ts +2 -0
  10. package/dist/auth/generated/index.js +3 -0
  11. package/dist/auth/http/index.d.ts +64 -0
  12. package/dist/auth/http/index.js +461 -0
  13. package/dist/auth/index.d.ts +221 -0
  14. package/dist/auth/index.js +1398 -0
  15. package/dist/auth/nextjs/index.d.ts +50 -0
  16. package/dist/auth/nextjs/index.js +81 -0
  17. package/dist/auth-store-Cljlmdmi.js +197 -0
  18. package/dist/builder-CBdG5W6A.js +1974 -0
  19. package/dist/caller-factory-cTXNvYdz.js +216 -0
  20. package/dist/cli.mjs +13255 -0
  21. package/dist/codegen-lF80HSWu.mjs +3416 -0
  22. package/dist/context-utils-HPC5nXzx.d.ts +17 -0
  23. package/dist/create-schema-odyF4kCy.js +156 -0
  24. package/dist/create-schema-orm-DOyiNDCx.js +246 -0
  25. package/dist/crpc/index.d.ts +105 -0
  26. package/dist/crpc/index.js +169 -0
  27. package/dist/customFunctions-C0voKmtx.js +144 -0
  28. package/dist/error-BZEnI7Sq.js +41 -0
  29. package/dist/generated-contract-disabled-Cih4eITO.js +50 -0
  30. package/dist/generated-contract-disabled-D-sOFy92.d.ts +354 -0
  31. package/dist/http-types-DqJubRPJ.d.ts +292 -0
  32. package/dist/meta-utils-0Pu0Nrap.js +117 -0
  33. package/dist/middleware-BUybuv9n.d.ts +34 -0
  34. package/dist/middleware-C2qTZ3V7.js +84 -0
  35. package/dist/orm/index.d.ts +17 -0
  36. package/dist/orm/index.js +10713 -0
  37. package/dist/plugins/index.d.ts +2 -0
  38. package/dist/plugins/index.js +3 -0
  39. package/dist/procedure-caller-DtxLmGwA.d.ts +1467 -0
  40. package/dist/procedure-caller-MWcxhQDv.js +349 -0
  41. package/dist/query-context-B8o6-8kC.js +1518 -0
  42. package/dist/query-context-CFZqIvD7.d.ts +42 -0
  43. package/dist/query-options-Dw7cOyXl.js +121 -0
  44. package/dist/ratelimit/index.d.ts +269 -0
  45. package/dist/ratelimit/index.js +856 -0
  46. package/dist/ratelimit/react/index.d.ts +76 -0
  47. package/dist/ratelimit/react/index.js +183 -0
  48. package/dist/react/index.d.ts +1284 -0
  49. package/dist/react/index.js +2526 -0
  50. package/dist/rsc/index.d.ts +276 -0
  51. package/dist/rsc/index.js +233 -0
  52. package/dist/runtime-CtvJPkur.js +2453 -0
  53. package/dist/server/index.d.ts +5 -0
  54. package/dist/server/index.js +6 -0
  55. package/dist/solid/index.d.ts +1221 -0
  56. package/dist/solid/index.js +2940 -0
  57. package/dist/transformer-DtDhR3Lc.js +194 -0
  58. package/dist/types-BTb_4BaU.d.ts +42 -0
  59. package/dist/types-BiJE7qxR.d.ts +4 -0
  60. package/dist/types-DEJpkIhw.d.ts +88 -0
  61. package/dist/types-HhO_R6pd.d.ts +213 -0
  62. package/dist/validators-B7oIJCAp.js +279 -0
  63. package/dist/validators-vzRKjBJC.d.ts +88 -0
  64. package/dist/watcher.mjs +96 -0
  65. package/dist/where-clause-compiler-DdjN63Io.d.ts +4756 -0
  66. package/package.json +107 -35
  67. package/skills/convex/SKILL.md +486 -0
  68. package/skills/convex/references/features/aggregates.md +353 -0
  69. package/skills/convex/references/features/auth-admin.md +446 -0
  70. package/skills/convex/references/features/auth-organizations.md +1141 -0
  71. package/skills/convex/references/features/auth-polar.md +579 -0
  72. package/skills/convex/references/features/auth.md +470 -0
  73. package/skills/convex/references/features/create-plugins.md +153 -0
  74. package/skills/convex/references/features/http.md +676 -0
  75. package/skills/convex/references/features/migrations.md +162 -0
  76. package/skills/convex/references/features/orm.md +1166 -0
  77. package/skills/convex/references/features/react.md +657 -0
  78. package/skills/convex/references/features/scheduling.md +267 -0
  79. package/skills/convex/references/features/testing.md +209 -0
  80. package/skills/convex/references/setup/auth.md +501 -0
  81. package/skills/convex/references/setup/biome.md +190 -0
  82. package/skills/convex/references/setup/doc-guidelines.md +145 -0
  83. package/skills/convex/references/setup/index.md +759 -0
  84. package/skills/convex/references/setup/next.md +116 -0
  85. package/skills/convex/references/setup/react.md +175 -0
  86. package/skills/convex/references/setup/server.md +473 -0
  87. package/skills/convex/references/setup/start.md +67 -0
  88. package/LICENSE +0 -21
  89. package/README.md +0 -0
  90. package/dist/index.d.mts +0 -5
  91. package/dist/index.d.mts.map +0 -1
  92. package/dist/index.mjs +0 -6
  93. package/dist/index.mjs.map +0 -1
@@ -0,0 +1,1974 @@
1
+ import { l as pick, o as vRequired, t as addFieldsToValidator } from "./validators-B7oIJCAp.js";
2
+ import { n as customCtx, t as NoOp } from "./customFunctions-C0voKmtx.js";
3
+ import { s as getTransformer } from "./transformer-DtDhR3Lc.js";
4
+ import { ConvexError, v } from "convex/values";
5
+ import { HttpRouter, actionGeneric, httpActionGeneric, internalActionGeneric, internalMutationGeneric, internalQueryGeneric, mutationGeneric, queryGeneric } from "convex/server";
6
+ import { z } from "zod";
7
+ import * as z$1 from "zod/v4";
8
+ import * as zCore from "zod/v4/core";
9
+
10
+ //#region src/internal/upstream/server/zod4.ts
11
+ /**
12
+ * zCustomQuery is like customQuery, but allows validation via zod.
13
+ * You can define custom behavior on top of `query` or `internalQuery`
14
+ * by passing a function that modifies the ctx and args. Or NoOp to do nothing.
15
+ *
16
+ * Example usage:
17
+ * ```ts
18
+ * const myQueryBuilder = zCustomQuery(query, {
19
+ * args: { sessionId: v.id("sessions") },
20
+ * input: async (ctx, args) => {
21
+ * const user = await getUserOrNull(ctx);
22
+ * const session = await db.get(sessionId);
23
+ * const db = wrapDatabaseReader({ user }, ctx.db, rlsRules);
24
+ * return { ctx: { db, user, session }, args: {} };
25
+ * },
26
+ * });
27
+ *
28
+ * // Using the custom builder
29
+ * export const getSomeData = myQueryBuilder({
30
+ * args: { someArg: z.string() },
31
+ * handler: async (ctx, args) => {
32
+ * const { db, user, session, scheduler } = ctx;
33
+ * const { someArg } = args;
34
+ * // ...
35
+ * }
36
+ * });
37
+ * ```
38
+ *
39
+ * Simple usage only modifying ctx:
40
+ * ```ts
41
+ * const myInternalQuery = zCustomQuery(
42
+ * internalQuery,
43
+ * customCtx(async (ctx) => {
44
+ * return {
45
+ * // Throws an exception if the user isn't logged in
46
+ * user: await getUserByTokenIdentifier(ctx),
47
+ * };
48
+ * })
49
+ * );
50
+ *
51
+ * // Using it
52
+ * export const getUser = myInternalQuery({
53
+ * args: { email: z.string().email() },
54
+ * handler: async (ctx, args) => {
55
+ * console.log(args.email);
56
+ * return ctx.user;
57
+ * },
58
+ * });
59
+ *
60
+ * @param query The query to be modified. Usually `query` or `internalQuery`
61
+ * from `_generated/server`.
62
+ * @param customization The customization to be applied to the query, changing ctx and args.
63
+ * @returns A new query builder using zod validation to define queries.
64
+ */
65
+ function zCustomQuery(query, customization) {
66
+ return customFnBuilder(query, customization);
67
+ }
68
+ /**
69
+ * zCustomMutation is like customMutation, but allows validation via zod.
70
+ * You can define custom behavior on top of `mutation` or `internalMutation`
71
+ * by passing a function that modifies the ctx and args. Or NoOp to do nothing.
72
+ *
73
+ * Example usage:
74
+ * ```ts
75
+ * const myMutationBuilder = zCustomMutation(mutation, {
76
+ * args: { sessionId: v.id("sessions") },
77
+ * input: async (ctx, args) => {
78
+ * const user = await getUserOrNull(ctx);
79
+ * const session = await db.get(sessionId);
80
+ * const db = wrapDatabaseReader({ user }, ctx.db, rlsRules);
81
+ * return { ctx: { db, user, session }, args: {} };
82
+ * },
83
+ * });
84
+ *
85
+ * // Using the custom builder
86
+ * export const getSomeData = myMutationBuilder({
87
+ * args: { someArg: z.string() },
88
+ * handler: async (ctx, args) => {
89
+ * const { db, user, session, scheduler } = ctx;
90
+ * const { someArg } = args;
91
+ * // ...
92
+ * }
93
+ * });
94
+ * ```
95
+ *
96
+ * Simple usage only modifying ctx:
97
+ * ```ts
98
+ * const myInternalMutation = zCustomMutation(
99
+ * internalMutation,
100
+ * customCtx(async (ctx) => {
101
+ * return {
102
+ * // Throws an exception if the user isn't logged in
103
+ * user: await getUserByTokenIdentifier(ctx),
104
+ * };
105
+ * })
106
+ * );
107
+ *
108
+ * // Using it
109
+ * export const getUser = myInternalMutation({
110
+ * args: { email: z.string().email() },
111
+ * handler: async (ctx, args) => {
112
+ * console.log(args.email);
113
+ * return ctx.user;
114
+ * },
115
+ * });
116
+ *
117
+ * @param mutation The mutation to be modified. Usually `mutation` or `internalMutation`
118
+ * from `_generated/server`.
119
+ * @param customization The customization to be applied to the mutation, changing ctx and args.
120
+ * @returns A new mutation builder using zod validation to define queries.
121
+ */
122
+ function zCustomMutation(mutation, customization) {
123
+ return customFnBuilder(mutation, customization);
124
+ }
125
+ /**
126
+ * zCustomAction is like customAction, but allows validation via zod.
127
+ * You can define custom behavior on top of `action` or `internalAction`
128
+ * by passing a function that modifies the ctx and args. Or NoOp to do nothing.
129
+ *
130
+ * Example usage:
131
+ * ```ts
132
+ * const myActionBuilder = zCustomAction(action, {
133
+ * args: { sessionId: v.id("sessions") },
134
+ * input: async (ctx, args) => {
135
+ * const user = await getUserOrNull(ctx);
136
+ * const session = await db.get(sessionId);
137
+ * const db = wrapDatabaseReader({ user }, ctx.db, rlsRules);
138
+ * return { ctx: { db, user, session }, args: {} };
139
+ * },
140
+ * });
141
+ *
142
+ * // Using the custom builder
143
+ * export const getSomeData = myActionBuilder({
144
+ * args: { someArg: z.string() },
145
+ * handler: async (ctx, args) => {
146
+ * const { db, user, session, scheduler } = ctx;
147
+ * const { someArg } = args;
148
+ * // ...
149
+ * }
150
+ * });
151
+ * ```
152
+ *
153
+ * Simple usage only modifying ctx:
154
+ * ```ts
155
+ * const myInternalAction = zCustomAction(
156
+ * internalAction,
157
+ * customCtx(async (ctx) => {
158
+ * return {
159
+ * // Throws an exception if the user isn't logged in
160
+ * user: await getUserByTokenIdentifier(ctx),
161
+ * };
162
+ * })
163
+ * );
164
+ *
165
+ * // Using it
166
+ * export const getUser = myInternalAction({
167
+ * args: { email: z.string().email() },
168
+ * handler: async (ctx, args) => {
169
+ * console.log(args.email);
170
+ * return ctx.user;
171
+ * },
172
+ * });
173
+ *
174
+ * @param action The action to be modified. Usually `action` or `internalAction`
175
+ * from `_generated/server`.
176
+ * @param customization The customization to be applied to the action, changing ctx and args.
177
+ * @returns A new action builder using zod validation to define queries.
178
+ */
179
+ function zCustomAction(action, customization) {
180
+ return customFnBuilder(action, customization);
181
+ }
182
+ /**
183
+ * Creates a validator for a Convex `Id`.
184
+ *
185
+ * - When **used within Zod**, it will only check that the ID is a string.
186
+ * - When **converted to a Convex validator** (e.g. through {@link zodToConvex}),
187
+ * it will check that it's for the right table.
188
+ *
189
+ * @param tableName - The table that the `Id` references. i.e. `Id<tableName>`
190
+ * @returns A Zod schema representing a Convex `Id`
191
+ */
192
+ const zid = (tableName) => {
193
+ const result = z$1.custom((val) => typeof val === "string");
194
+ _zidRegistry.add(result, { tableName });
195
+ return result;
196
+ };
197
+ /**
198
+ * Turns a Zod or Zod Mini validator into a Convex validator.
199
+ *
200
+ * The Convex validator will be as close to possible to the Zod validator,
201
+ * but might be broader than the Zod validator:
202
+ *
203
+ * ```ts
204
+ * zodToConvex(z.string().email()) // → v.string()
205
+ * ```
206
+ *
207
+ * This function is useful when running the Zod validator _after_ running the Convex validator
208
+ * (i.e. the Convex validator validates the input of the Zod validator). Hence, the Convex types
209
+ * will match the _input type_ of Zod transformations:
210
+ * ```ts
211
+ * zodToConvex(z.object({
212
+ * name: z.string().default("Nicolas"),
213
+ * })) // → v.object({ name: v.optional(v.string()) })
214
+ *
215
+ * zodToConvex(z.object({
216
+ * name: z.string().transform(s => s.length)
217
+ * })) // → v.object({ name: v.string() })
218
+ * ````
219
+ *
220
+ * This function is useful for:
221
+ * * **Validating function arguments with Zod**: through {@link zCustomQuery},
222
+ * {@link zCustomMutation} and {@link zCustomAction}, you can define the argument validation logic
223
+ * using Zod validators instead of Convex validators. `zodToConvex` will generate a Convex validator
224
+ * from your Zod validator. This will allow you to:
225
+ * - validate at run time that Convex IDs are from the right table (using {@link zid})
226
+ * - allow some features of Convex to understand the expected shape of the arguments
227
+ * (e.g. argument validation/prefilling in the function runner on the Convex dashboard)
228
+ * - still run the full Zod validation when the function runs
229
+ * (which is useful for more advanced Zod validators like `z.string().email()`)
230
+ * * **Validating data after reading it from the database**: if you want to write your DB schema
231
+ * with Zod, you can run Zod whenever you read from the database to check that the data
232
+ * still matches the schema. Note that this approach won’t ensure that the data stored in the DB
233
+ * matches the Zod schema; see
234
+ * https://stack.convex.dev/typescript-zod-function-validation#can-i-use-zod-to-define-my-database-types-too
235
+ * for more details.
236
+ *
237
+ * Note that some values might be valid in Zod but not in Convex,
238
+ * in the same way that valid JavaScript values might not be valid
239
+ * Convex values for the corresponding Convex type.
240
+ * (see the limits of Convex data types on https://docs.convex.dev/database/types).
241
+ *
242
+ * ```
243
+ * ┌─────────────────────────────────────┬─────────────────────────────────────┐
244
+ * │ **zodToConvex** │ zodOutputToConvex │
245
+ * ├─────────────────────────────────────┼─────────────────────────────────────┤
246
+ * │ For when the Zod validator runs │ For when the Zod validator runs │
247
+ * │ _after_ the Convex validator │ _before_ the Convex validator │
248
+ * ├─────────────────────────────────────┼─────────────────────────────────────┤
249
+ * │ Convex types use the _input types_ │ Convex types use the _return types_ │
250
+ * │ of Zod transformations │ of Zod transformations │
251
+ * ├─────────────────────────────────────┼─────────────────────────────────────┤
252
+ * │ The Convex validator can be less │ The Convex validator can be less │
253
+ * │ strict (i.e. some inputs might be │ strict (i.e. the type in Convex can │
254
+ * │ accepted by Convex then rejected │ be less precise than the type in │
255
+ * │ by Zod) │ the Zod output) │
256
+ * ├─────────────────────────────────────┼─────────────────────────────────────┤
257
+ * │ When using Zod schemas │ When using Zod schemas │
258
+ * │ for function definitions: │ for function definitions: │
259
+ * │ used for _arguments_ │ used for _return values_ │
260
+ * ├─────────────────────────────────────┼─────────────────────────────────────┤
261
+ * │ When validating contents of the │ When validating contents of the │
262
+ * │ database with a Zod schema: │ database with a Zod schema: │
263
+ * │ used to validate data │ used to validate data │
264
+ * │ _after reading_ │ _before writing_ │
265
+ * └─────────────────────────────────────┴─────────────────────────────────────┘
266
+ * ```
267
+ *
268
+ * @param zod Zod validator can be a Zod object, or a Zod type like `z.string()`
269
+ * @returns Convex Validator (e.g. `v.string()` from "convex/values")
270
+ * @throws If there is no equivalent Convex validator for the value (e.g. `z.date()`)
271
+ */
272
+ function zodToConvex(validator) {
273
+ const visited = /* @__PURE__ */ new WeakSet();
274
+ function zodToConvexInner(validator) {
275
+ if (visited.has(validator)) return v.any();
276
+ visited.add(validator);
277
+ const result = validator instanceof zCore.$ZodDefault ? v.optional(zodToConvexInner(validator._zod.def.innerType)) : validator instanceof zCore.$ZodPipe ? zodToConvexInner(validator._zod.def.in) : zodToConvexCommon(validator, zodToConvexInner);
278
+ visited.delete(validator);
279
+ return result;
280
+ }
281
+ return zodToConvexInner(validator);
282
+ }
283
+ /**
284
+ * Converts a Zod or Zod Mini validator to a Convex validator that checks the value _after_
285
+ * it has been validated (and possibly transformed) by the Zod validator.
286
+ *
287
+ * This is similar to {@link zodToConvex}, but is meant for cases where the Convex
288
+ * validator runs _after_ the Zod validator. Thus, the Convex type refers to the
289
+ * _output_ type of the Zod transformations:
290
+ * ```ts
291
+ * zodOutputToConvex(z.object({
292
+ * name: z.string().default("Nicolas"),
293
+ * })) // → v.object({ name: v.string() })
294
+ *
295
+ * zodOutputToConvex(z.object({
296
+ * name: z.string().transform(s => s.length)
297
+ * })) // → v.object({ name: v.number() })
298
+ * ````
299
+ *
300
+ * This function can be useful for:
301
+ * - **Validating function return values with Zod**: through {@link zCustomQuery},
302
+ * {@link zCustomMutation} and {@link zCustomAction}, you can define the `returns` property
303
+ * of a function using Zod validators instead of Convex validators.
304
+ * - **Validating data after reading it from the database**: if you want to write your DB schema
305
+ * Zod validators, you can run Zod whenever you write to the database to ensure your data matches
306
+ * the expected format. Note that this approach won’t ensure that the data stored in the DB
307
+ * isn’t modified manually in a way that doesn’t match your Zod schema; see
308
+ * https://stack.convex.dev/typescript-zod-function-validation#can-i-use-zod-to-define-my-database-types-too
309
+ * for more details.
310
+ *
311
+ * ```
312
+ * ┌─────────────────────────────────────┬─────────────────────────────────────┐
313
+ * │ zodToConvex │ **zodOutputToConvex** │
314
+ * ├─────────────────────────────────────┼─────────────────────────────────────┤
315
+ * │ For when the Zod validator runs │ For when the Zod validator runs │
316
+ * │ _after_ the Convex validator │ _before_ the Convex validator │
317
+ * ├─────────────────────────────────────┼─────────────────────────────────────┤
318
+ * │ Convex types use the _input types_ │ Convex types use the _return types_ │
319
+ * │ of Zod transformations │ of Zod transformations │
320
+ * ├─────────────────────────────────────┼─────────────────────────────────────┤
321
+ * │ The Convex validator can be less │ The Convex validator can be less │
322
+ * │ strict (i.e. some inputs might be │ strict (i.e. the type in Convex can │
323
+ * │ accepted by Convex then rejected │ be less precise than the type in │
324
+ * │ by Zod) │ the Zod output) │
325
+ * ├─────────────────────────────────────┼─────────────────────────────────────┤
326
+ * │ When using Zod schemas │ When using Zod schemas │
327
+ * │ for function definitions: │ for function definitions: │
328
+ * │ used for _arguments_ │ used for _return values_ │
329
+ * ├─────────────────────────────────────┼─────────────────────────────────────┤
330
+ * │ When validating contents of the │ When validating contents of the │
331
+ * │ database with a Zod schema: │ database with a Zod schema: │
332
+ * │ used to validate data │ used to validate data │
333
+ * │ _after reading_ │ _before writing_ │
334
+ * └─────────────────────────────────────┴─────────────────────────────────────┘
335
+ * ```
336
+ *
337
+ * @param z The zod validator
338
+ * @returns Convex Validator (e.g. `v.string()` from "convex/values")
339
+ * @throws If there is no equivalent Convex validator for the value (e.g. `z.date()`)
340
+ */
341
+ function zodOutputToConvex(validator) {
342
+ const visited = /* @__PURE__ */ new WeakSet();
343
+ function zodOutputToConvexInner(validator) {
344
+ if (visited.has(validator)) return v.any();
345
+ visited.add(validator);
346
+ const result = validator instanceof zCore.$ZodDefault ? zodOutputToConvexInner(validator._zod.def.innerType) : validator instanceof zCore.$ZodPipe ? zodOutputToConvexInner(validator._zod.def.out) : validator instanceof zCore.$ZodTransform ? v.any() : zodToConvexCommon(validator, zodOutputToConvexInner);
347
+ visited.delete(validator);
348
+ return result;
349
+ }
350
+ return zodOutputToConvexInner(validator);
351
+ }
352
+ /**
353
+ * Like {@link zodToConvex}, but it takes in a bare object, as expected by Convex
354
+ * function arguments, or the argument to {@link defineTable}.
355
+ *
356
+ * ```ts
357
+ * zodToConvexFields({
358
+ * name: z.string().default("Nicolas"),
359
+ * }) // → { name: v.optional(v.string()) }
360
+ * ```
361
+ *
362
+ * @param fields Object with string keys and Zod validators as values
363
+ * @returns Object with the same keys, but with Convex validators as values
364
+ */
365
+ function zodToConvexFields(fields) {
366
+ return Object.fromEntries(Object.entries(fields).map(([k, v]) => [k, zodToConvex(v)]));
367
+ }
368
+ /**
369
+ * Like {@link zodOutputToConvex}, but it takes in a bare object, as expected by
370
+ * Convex function arguments, or the argument to {@link defineTable}.
371
+ *
372
+ * ```ts
373
+ * zodOutputToConvexFields({
374
+ * name: z.string().default("Nicolas"),
375
+ * }) // → { name: v.string() }
376
+ * ```
377
+ *
378
+ * This is different from {@link zodToConvexFields} because it generates the
379
+ * Convex validator for the output of the Zod validator, not the input;
380
+ * see the documentation of {@link zodToConvex} and {@link zodOutputToConvex}
381
+ * for more details.
382
+ *
383
+ * @param zod Object with string keys and Zod validators as values
384
+ * @returns Object with the same keys, but with Convex validators as values
385
+ */
386
+ function zodOutputToConvexFields(fields) {
387
+ return Object.fromEntries(Object.entries(fields).map(([k, v]) => [k, zodOutputToConvex(v)]));
388
+ }
389
+ /**
390
+ * Turns a Convex validator into a Zod validator.
391
+ *
392
+ * This is useful when you want to use types you defined using Convex validators
393
+ * with external libraries that expect to receive a Zod validator.
394
+ *
395
+ * ```ts
396
+ * convexToZod(v.string()) // → z.string()
397
+ * ```
398
+ *
399
+ * This function returns Zod validators, not Zod Mini validators.
400
+ *
401
+ * @param convexValidator Convex validator can be any validator from "convex/values" e.g. `v.string()`
402
+ * @returns Zod validator (e.g. `z.string()`) with inferred type matching the Convex validator
403
+ */
404
+ function convexToZod(convexValidator) {
405
+ const isOptional = convexValidator.isOptional === "optional";
406
+ let zodValidator;
407
+ const { kind } = convexValidator;
408
+ switch (kind) {
409
+ case "id":
410
+ zodValidator = zid(convexValidator.tableName);
411
+ break;
412
+ case "string":
413
+ zodValidator = z$1.string();
414
+ break;
415
+ case "float64":
416
+ zodValidator = z$1.number();
417
+ break;
418
+ case "int64":
419
+ zodValidator = z$1.bigint();
420
+ break;
421
+ case "boolean":
422
+ zodValidator = z$1.boolean();
423
+ break;
424
+ case "null":
425
+ zodValidator = z$1.null();
426
+ break;
427
+ case "any":
428
+ zodValidator = z$1.any();
429
+ break;
430
+ case "array":
431
+ zodValidator = z$1.array(convexToZod(convexValidator.element));
432
+ break;
433
+ case "object":
434
+ zodValidator = z$1.object(convexToZodFields(convexValidator.fields));
435
+ break;
436
+ case "union": {
437
+ if (convexValidator.members.length === 0) {
438
+ zodValidator = z$1.never();
439
+ break;
440
+ }
441
+ if (convexValidator.members.length === 1) {
442
+ zodValidator = convexToZod(convexValidator.members[0]);
443
+ break;
444
+ }
445
+ const memberValidators = convexValidator.members.map((member) => convexToZod(member));
446
+ zodValidator = z$1.union([...memberValidators]);
447
+ break;
448
+ }
449
+ case "literal": {
450
+ const literalValidator = convexValidator;
451
+ zodValidator = z$1.literal(literalValidator.value);
452
+ break;
453
+ }
454
+ case "record":
455
+ zodValidator = z$1.record(convexToZod(convexValidator.key), convexToZod(convexValidator.value));
456
+ break;
457
+ case "bytes": throw new Error("v.bytes() is not supported");
458
+ default: throw new Error(`Unknown convex validator type: ${kind}`);
459
+ }
460
+ return isOptional ? z$1.optional(zodValidator) : zodValidator;
461
+ }
462
+ /**
463
+ * Like {@link convexToZod}, but it takes in a bare object, as expected by Convex
464
+ * function arguments, or the argument to {@link defineTable}.
465
+ *
466
+ * ```ts
467
+ * convexToZodFields({
468
+ * name: v.string(),
469
+ * }) // → { name: z.string() }
470
+ * ```
471
+ *
472
+ * @param convexValidators Object with string keys and Convex validators as values
473
+ * @returns Object with the same keys, but with Zod validators as values
474
+ */
475
+ function convexToZodFields(convexValidators) {
476
+ return Object.fromEntries(Object.entries(convexValidators).map(([k, v]) => [k, convexToZod(v)]));
477
+ }
478
+ /**
479
+ * Zod helper for adding Convex system fields to a record to return.
480
+ *
481
+ * ```ts
482
+ * withSystemFields("users", {
483
+ * name: z.string(),
484
+ * })
485
+ * // → {
486
+ * // name: z.string(),
487
+ * // _id: zid("users"),
488
+ * // _creationTime: z.number(),
489
+ * // }
490
+ * ```
491
+ *
492
+ * @param tableName - The table where records are from, i.e. Doc<tableName>
493
+ * @param zObject - Validators for the user-defined fields on the document.
494
+ * @returns Zod shape for use with `z.object(shape)` that includes system fields.
495
+ */
496
+ function withSystemFields(tableName, zObject) {
497
+ return {
498
+ ...zObject,
499
+ _id: zid(tableName),
500
+ _creationTime: z$1.number()
501
+ };
502
+ }
503
+ function customFnBuilder(builder, customization) {
504
+ const customInput = customization.input ?? NoOp.input;
505
+ const inputArgs = customization.args ?? NoOp.args;
506
+ return function customBuilder(fn) {
507
+ const { args, handler = fn, skipConvexValidation = false, returns: maybeObject, ...extra } = fn;
508
+ const returns = maybeObject && !(maybeObject instanceof zCore.$ZodType) ? z$1.object(maybeObject) : maybeObject;
509
+ const returnValidator = returns && !skipConvexValidation ? { returns: zodOutputToConvex(returns) } : null;
510
+ if (args) {
511
+ let argsValidator = args;
512
+ if (argsValidator instanceof zCore.$ZodType) if (argsValidator instanceof zCore.$ZodObject) argsValidator = argsValidator._zod.def.shape;
513
+ else throw new Error("Unsupported zod type as args validator: " + argsValidator.constructor.name);
514
+ const convexValidator = zodToConvexFields(argsValidator);
515
+ return builder({
516
+ args: skipConvexValidation ? void 0 : addFieldsToValidator(convexValidator, inputArgs),
517
+ ...returnValidator,
518
+ handler: async (ctx, allArgs) => {
519
+ const added = await customInput(ctx, pick(allArgs, Object.keys(inputArgs)), extra);
520
+ const rawArgs = pick(allArgs, Object.keys(argsValidator));
521
+ const parsed = await z$1.object(argsValidator).safeParseAsync(rawArgs);
522
+ if (!parsed.success) throw new ConvexError({ ZodError: JSON.parse(JSON.stringify(parsed.error.issues, null, 2)) });
523
+ const args = parsed.data;
524
+ const ret = await handler({
525
+ ...ctx,
526
+ ...added.ctx
527
+ }, {
528
+ ...args,
529
+ ...added.args
530
+ });
531
+ const result = returns ? await returns.parseAsync(ret === void 0 ? null : ret) : ret;
532
+ if (added.onSuccess) await added.onSuccess({
533
+ ctx,
534
+ args,
535
+ result
536
+ });
537
+ return result;
538
+ }
539
+ });
540
+ }
541
+ if (skipConvexValidation && Object.keys(inputArgs).length > 0) throw new Error("If you're using a custom function with arguments for the input customization, you cannot skip convex validation.");
542
+ return builder({
543
+ ...returnValidator,
544
+ handler: async (ctx, args) => {
545
+ const added = await customInput(ctx, args, extra);
546
+ const ret = await handler({
547
+ ...ctx,
548
+ ...added.ctx
549
+ }, {
550
+ ...args,
551
+ ...added.args
552
+ });
553
+ const result = returns ? await returns.parseAsync(ret === void 0 ? null : ret) : ret;
554
+ if (added.onSuccess) await added.onSuccess({
555
+ ctx,
556
+ args,
557
+ result
558
+ });
559
+ return result;
560
+ }
561
+ });
562
+ };
563
+ }
564
+ function zodToConvexCommon(validator, toConvex) {
565
+ if (validator instanceof zCore.$ZodString) return v.string();
566
+ if (validator instanceof zCore.$ZodNumber || validator instanceof zCore.$ZodNaN) return v.number();
567
+ if (validator instanceof zCore.$ZodBigInt) return v.int64();
568
+ if (validator instanceof zCore.$ZodBoolean) return v.boolean();
569
+ if (validator instanceof zCore.$ZodNull) return v.null();
570
+ if (validator instanceof zCore.$ZodAny || validator instanceof zCore.$ZodUnknown) return v.any();
571
+ if (validator instanceof zCore.$ZodArray) {
572
+ const inner = toConvex(validator._zod.def.element);
573
+ if (inner.isOptional === "optional") throw new Error("Arrays of optional values are not supported");
574
+ return v.array(inner);
575
+ }
576
+ if (validator instanceof zCore.$ZodObject) return v.object(Object.fromEntries(Object.entries(validator._zod.def.shape).map(([k, v]) => [k, toConvex(v)])));
577
+ if (validator instanceof zCore.$ZodUnion) return v.union(...validator._zod.def.options.map(toConvex));
578
+ if (validator instanceof zCore.$ZodNever) return v.union();
579
+ if (validator instanceof zCore.$ZodTuple) {
580
+ const { items, rest } = validator._zod.def;
581
+ return v.array(v.union(...[...items, ...rest !== null ? [rest] : []].map(toConvex)));
582
+ }
583
+ if (validator instanceof zCore.$ZodLiteral) {
584
+ const { values } = validator._zod.def;
585
+ if (values.length === 1) return convexToZodLiteral(values[0]);
586
+ return v.union(...values.map(convexToZodLiteral));
587
+ }
588
+ if (validator instanceof zCore.$ZodEnum) return v.union(...Object.entries(validator._zod.def.entries).filter(([key, value]) => key === value || isNaN(Number(key))).map(([_key, value]) => v.literal(value)));
589
+ if (validator instanceof zCore.$ZodOptional) return v.optional(toConvex(validator._zod.def.innerType));
590
+ if (validator instanceof zCore.$ZodNonOptional) return vRequired(toConvex(validator._zod.def.innerType));
591
+ if (validator instanceof zCore.$ZodNullable) {
592
+ const inner = toConvex(validator._zod.def.innerType);
593
+ if (inner.isOptional === "optional") return v.optional(v.union(vRequired(inner), v.null()));
594
+ return v.union(inner, v.null());
595
+ }
596
+ if (validator instanceof zCore.$ZodRecord) {
597
+ const { keyType, valueType } = validator._zod.def;
598
+ const isPartial = keyType._zod.values === void 0;
599
+ const valueValidator = toConvex(valueType);
600
+ const keyValidator = toConvex(keyType);
601
+ const stringLiterals = extractStringLiterals(keyValidator);
602
+ if (stringLiterals !== null) {
603
+ const fieldValue = isPartial || valueValidator.isOptional === "optional" ? v.optional(valueValidator) : vRequired(valueValidator);
604
+ const fields = {};
605
+ for (const literal of stringLiterals) fields[literal] = fieldValue;
606
+ return v.object(fields);
607
+ }
608
+ return v.record(isValidRecordKey(keyValidator) ? keyValidator : v.string(), vRequired(valueValidator));
609
+ }
610
+ if (validator instanceof zCore.$ZodReadonly) return toConvex(validator._zod.def.innerType);
611
+ if (validator instanceof zCore.$ZodLazy) return toConvex(validator._zod.def.getter());
612
+ if (validator instanceof zCore.$ZodTemplateLiteral) return v.string();
613
+ if (validator instanceof zCore.$ZodCustom) {
614
+ const idTableName = _zidRegistry.get(validator);
615
+ if (idTableName !== void 0 && typeof idTableName.tableName === "string") return v.id(idTableName.tableName);
616
+ return v.any();
617
+ }
618
+ if (validator instanceof zCore.$ZodIntersection) return v.any();
619
+ if (validator instanceof zCore.$ZodCatch) return toConvex(validator._zod.def.innerType);
620
+ if (validator instanceof zCore.$ZodDate || validator instanceof zCore.$ZodSymbol || validator instanceof zCore.$ZodMap || validator instanceof zCore.$ZodSet || validator instanceof zCore.$ZodPromise || validator instanceof zCore.$ZodFile || validator instanceof zCore.$ZodFunction || validator instanceof zCore.$ZodVoid || validator instanceof zCore.$ZodUndefined) throw new Error(`Validator ${validator.constructor.name} is not supported in Convex`);
621
+ return v.any();
622
+ }
623
+ function convexToZodLiteral(literal) {
624
+ if (literal === void 0) throw new Error("undefined is not a valid Convex value");
625
+ if (literal === null) return v.null();
626
+ return v.literal(literal);
627
+ }
628
+ function extractStringLiterals(validator) {
629
+ if (validator.kind === "literal") {
630
+ const literalValidator = validator;
631
+ if (typeof literalValidator.value === "string") return [literalValidator.value];
632
+ return null;
633
+ }
634
+ if (validator.kind === "union") {
635
+ const unionValidator = validator;
636
+ const literals = [];
637
+ for (const member of unionValidator.members) {
638
+ const memberLiterals = extractStringLiterals(member);
639
+ if (memberLiterals === null) return null;
640
+ literals.push(...memberLiterals);
641
+ }
642
+ return literals;
643
+ }
644
+ return null;
645
+ }
646
+ function isValidRecordKey(validator) {
647
+ if (validator.kind === "string" || validator.kind === "id") return true;
648
+ if (validator.kind === "union") return validator.members.every(isValidRecordKey);
649
+ return false;
650
+ }
651
+ /** Stores the table names for each `Zid` instance that is created. */
652
+ const _zidRegistry = zCore.registry();
653
+
654
+ //#endregion
655
+ //#region src/server/error.ts
656
+ /**
657
+ * CRPC Error - tRPC-style error handling for Convex
658
+ *
659
+ * Extends ConvexError with typed error codes and HTTP status mapping.
660
+ */
661
+ /** JSON-RPC 2.0 error codes (tRPC-style) */
662
+ const CRPC_ERROR_CODES_BY_KEY = {
663
+ PARSE_ERROR: -32700,
664
+ BAD_REQUEST: -32600,
665
+ INTERNAL_SERVER_ERROR: -32603,
666
+ NOT_IMPLEMENTED: -32603,
667
+ BAD_GATEWAY: -32603,
668
+ SERVICE_UNAVAILABLE: -32603,
669
+ GATEWAY_TIMEOUT: -32603,
670
+ UNAUTHORIZED: -32001,
671
+ PAYMENT_REQUIRED: -32002,
672
+ FORBIDDEN: -32003,
673
+ NOT_FOUND: -32004,
674
+ METHOD_NOT_SUPPORTED: -32005,
675
+ TIMEOUT: -32008,
676
+ CONFLICT: -32009,
677
+ PRECONDITION_FAILED: -32012,
678
+ PAYLOAD_TOO_LARGE: -32013,
679
+ UNSUPPORTED_MEDIA_TYPE: -32015,
680
+ UNPROCESSABLE_CONTENT: -32022,
681
+ PRECONDITION_REQUIRED: -32028,
682
+ TOO_MANY_REQUESTS: -32029,
683
+ CLIENT_CLOSED_REQUEST: -32099
684
+ };
685
+ /** Map error codes to HTTP status codes */
686
+ const CRPC_ERROR_CODE_TO_HTTP = {
687
+ PARSE_ERROR: 400,
688
+ BAD_REQUEST: 400,
689
+ UNAUTHORIZED: 401,
690
+ PAYMENT_REQUIRED: 402,
691
+ FORBIDDEN: 403,
692
+ NOT_FOUND: 404,
693
+ METHOD_NOT_SUPPORTED: 405,
694
+ TIMEOUT: 408,
695
+ CONFLICT: 409,
696
+ PRECONDITION_FAILED: 412,
697
+ PAYLOAD_TOO_LARGE: 413,
698
+ UNSUPPORTED_MEDIA_TYPE: 415,
699
+ UNPROCESSABLE_CONTENT: 422,
700
+ PRECONDITION_REQUIRED: 428,
701
+ TOO_MANY_REQUESTS: 429,
702
+ CLIENT_CLOSED_REQUEST: 499,
703
+ INTERNAL_SERVER_ERROR: 500,
704
+ NOT_IMPLEMENTED: 501,
705
+ BAD_GATEWAY: 502,
706
+ SERVICE_UNAVAILABLE: 503,
707
+ GATEWAY_TIMEOUT: 504
708
+ };
709
+ /** Extract Error from unknown cause (from tRPC) */
710
+ function getCauseFromUnknown(cause) {
711
+ if (cause instanceof Error) return cause;
712
+ if (typeof cause === "undefined" || typeof cause === "function" || cause === null) return;
713
+ if (typeof cause !== "object") return new Error(String(cause));
714
+ }
715
+ /**
716
+ * tRPC-style error extending ConvexError
717
+ *
718
+ * @example
719
+ * ```typescript
720
+ * throw new CRPCError({
721
+ * code: 'BAD_REQUEST',
722
+ * message: 'Invalid input',
723
+ * cause: originalError,
724
+ * });
725
+ * ```
726
+ */
727
+ var CRPCError = class extends ConvexError {
728
+ code;
729
+ cause;
730
+ constructor(opts) {
731
+ const cause = getCauseFromUnknown(opts.cause);
732
+ const message = opts.message ?? cause?.message ?? opts.code;
733
+ super({
734
+ code: opts.code,
735
+ message
736
+ });
737
+ this.name = "CRPCError";
738
+ this.code = opts.code;
739
+ this.cause = cause;
740
+ this.message = message;
741
+ }
742
+ };
743
+ function isOrmNotFoundErrorLike(cause) {
744
+ return cause instanceof Error && cause.name === "OrmNotFoundError";
745
+ }
746
+ function isApiErrorLike(cause) {
747
+ return cause instanceof Error && cause.name === "APIError" && typeof cause.statusCode === "number";
748
+ }
749
+ function mapHttpStatusCodeToCRPCCode(statusCode) {
750
+ switch (statusCode) {
751
+ case 400: return "BAD_REQUEST";
752
+ case 401: return "UNAUTHORIZED";
753
+ case 402: return "PAYMENT_REQUIRED";
754
+ case 403: return "FORBIDDEN";
755
+ case 404: return "NOT_FOUND";
756
+ case 405: return "METHOD_NOT_SUPPORTED";
757
+ case 408: return "TIMEOUT";
758
+ case 409: return "CONFLICT";
759
+ case 412: return "PRECONDITION_FAILED";
760
+ case 413: return "PAYLOAD_TOO_LARGE";
761
+ case 415: return "UNSUPPORTED_MEDIA_TYPE";
762
+ case 422: return "UNPROCESSABLE_CONTENT";
763
+ case 428: return "PRECONDITION_REQUIRED";
764
+ case 429: return "TOO_MANY_REQUESTS";
765
+ case 499: return "CLIENT_CLOSED_REQUEST";
766
+ default: return "INTERNAL_SERVER_ERROR";
767
+ }
768
+ }
769
+ function getApiErrorMessage(cause) {
770
+ const body = cause.body;
771
+ if (body && typeof body === "object") {
772
+ const message = body.message;
773
+ if (typeof message === "string" && message.length > 0) return message;
774
+ }
775
+ if (typeof cause.message === "string" && cause.message.length > 0) return cause.message;
776
+ return "Request failed";
777
+ }
778
+ /**
779
+ * Convert known framework/library errors into CRPCError.
780
+ *
781
+ * Intended for cRPC internals so callers don't need per-endpoint try/catch.
782
+ */
783
+ function toCRPCError(cause) {
784
+ if (cause instanceof CRPCError) return cause;
785
+ if (cause instanceof Error && cause.name === "CRPCError") return cause;
786
+ if (isOrmNotFoundErrorLike(cause)) {
787
+ const err = new CRPCError({
788
+ code: "NOT_FOUND",
789
+ message: cause.message,
790
+ cause
791
+ });
792
+ if (cause.stack) err.stack = cause.stack;
793
+ return err;
794
+ }
795
+ if (isApiErrorLike(cause)) {
796
+ const status = cause.status;
797
+ const statusCode = cause.statusCode;
798
+ const err = new CRPCError({
799
+ code: typeof status === "string" && status in CRPC_ERROR_CODES_BY_KEY ? status : typeof statusCode === "number" ? mapHttpStatusCodeToCRPCCode(statusCode) : "INTERNAL_SERVER_ERROR",
800
+ message: getApiErrorMessage(cause),
801
+ cause
802
+ });
803
+ if (cause.stack) err.stack = cause.stack;
804
+ return err;
805
+ }
806
+ return null;
807
+ }
808
+ /**
809
+ * Wrap unknown error in CRPCError (from tRPC)
810
+ *
811
+ * @example
812
+ * ```typescript
813
+ * try {
814
+ * await someOperation();
815
+ * } catch (error) {
816
+ * throw getCRPCErrorFromUnknown(error);
817
+ * }
818
+ * ```
819
+ */
820
+ function getCRPCErrorFromUnknown(cause) {
821
+ const handled = toCRPCError(cause);
822
+ if (handled) return handled;
823
+ const error = new CRPCError({
824
+ code: "INTERNAL_SERVER_ERROR",
825
+ cause
826
+ });
827
+ if (cause instanceof Error && cause.stack) error.stack = cause.stack;
828
+ return error;
829
+ }
830
+ /**
831
+ * Get HTTP status code from CRPCError
832
+ *
833
+ * @example
834
+ * ```typescript
835
+ * const httpStatus = getHTTPStatusCodeFromError(error); // 400
836
+ * ```
837
+ */
838
+ function getHTTPStatusCodeFromError(error) {
839
+ return CRPC_ERROR_CODE_TO_HTTP[error.code] ?? 500;
840
+ }
841
+ /** Type guard for CRPCError */
842
+ function isCRPCError(error) {
843
+ return error instanceof CRPCError;
844
+ }
845
+
846
+ //#endregion
847
+ //#region src/server/http-builder.ts
848
+ function extractPathParams(path) {
849
+ const matches = path.match(/:([a-zA-Z_][a-zA-Z0-9_]*)/g);
850
+ return matches ? matches.map((m) => m.slice(1)) : [];
851
+ }
852
+ function matchPathParams(template, pathname) {
853
+ const templateParts = template.split("/").filter(Boolean);
854
+ const pathParts = pathname.split("/").filter(Boolean);
855
+ if (templateParts.length !== pathParts.length) return null;
856
+ const params = {};
857
+ for (let i = 0; i < templateParts.length; i++) {
858
+ const templatePart = templateParts[i];
859
+ const pathPart = pathParts[i];
860
+ if (templatePart.startsWith(":")) params[templatePart.slice(1)] = decodeURIComponent(pathPart);
861
+ else if (templatePart !== pathPart) return null;
862
+ }
863
+ return params;
864
+ }
865
+ function handleHttpError(error) {
866
+ if (error instanceof CRPCError) {
867
+ const status = {
868
+ BAD_REQUEST: 400,
869
+ UNAUTHORIZED: 401,
870
+ FORBIDDEN: 403,
871
+ NOT_FOUND: 404,
872
+ METHOD_NOT_SUPPORTED: 405,
873
+ CONFLICT: 409,
874
+ UNPROCESSABLE_CONTENT: 422,
875
+ TOO_MANY_REQUESTS: 429,
876
+ INTERNAL_SERVER_ERROR: 500
877
+ }[error.code] ?? 500;
878
+ return Response.json({ error: {
879
+ code: error.code,
880
+ message: error.message
881
+ } }, { status });
882
+ }
883
+ console.error("Unhandled HTTP error:", error);
884
+ return Response.json({ error: {
885
+ code: "INTERNAL_SERVER_ERROR",
886
+ message: "An unexpected error occurred"
887
+ } }, { status: 500 });
888
+ }
889
+ function getBaseSchema(schema) {
890
+ if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable) return getBaseSchema(schema.unwrap());
891
+ if (schema instanceof z.ZodDefault) return getBaseSchema(schema._def.innerType);
892
+ return schema;
893
+ }
894
+ function isArraySchema(schema) {
895
+ return getBaseSchema(schema) instanceof z.ZodArray;
896
+ }
897
+ function isNumberSchema(schema) {
898
+ return getBaseSchema(schema) instanceof z.ZodNumber;
899
+ }
900
+ function isBooleanSchema(schema) {
901
+ return getBaseSchema(schema) instanceof z.ZodBoolean;
902
+ }
903
+ function parseQueryParams(url, schema) {
904
+ const params = {};
905
+ const keys = new Set(url.searchParams.keys());
906
+ const shape = schema instanceof z.ZodObject ? schema.shape : {};
907
+ for (const key of keys) {
908
+ const values = url.searchParams.getAll(key);
909
+ const fieldSchema = shape[key];
910
+ if (fieldSchema) if (isArraySchema(fieldSchema)) params[key] = values;
911
+ else if (isNumberSchema(fieldSchema)) params[key] = Number(values[0]);
912
+ else if (isBooleanSchema(fieldSchema)) {
913
+ const val = values[0].toLowerCase();
914
+ params[key] = val === "true" || val === "1";
915
+ } else params[key] = values.length === 1 ? values[0] : values;
916
+ else params[key] = values.length === 1 ? values[0] : values;
917
+ }
918
+ return params;
919
+ }
920
+ /** Factory function to create a new builder with merged def */
921
+ function createNewHttpBuilder(def1, def2) {
922
+ return createHttpBuilder({
923
+ ...def1,
924
+ ...def2
925
+ });
926
+ }
927
+ /** Internal method to create the HTTP procedure */
928
+ function createProcedure(def, handler, _type) {
929
+ if (!def.route) throw new Error("Route must be defined before action. Use .route(path, method) first.");
930
+ /**
931
+ * Hono-compatible handler function.
932
+ * When used with HttpRouterWithHono, Convex ctx is passed via c.env.
933
+ */
934
+ const honoHandler = async (c) => {
935
+ const convexCtx = c.env;
936
+ const request = c.req.raw;
937
+ try {
938
+ const url = new URL(request.url);
939
+ const pathParams = c.req.param() ?? matchPathParams(def.route.path, url.pathname) ?? {};
940
+ let ctx = def.functionConfig.createContext(convexCtx);
941
+ const getRawInput = async () => {
942
+ if ((request.headers.get("content-type") ?? "").includes("application/json")) return request.clone().json();
943
+ return null;
944
+ };
945
+ let currentInput;
946
+ for (const middleware of def.middlewares) {
947
+ const result = await middleware({
948
+ ctx,
949
+ input: currentInput,
950
+ getRawInput,
951
+ next: async (opts) => {
952
+ if (opts?.ctx) ctx = {
953
+ ...ctx,
954
+ ...opts.ctx
955
+ };
956
+ if (opts?.input !== void 0) currentInput = opts.input;
957
+ return {
958
+ ctx,
959
+ marker: void 0
960
+ };
961
+ },
962
+ meta: def.meta
963
+ });
964
+ if (result?.ctx) ctx = {
965
+ ...ctx,
966
+ ...result.ctx
967
+ };
968
+ }
969
+ let parsedParams;
970
+ if (def.paramsSchema) try {
971
+ parsedParams = def.paramsSchema.parse(pathParams);
972
+ } catch (error) {
973
+ if (error instanceof z.ZodError) throw new CRPCError({
974
+ code: "BAD_REQUEST",
975
+ message: "Invalid path params",
976
+ cause: error
977
+ });
978
+ throw error;
979
+ }
980
+ let parsedQuery;
981
+ if (def.querySchema) {
982
+ const queryParams = parseQueryParams(url, def.querySchema);
983
+ try {
984
+ parsedQuery = def.querySchema.parse(queryParams);
985
+ } catch (error) {
986
+ if (error instanceof z.ZodError) throw new CRPCError({
987
+ code: "BAD_REQUEST",
988
+ message: "Invalid query params",
989
+ cause: error
990
+ });
991
+ throw error;
992
+ }
993
+ }
994
+ let parsedInput;
995
+ if (def.inputSchema && request.method !== "GET") {
996
+ const contentType = request.headers.get("content-type") ?? "";
997
+ let body;
998
+ if (contentType.includes("application/json")) body = await request.json();
999
+ else if (contentType.includes("application/x-www-form-urlencoded")) {
1000
+ const formData = await request.formData();
1001
+ body = Object.fromEntries(formData.entries());
1002
+ } else body = await request.json().catch(() => ({}));
1003
+ try {
1004
+ parsedInput = def.inputSchema.parse(def.functionConfig.transformer.input.deserialize(body));
1005
+ } catch (error) {
1006
+ if (error instanceof z.ZodError) throw new CRPCError({
1007
+ code: "BAD_REQUEST",
1008
+ message: "Invalid input",
1009
+ cause: error
1010
+ });
1011
+ throw error;
1012
+ }
1013
+ }
1014
+ let parsedForm;
1015
+ if (def.formSchema && request.method !== "GET") {
1016
+ const formData = await request.formData();
1017
+ const formObj = {};
1018
+ for (const [key, value] of formData.entries()) formObj[key] = value;
1019
+ try {
1020
+ parsedForm = def.formSchema.parse(formObj);
1021
+ } catch (error) {
1022
+ if (error instanceof z.ZodError) throw new CRPCError({
1023
+ code: "BAD_REQUEST",
1024
+ message: "Invalid form data",
1025
+ cause: error
1026
+ });
1027
+ throw error;
1028
+ }
1029
+ }
1030
+ const handlerOpts = {
1031
+ ctx,
1032
+ c
1033
+ };
1034
+ if (parsedInput !== void 0) handlerOpts.input = parsedInput;
1035
+ if (parsedParams !== void 0) handlerOpts.params = parsedParams;
1036
+ if (parsedQuery !== void 0) handlerOpts.searchParams = parsedQuery;
1037
+ if (parsedForm !== void 0) handlerOpts.form = parsedForm;
1038
+ const result = await handler(handlerOpts);
1039
+ if (result instanceof Response) return result;
1040
+ const output = def.outputSchema ? def.outputSchema.parse(result) : result;
1041
+ return c.json(def.functionConfig.transformer.output.serialize(output));
1042
+ } catch (error) {
1043
+ return handleHttpError(error);
1044
+ }
1045
+ };
1046
+ honoHandler._crpcRoute = {
1047
+ path: def.route.path,
1048
+ method: def.route.method
1049
+ };
1050
+ const procedure = def.functionConfig.base(async (convexCtx, request) => {
1051
+ return honoHandler({
1052
+ env: convexCtx,
1053
+ req: {
1054
+ raw: request,
1055
+ param: () => matchPathParams(def.route.path, new URL(request.url).pathname) ?? {}
1056
+ },
1057
+ json: (data, status) => Response.json(data, { status }),
1058
+ text: (text, status) => new Response(text, { status }),
1059
+ body: (body, init) => new Response(body, init),
1060
+ html: (html, status) => new Response(html, {
1061
+ status,
1062
+ headers: { "Content-Type": "text/html" }
1063
+ }),
1064
+ redirect: (url, status) => Response.redirect(url, status ?? 302),
1065
+ header: (_name, _value) => {}
1066
+ });
1067
+ });
1068
+ procedure.isHttp = true;
1069
+ procedure._crpcHttpRoute = def.route;
1070
+ procedure._def = {
1071
+ inputSchema: def.inputSchema,
1072
+ outputSchema: def.outputSchema,
1073
+ paramsSchema: def.paramsSchema,
1074
+ querySchema: def.querySchema,
1075
+ formSchema: def.formSchema
1076
+ };
1077
+ procedure._honoHandler = honoHandler;
1078
+ return procedure;
1079
+ }
1080
+ /** Create the builder implementation object */
1081
+ function createHttpBuilder(def) {
1082
+ return {
1083
+ _def: def,
1084
+ use(middlewareOrBuilder) {
1085
+ const middlewares = "_middlewares" in middlewareOrBuilder ? middlewareOrBuilder._middlewares : [middlewareOrBuilder];
1086
+ return createNewHttpBuilder(def, { middlewares: [...def.middlewares, ...middlewares] });
1087
+ },
1088
+ meta(value) {
1089
+ return createNewHttpBuilder(def, { meta: def.meta ? {
1090
+ ...def.meta,
1091
+ ...value
1092
+ } : value });
1093
+ },
1094
+ route(path, method) {
1095
+ const pathParamNames = extractPathParams(path);
1096
+ return createNewHttpBuilder(def, { route: {
1097
+ path,
1098
+ method,
1099
+ pathParamNames,
1100
+ usePathPrefix: pathParamNames.length > 0
1101
+ } });
1102
+ },
1103
+ get(path) {
1104
+ const pathParamNames = extractPathParams(path);
1105
+ return createNewHttpBuilder(def, { route: {
1106
+ path,
1107
+ method: "GET",
1108
+ pathParamNames,
1109
+ usePathPrefix: pathParamNames.length > 0
1110
+ } });
1111
+ },
1112
+ post(path) {
1113
+ const pathParamNames = extractPathParams(path);
1114
+ return createNewHttpBuilder(def, { route: {
1115
+ path,
1116
+ method: "POST",
1117
+ pathParamNames,
1118
+ usePathPrefix: pathParamNames.length > 0
1119
+ } });
1120
+ },
1121
+ put(path) {
1122
+ const pathParamNames = extractPathParams(path);
1123
+ return createNewHttpBuilder(def, { route: {
1124
+ path,
1125
+ method: "PUT",
1126
+ pathParamNames,
1127
+ usePathPrefix: pathParamNames.length > 0
1128
+ } });
1129
+ },
1130
+ patch(path) {
1131
+ const pathParamNames = extractPathParams(path);
1132
+ return createNewHttpBuilder(def, { route: {
1133
+ path,
1134
+ method: "PATCH",
1135
+ pathParamNames,
1136
+ usePathPrefix: pathParamNames.length > 0
1137
+ } });
1138
+ },
1139
+ delete(path) {
1140
+ const pathParamNames = extractPathParams(path);
1141
+ return createNewHttpBuilder(def, { route: {
1142
+ path,
1143
+ method: "DELETE",
1144
+ pathParamNames,
1145
+ usePathPrefix: pathParamNames.length > 0
1146
+ } });
1147
+ },
1148
+ params(schema) {
1149
+ return createNewHttpBuilder(def, { paramsSchema: schema });
1150
+ },
1151
+ searchParams(schema) {
1152
+ return createNewHttpBuilder(def, { querySchema: schema });
1153
+ },
1154
+ input(schema) {
1155
+ return createNewHttpBuilder(def, { inputSchema: schema });
1156
+ },
1157
+ output(schema) {
1158
+ return createNewHttpBuilder(def, { outputSchema: schema });
1159
+ },
1160
+ form(schema) {
1161
+ return createNewHttpBuilder(def, { formSchema: schema });
1162
+ },
1163
+ query(handler) {
1164
+ return createProcedure(def, handler, "query");
1165
+ },
1166
+ mutation(handler) {
1167
+ return createProcedure(def, handler, "mutation");
1168
+ }
1169
+ };
1170
+ }
1171
+ /**
1172
+ * Create initial HttpProcedureBuilder
1173
+ */
1174
+ function createHttpProcedureBuilder(config) {
1175
+ return createHttpBuilder({
1176
+ middlewares: [],
1177
+ meta: config.meta,
1178
+ functionConfig: {
1179
+ base: config.base,
1180
+ createContext: config.createContext,
1181
+ transformer: getTransformer(config.transformer)
1182
+ }
1183
+ });
1184
+ }
1185
+
1186
+ //#endregion
1187
+ //#region src/server/http-router.ts
1188
+ /**
1189
+ * Check if an export is a cRPC HTTP procedure
1190
+ * Note: Procedures are functions with attached properties, not plain objects
1191
+ */
1192
+ function isCRPCHttpProcedure(value) {
1193
+ return typeof value === "function" && "isHttp" in value && value.isHttp === true && "_crpcHttpRoute" in value;
1194
+ }
1195
+ /**
1196
+ * Check if a value is a cRPC HTTP router
1197
+ */
1198
+ function isCRPCHttpRouter(value) {
1199
+ return typeof value === "object" && value !== null && "_def" in value && value._def?.router === true;
1200
+ }
1201
+ /**
1202
+ * HTTP Router that wraps a Hono app for use with Convex.
1203
+ * Internal class - use `createHttpRouter()` factory instead.
1204
+ */
1205
+ var HttpRouterWithHono = class extends HttpRouter {
1206
+ _app;
1207
+ _handler;
1208
+ constructor(app) {
1209
+ super();
1210
+ this._app = app;
1211
+ this._handler = httpActionGeneric(async (ctx, request) => {
1212
+ return await app.fetch(request, ctx);
1213
+ });
1214
+ const parentGetRoutes = this.getRoutes.bind(this);
1215
+ const parentLookup = this.lookup.bind(this);
1216
+ /**
1217
+ * Get routes from the Hono app for Convex dashboard display.
1218
+ * Returns route definitions in the format expected by Convex.
1219
+ */
1220
+ this.getRoutes = () => {
1221
+ const parentRoutes = parentGetRoutes();
1222
+ const honoRoutes = [];
1223
+ for (const route of this._app.routes) {
1224
+ const method = route.method.toUpperCase();
1225
+ if ([
1226
+ "GET",
1227
+ "POST",
1228
+ "PUT",
1229
+ "PATCH",
1230
+ "DELETE",
1231
+ "OPTIONS",
1232
+ "HEAD"
1233
+ ].includes(method)) honoRoutes.push([
1234
+ route.path,
1235
+ method,
1236
+ this._handler
1237
+ ]);
1238
+ }
1239
+ return [...parentRoutes.map((r) => [...r]), ...honoRoutes];
1240
+ };
1241
+ /**
1242
+ * Look up the handler for a given path and method.
1243
+ * Checks traditional routes first, then delegates to Hono's router.
1244
+ */
1245
+ this.lookup = (path, method) => {
1246
+ const parentMatch = parentLookup(path, method);
1247
+ if (parentMatch !== null) return parentMatch;
1248
+ const normalizedMethod = method === "HEAD" ? "GET" : method;
1249
+ const matchResult = this._app.router.match(normalizedMethod, path);
1250
+ if (matchResult && matchResult[0].length > 0) return [
1251
+ this._handler,
1252
+ normalizedMethod,
1253
+ path
1254
+ ];
1255
+ return null;
1256
+ };
1257
+ }
1258
+ };
1259
+ /**
1260
+ * Create a router factory function (like tRPC's createRouterFactory)
1261
+ *
1262
+ * @example
1263
+ * ```ts
1264
+ * // In crpc.ts
1265
+ * export const router = c.router;
1266
+ *
1267
+ * // In api/todos.ts
1268
+ * export const todosRouter = router({
1269
+ * get: publicRoute.get('/api/todos/:id')...,
1270
+ * create: authRoute.post('/api/todos')...,
1271
+ * });
1272
+ *
1273
+ * // In http.ts
1274
+ * export const httpRouter = router({
1275
+ * todos: todosRouter,
1276
+ * health,
1277
+ * });
1278
+ * export type AppRouter = typeof httpRouter;
1279
+ * ```
1280
+ */
1281
+ function createHttpRouterFactory() {
1282
+ return function router(record) {
1283
+ const procedures = {};
1284
+ /**
1285
+ * Recursively flatten procedures with dot-notation paths
1286
+ * Like tRPC's step() function in router.ts
1287
+ */
1288
+ function step(obj, path = []) {
1289
+ for (const [key, value] of Object.entries(obj)) {
1290
+ const newPath = [...path, key];
1291
+ const pathKey = newPath.join(".");
1292
+ if (isCRPCHttpProcedure(value)) procedures[pathKey] = value;
1293
+ else if (isCRPCHttpRouter(value)) for (const [procPath, proc] of Object.entries(value._def.procedures)) procedures[`${pathKey}.${procPath}`] = proc;
1294
+ else if (typeof value === "object" && value !== null) step(value, newPath);
1295
+ }
1296
+ }
1297
+ step(record);
1298
+ return { _def: {
1299
+ router: true,
1300
+ procedures,
1301
+ record
1302
+ } };
1303
+ };
1304
+ }
1305
+ /**
1306
+ * Create an HTTP router with cRPC routes registered.
1307
+ *
1308
+ * @example
1309
+ * ```ts
1310
+ * import { Hono } from 'hono';
1311
+ * import { cors } from 'hono/cors';
1312
+ * import { createHttpRouter } from 'kitcn/server';
1313
+ *
1314
+ * const app = new Hono();
1315
+ * app.use('/api/*', cors({ origin: process.env.SITE_URL, credentials: true }));
1316
+ *
1317
+ * export default createHttpRouter(app, httpRouter);
1318
+ * ```
1319
+ */
1320
+ function createHttpRouter(app, router) {
1321
+ for (const procedure of Object.values(router._def.procedures)) {
1322
+ const { path, method } = procedure._crpcHttpRoute;
1323
+ const honoHandler = procedure._honoHandler;
1324
+ if (!honoHandler) {
1325
+ console.warn(`Procedure at ${path} does not have a Hono handler. Make sure you are using the latest version of kitcn.`);
1326
+ continue;
1327
+ }
1328
+ switch (method) {
1329
+ case "GET":
1330
+ app.get(path, honoHandler);
1331
+ break;
1332
+ case "POST":
1333
+ app.post(path, honoHandler);
1334
+ break;
1335
+ case "PUT":
1336
+ app.put(path, honoHandler);
1337
+ break;
1338
+ case "PATCH":
1339
+ app.patch(path, honoHandler);
1340
+ break;
1341
+ case "DELETE":
1342
+ app.delete(path, honoHandler);
1343
+ break;
1344
+ }
1345
+ }
1346
+ return new HttpRouterWithHono(app);
1347
+ }
1348
+ /**
1349
+ * Extract route map from procedures for client runtime
1350
+ *
1351
+ * @example
1352
+ * ```ts
1353
+ * export const httpRoutes = extractRouteMap(httpRouter._def.procedures);
1354
+ * ```
1355
+ */
1356
+ function extractRouteMap(procedures) {
1357
+ const result = {};
1358
+ for (const [name, proc] of Object.entries(procedures)) if (isCRPCHttpProcedure(proc)) result[name] = {
1359
+ path: proc._crpcHttpRoute.path,
1360
+ method: proc._crpcHttpRoute.method
1361
+ };
1362
+ return result;
1363
+ }
1364
+
1365
+ //#endregion
1366
+ //#region src/server/builder.ts
1367
+ /**
1368
+ * CRPC - Convex RPC Builder
1369
+ * A tRPC-style fluent API for Convex functions
1370
+ *
1371
+ * Core library - no project-specific dependencies
1372
+ */
1373
+ z.object({
1374
+ cursor: z.union([z.string(), z.null()]),
1375
+ limit: z.number()
1376
+ });
1377
+ z.object({
1378
+ cursor: z.union([z.string(), z.null()]).optional(),
1379
+ limit: z.number().optional()
1380
+ });
1381
+ /**
1382
+ * Create a middleware factory for building reusable middleware chains
1383
+ *
1384
+ * @example
1385
+ * ```typescript
1386
+ * const loggedIn = c.middleware(({ ctx, next }) => {
1387
+ * if (!ctx.userId) throw new CRPCError({ code: 'UNAUTHORIZED' });
1388
+ * return next({ ctx });
1389
+ * });
1390
+ *
1391
+ * const isAdmin = loggedIn.pipe(({ ctx, next }) => {
1392
+ * if (!ctx.user.isAdmin) throw new CRPCError({ code: 'FORBIDDEN' });
1393
+ * return next({ ctx });
1394
+ * });
1395
+ * ```
1396
+ */
1397
+ function createMiddlewareFactory() {
1398
+ function createMiddlewareInner(middlewares) {
1399
+ return {
1400
+ _middlewares: middlewares,
1401
+ pipe(fn) {
1402
+ return createMiddlewareInner([...middlewares, fn]);
1403
+ }
1404
+ };
1405
+ }
1406
+ return function createMiddleware(fn) {
1407
+ return createMiddlewareInner([fn]);
1408
+ };
1409
+ }
1410
+ /** Execute middleware chain recursively with input access */
1411
+ async function executeMiddlewares(middlewares, ctx, meta, input, getRawInput, index = 0) {
1412
+ if (index >= middlewares.length) return {
1413
+ marker: void 0,
1414
+ ctx,
1415
+ input
1416
+ };
1417
+ const middleware = middlewares[index];
1418
+ let currentInput = input;
1419
+ const next = async (opts) => {
1420
+ const nextCtx = opts?.ctx ?? ctx;
1421
+ const nextInput = opts?.input ?? currentInput;
1422
+ if (opts?.input !== void 0) currentInput = opts.input;
1423
+ return await executeMiddlewares(middlewares, nextCtx, meta, nextInput, getRawInput, index + 1);
1424
+ };
1425
+ return {
1426
+ marker: void 0,
1427
+ ctx: (await middleware({
1428
+ ctx,
1429
+ meta,
1430
+ input,
1431
+ getRawInput,
1432
+ next
1433
+ })).ctx ?? ctx,
1434
+ input: currentInput
1435
+ };
1436
+ }
1437
+ const isPlainObject = (value) => !!value && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
1438
+ const toConvexSafeValue = (value) => {
1439
+ if (value instanceof Date) return value.getTime();
1440
+ if (Array.isArray(value)) {
1441
+ let serialized;
1442
+ for (let index = 0; index < value.length; index += 1) {
1443
+ const nested = value[index];
1444
+ const encoded = toConvexSafeValue(nested);
1445
+ const normalized = encoded === void 0 ? null : encoded;
1446
+ if (normalized !== nested) {
1447
+ if (!serialized) serialized = value.slice();
1448
+ serialized[index] = normalized;
1449
+ }
1450
+ }
1451
+ return serialized ?? value;
1452
+ }
1453
+ if (!isPlainObject(value)) return value;
1454
+ let serialized;
1455
+ for (const key in value) {
1456
+ if (!Object.hasOwn(value, key)) continue;
1457
+ const nested = value[key];
1458
+ const encoded = toConvexSafeValue(nested);
1459
+ if (encoded === void 0) {
1460
+ if (!serialized) serialized = { ...value };
1461
+ delete serialized[key];
1462
+ continue;
1463
+ }
1464
+ if (encoded !== nested) {
1465
+ if (!serialized) serialized = { ...value };
1466
+ serialized[key] = encoded;
1467
+ }
1468
+ }
1469
+ return serialized ?? value;
1470
+ };
1471
+ const wrapTwoArgRunner = (runner, owner) => {
1472
+ if (typeof runner !== "function") return;
1473
+ return (functionReference, args) => Reflect.apply(runner, owner, [functionReference, toConvexSafeValue(args)]);
1474
+ };
1475
+ const wrapSchedulerRunner = (runner, owner) => {
1476
+ if (typeof runner !== "function") return;
1477
+ return (first, functionReference, args) => Reflect.apply(runner, owner, [
1478
+ first,
1479
+ functionReference,
1480
+ toConvexSafeValue(args)
1481
+ ]);
1482
+ };
1483
+ const withConvexSafeRunners = (ctx) => {
1484
+ if (!ctx || typeof ctx !== "object") return ctx;
1485
+ const contextObject = ctx;
1486
+ let changed = false;
1487
+ const wrappedContext = { ...contextObject };
1488
+ const runMutation = wrapTwoArgRunner(contextObject.runMutation, contextObject);
1489
+ if (runMutation) {
1490
+ wrappedContext.runMutation = runMutation;
1491
+ changed = true;
1492
+ }
1493
+ const runQuery = wrapTwoArgRunner(contextObject.runQuery, contextObject);
1494
+ if (runQuery) {
1495
+ wrappedContext.runQuery = runQuery;
1496
+ changed = true;
1497
+ }
1498
+ const runAction = wrapTwoArgRunner(contextObject.runAction, contextObject);
1499
+ if (runAction) {
1500
+ wrappedContext.runAction = runAction;
1501
+ changed = true;
1502
+ }
1503
+ const scheduler = contextObject.scheduler;
1504
+ if (scheduler && typeof scheduler === "object") {
1505
+ const schedulerObject = scheduler;
1506
+ let schedulerChanged = false;
1507
+ const wrappedScheduler = { ...schedulerObject };
1508
+ const runAfter = wrapSchedulerRunner(schedulerObject.runAfter, schedulerObject);
1509
+ if (runAfter) {
1510
+ wrappedScheduler.runAfter = runAfter;
1511
+ schedulerChanged = true;
1512
+ }
1513
+ const runAt = wrapSchedulerRunner(schedulerObject.runAt, schedulerObject);
1514
+ if (runAt) {
1515
+ wrappedScheduler.runAt = runAt;
1516
+ schedulerChanged = true;
1517
+ }
1518
+ if (schedulerChanged) {
1519
+ wrappedContext.scheduler = wrappedScheduler;
1520
+ changed = true;
1521
+ }
1522
+ }
1523
+ return changed ? wrappedContext : contextObject;
1524
+ };
1525
+ const replaceUnencodableOutputTypes = (schema) => {
1526
+ if (schema instanceof z.ZodDate) return z.any();
1527
+ if (schema instanceof z.ZodArray) return z.array(replaceUnencodableOutputTypes(schema.element));
1528
+ if (schema instanceof z.ZodObject) {
1529
+ const nextShape = {};
1530
+ for (const [key, value] of Object.entries(schema.shape)) nextShape[key] = replaceUnencodableOutputTypes(value);
1531
+ return z.object(nextShape);
1532
+ }
1533
+ if (schema instanceof z.ZodUnion) return z.union(schema.options.map((option) => replaceUnencodableOutputTypes(option)));
1534
+ if (schema instanceof z.ZodOptional) return replaceUnencodableOutputTypes(schema.unwrap()).optional();
1535
+ if (schema instanceof z.ZodNullable) return replaceUnencodableOutputTypes(schema.unwrap()).nullable();
1536
+ if (schema instanceof z.ZodRecord) return z.record(schema.keyType, replaceUnencodableOutputTypes(schema.valueType));
1537
+ return schema;
1538
+ };
1539
+ const replaceUnencodableInputTypes = (schema) => {
1540
+ if (schema instanceof z.ZodDate) return z.any();
1541
+ if (schema instanceof z.ZodArray) return z.array(replaceUnencodableInputTypes(schema.element));
1542
+ if (schema instanceof z.ZodObject) {
1543
+ const nextShape = {};
1544
+ for (const [key, value] of Object.entries(schema.shape)) nextShape[key] = replaceUnencodableInputTypes(value);
1545
+ return z.object(nextShape);
1546
+ }
1547
+ if (schema instanceof z.ZodUnion) return z.union(schema.options.map((option) => replaceUnencodableInputTypes(option)));
1548
+ if (schema instanceof z.ZodOptional) return replaceUnencodableInputTypes(schema.unwrap()).optional();
1549
+ if (schema instanceof z.ZodNullable) return replaceUnencodableInputTypes(schema.unwrap()).nullable();
1550
+ if (schema instanceof z.ZodRecord) return z.record(schema.keyType, replaceUnencodableInputTypes(schema.valueType));
1551
+ if (schema instanceof z.ZodDefault) return replaceUnencodableInputTypes(schema.removeDefault());
1552
+ return schema;
1553
+ };
1554
+ const resolveConvexArgsShape = (inputShape) => {
1555
+ if (!inputShape) return;
1556
+ const rawSchema = z.object(inputShape);
1557
+ try {
1558
+ zodToConvex(rawSchema);
1559
+ return inputShape;
1560
+ } catch {
1561
+ const compatibleSchema = replaceUnencodableInputTypes(rawSchema);
1562
+ try {
1563
+ zodToConvex(compatibleSchema);
1564
+ return compatibleSchema.shape;
1565
+ } catch {
1566
+ return Object.fromEntries(Object.keys(inputShape).map((key) => [key, z.any()]));
1567
+ }
1568
+ }
1569
+ };
1570
+ const resolveConvexReturnsSchema = (schema) => {
1571
+ if (!schema) return;
1572
+ try {
1573
+ zodOutputToConvex(schema);
1574
+ return schema;
1575
+ } catch {
1576
+ const compatibleSchema = replaceUnencodableOutputTypes(schema);
1577
+ try {
1578
+ zodOutputToConvex(compatibleSchema);
1579
+ return compatibleSchema;
1580
+ } catch {
1581
+ return;
1582
+ }
1583
+ }
1584
+ };
1585
+ /**
1586
+ * Fluent procedure builder with full type inference
1587
+ *
1588
+ * @typeParam TBaseCtx - Base context type from config
1589
+ * @typeParam TContext - Current context type (starts as TBaseCtx)
1590
+ * @typeParam TContextOverrides - Accumulated context from middleware (starts as UnsetMarker)
1591
+ * @typeParam TInput - Input schema (starts as UnsetMarker)
1592
+ * @typeParam TOutput - Output schema (starts as UnsetMarker)
1593
+ * @typeParam TMeta - Procedure metadata type
1594
+ */
1595
+ var ProcedureBuilder = class {
1596
+ _def;
1597
+ constructor(def) {
1598
+ this._def = def;
1599
+ }
1600
+ /** Add middleware that transforms the context - to be overridden by subclasses */
1601
+ _use(middlewareOrBuilder) {
1602
+ const middlewares = "_middlewares" in middlewareOrBuilder ? middlewareOrBuilder._middlewares : [middlewareOrBuilder];
1603
+ return {
1604
+ ...this._def,
1605
+ middlewares: [...this._def.middlewares, ...middlewares]
1606
+ };
1607
+ }
1608
+ /** Define input schema (chainable - schemas are merged) - to be overridden by subclasses */
1609
+ _input(schema) {
1610
+ return {
1611
+ ...this._def,
1612
+ inputSchemas: [...this._def.inputSchemas, schema.shape]
1613
+ };
1614
+ }
1615
+ /** Define output schema - to be overridden by subclasses */
1616
+ _output(schema) {
1617
+ return {
1618
+ ...this._def,
1619
+ outputSchema: schema
1620
+ };
1621
+ }
1622
+ /** Set procedure metadata (shallow merged when chained) - to be overridden by subclasses */
1623
+ _meta(value) {
1624
+ return {
1625
+ ...this._def,
1626
+ meta: this._def.meta ? {
1627
+ ...this._def.meta,
1628
+ ...value
1629
+ } : value
1630
+ };
1631
+ }
1632
+ /** Merge all input schemas into one */
1633
+ _getMergedInput() {
1634
+ const { inputSchemas } = this._def;
1635
+ if (inputSchemas.length === 0) return;
1636
+ return Object.assign({}, ...inputSchemas);
1637
+ }
1638
+ _createFunction(handler, baseFunction, customFn, fnType) {
1639
+ const { middlewares, outputSchema, meta, functionConfig, isInternal } = this._def;
1640
+ const mergedInput = this._getMergedInput();
1641
+ const inputSchema = mergedInput ? z.object(mergedInput) : void 0;
1642
+ const convexArgs = resolveConvexArgsShape(mergedInput);
1643
+ const customFunction = customFn(baseFunction, customCtx(async (_ctx) => withConvexSafeRunners(await functionConfig.createContext(_ctx))));
1644
+ const returnsSchema = resolveConvexReturnsSchema(outputSchema);
1645
+ const typedReturnsSchema = returnsSchema;
1646
+ const typedArgs = convexArgs ?? {};
1647
+ const shouldValidateOutputWithZod = !!outputSchema && returnsSchema !== outputSchema;
1648
+ const fn = customFunction({
1649
+ args: typedArgs,
1650
+ ...typedReturnsSchema ? { returns: typedReturnsSchema } : {},
1651
+ handler: async (ctx, rawInput) => {
1652
+ const decodedInput = functionConfig.transformer.input.deserialize(rawInput);
1653
+ const parsedInput = inputSchema ? inputSchema.parse(decodedInput) : decodedInput;
1654
+ const getRawInput = async () => parsedInput;
1655
+ try {
1656
+ const result = await executeMiddlewares(middlewares, ctx, meta, parsedInput, getRawInput);
1657
+ const handlerInput = result.input === parsedInput ? parsedInput : functionConfig.transformer.input.deserialize(result.input ?? parsedInput);
1658
+ const output = await handler({
1659
+ ctx: result.ctx,
1660
+ input: handlerInput
1661
+ });
1662
+ const validatedOutput = shouldValidateOutputWithZod ? outputSchema.parse(output) : output;
1663
+ return functionConfig.transformer.output.serialize(validatedOutput);
1664
+ } catch (cause) {
1665
+ const err = toCRPCError(cause);
1666
+ if (err) throw err;
1667
+ throw cause;
1668
+ }
1669
+ }
1670
+ });
1671
+ fn._crpcMeta = {
1672
+ type: fnType,
1673
+ internal: isInternal ?? false,
1674
+ ...meta
1675
+ };
1676
+ fn.__kitcnTransformer = functionConfig.transformer;
1677
+ fn.__kitcnRawHandler = (opts) => handler(opts);
1678
+ return fn;
1679
+ }
1680
+ };
1681
+ /**
1682
+ * Query-specific procedure builder
1683
+ * Only exposes .query() and .internalQuery() methods
1684
+ */
1685
+ var QueryProcedureBuilder = class QueryProcedureBuilder extends ProcedureBuilder {
1686
+ /**
1687
+ * Add middleware that transforms the context
1688
+ * Middleware receives typed input if called after .input(), unknown otherwise
1689
+ * $ContextOverridesOut is inferred from next()
1690
+ */
1691
+ use(middlewareOrBuilder) {
1692
+ return new QueryProcedureBuilder(this._use(middlewareOrBuilder));
1693
+ }
1694
+ /** Set procedure metadata (shallow merged when chained) */
1695
+ meta(value) {
1696
+ return new QueryProcedureBuilder(this._meta(value));
1697
+ }
1698
+ /** Define input schema (chainable - schemas are merged) */
1699
+ input(schema) {
1700
+ return new QueryProcedureBuilder(this._input(schema));
1701
+ }
1702
+ /**
1703
+ * Add pagination input (chainable before .query())
1704
+ *
1705
+ * Creates flat { cursor, limit } input like tRPC and auto-wraps output.
1706
+ * User accesses args.cursor and args.limit directly.
1707
+ *
1708
+ * @param opts.limit - Default/max items per page
1709
+ * @param opts.item - Zod schema for each item in the page array
1710
+ */
1711
+ paginated(opts) {
1712
+ const paginationSchemaWithDefault = z.object({
1713
+ cursor: z.union([z.string(), z.null()]).default(null),
1714
+ limit: z.number().default(opts.limit).transform((n) => Math.min(n, opts.limit))
1715
+ });
1716
+ const outputSchema = z.object({
1717
+ continueCursor: z.union([z.string(), z.null()]),
1718
+ isDone: z.boolean(),
1719
+ page: z.array(opts.item)
1720
+ });
1721
+ return new QueryProcedureBuilder({
1722
+ ...this._def,
1723
+ inputSchemas: [...this._def.inputSchemas, paginationSchemaWithDefault.shape],
1724
+ outputSchema,
1725
+ meta: {
1726
+ ...this._def.meta,
1727
+ limit: opts.limit
1728
+ }
1729
+ });
1730
+ }
1731
+ /** Define output schema */
1732
+ output(schema) {
1733
+ return new QueryProcedureBuilder(this._output(schema));
1734
+ }
1735
+ /** Create a query */
1736
+ query(handler) {
1737
+ return this._createFunction(handler, this._def.functionConfig.base, zCustomQuery, "query");
1738
+ }
1739
+ /** Mark as internal - returns chainable builder using internal function */
1740
+ internal() {
1741
+ const internal = this._def.functionConfig.internal;
1742
+ if (!internal) throw new Error("internalQuery base function not configured");
1743
+ return new QueryProcedureBuilder({
1744
+ ...this._def,
1745
+ isInternal: true,
1746
+ functionConfig: {
1747
+ ...this._def.functionConfig,
1748
+ base: internal
1749
+ }
1750
+ });
1751
+ }
1752
+ };
1753
+ /**
1754
+ * Mutation-specific procedure builder
1755
+ * Only exposes .mutation() and .internalMutation() methods
1756
+ */
1757
+ var MutationProcedureBuilder = class MutationProcedureBuilder extends ProcedureBuilder {
1758
+ /**
1759
+ * Add middleware that transforms the context
1760
+ * Middleware receives typed input if called after .input(), unknown otherwise
1761
+ * $ContextOverridesOut is inferred from next()
1762
+ */
1763
+ use(middlewareOrBuilder) {
1764
+ return new MutationProcedureBuilder(this._use(middlewareOrBuilder));
1765
+ }
1766
+ /** Set procedure metadata (shallow merged when chained) */
1767
+ meta(value) {
1768
+ return new MutationProcedureBuilder(this._meta(value));
1769
+ }
1770
+ /** Define input schema (chainable - schemas are merged) */
1771
+ input(schema) {
1772
+ return new MutationProcedureBuilder(this._input(schema));
1773
+ }
1774
+ /** Define output schema */
1775
+ output(schema) {
1776
+ return new MutationProcedureBuilder(this._output(schema));
1777
+ }
1778
+ /** Create a mutation */
1779
+ mutation(handler) {
1780
+ return this._createFunction(handler, this._def.functionConfig.base, zCustomMutation, "mutation");
1781
+ }
1782
+ /** Mark as internal - returns chainable builder using internal function */
1783
+ internal() {
1784
+ const internal = this._def.functionConfig.internal;
1785
+ if (!internal) throw new Error("internalMutation base function not configured");
1786
+ return new MutationProcedureBuilder({
1787
+ ...this._def,
1788
+ isInternal: true,
1789
+ functionConfig: {
1790
+ ...this._def.functionConfig,
1791
+ base: internal
1792
+ }
1793
+ });
1794
+ }
1795
+ };
1796
+ /**
1797
+ * Action-specific procedure builder
1798
+ * Only exposes .action() and .internalAction() methods
1799
+ */
1800
+ var ActionProcedureBuilder = class ActionProcedureBuilder extends ProcedureBuilder {
1801
+ /** Add middleware that transforms the context - $ContextOverridesOut is inferred from next() */
1802
+ use(middlewareOrBuilder) {
1803
+ return new ActionProcedureBuilder(this._use(middlewareOrBuilder));
1804
+ }
1805
+ /** Set procedure metadata (shallow merged when chained) */
1806
+ meta(value) {
1807
+ return new ActionProcedureBuilder(this._meta(value));
1808
+ }
1809
+ /** Define input schema (chainable - schemas are merged) */
1810
+ input(schema) {
1811
+ return new ActionProcedureBuilder(this._input(schema));
1812
+ }
1813
+ /** Define output schema */
1814
+ output(schema) {
1815
+ return new ActionProcedureBuilder(this._output(schema));
1816
+ }
1817
+ /** Create an action */
1818
+ action(handler) {
1819
+ return this._createFunction(handler, this._def.functionConfig.base, zCustomAction, "action");
1820
+ }
1821
+ /** Mark as internal - returns chainable builder using internal function */
1822
+ internal() {
1823
+ const internal = this._def.functionConfig.internal;
1824
+ if (!internal) throw new Error("internalAction base function not configured");
1825
+ return new ActionProcedureBuilder({
1826
+ ...this._def,
1827
+ isInternal: true,
1828
+ functionConfig: {
1829
+ ...this._def.functionConfig,
1830
+ base: internal
1831
+ }
1832
+ });
1833
+ }
1834
+ };
1835
+ /**
1836
+ * Builder with context configured, ready to create instance
1837
+ */
1838
+ var CRPCBuilderWithContext = class {
1839
+ contextConfig;
1840
+ constructor(contextConfig) {
1841
+ this.contextConfig = contextConfig;
1842
+ }
1843
+ /**
1844
+ * Define the metadata type for procedures (can be called after context)
1845
+ */
1846
+ meta() {
1847
+ return this;
1848
+ }
1849
+ /**
1850
+ * Create the CRPC instance with function builders
1851
+ */
1852
+ create(config) {
1853
+ const { defaultMeta = {}, query = queryGeneric, internalQuery = internalQueryGeneric, mutation = mutationGeneric, internalMutation = internalMutationGeneric, action = actionGeneric, internalAction = internalActionGeneric, httpAction = httpActionGeneric, transformer: transformerOptions } = config ?? {};
1854
+ const transformer = getTransformer(transformerOptions);
1855
+ const mutationCreateContext = this.contextConfig.mutation ?? ((ctx) => ctx);
1856
+ return {
1857
+ query: new QueryProcedureBuilder({
1858
+ middlewares: [],
1859
+ inputSchemas: [],
1860
+ meta: defaultMeta,
1861
+ functionConfig: {
1862
+ base: query,
1863
+ internal: internalQuery,
1864
+ createContext: this.contextConfig.query ?? ((ctx) => ctx),
1865
+ transformer
1866
+ }
1867
+ }),
1868
+ mutation: new MutationProcedureBuilder({
1869
+ middlewares: [],
1870
+ inputSchemas: [],
1871
+ meta: defaultMeta,
1872
+ functionConfig: {
1873
+ base: mutation,
1874
+ internal: internalMutation,
1875
+ createContext: mutationCreateContext,
1876
+ transformer
1877
+ }
1878
+ }),
1879
+ action: new ActionProcedureBuilder({
1880
+ middlewares: [],
1881
+ inputSchemas: [],
1882
+ meta: defaultMeta,
1883
+ functionConfig: {
1884
+ base: action,
1885
+ internal: internalAction,
1886
+ createContext: this.contextConfig.action ?? ((ctx) => ctx),
1887
+ transformer
1888
+ }
1889
+ }),
1890
+ httpAction: createHttpProcedureBuilder({
1891
+ base: httpAction,
1892
+ createContext: this.contextConfig.action ?? ((ctx) => ctx),
1893
+ meta: defaultMeta,
1894
+ transformer: transformerOptions
1895
+ }),
1896
+ middleware: createMiddlewareFactory(),
1897
+ router: createHttpRouterFactory()
1898
+ };
1899
+ }
1900
+ };
1901
+ /**
1902
+ * Builder with meta type configured
1903
+ */
1904
+ var CRPCBuilderWithMeta = class {
1905
+ /**
1906
+ * Configure context creators for each function type
1907
+ */
1908
+ context(config) {
1909
+ return new CRPCBuilderWithContext(config);
1910
+ }
1911
+ /**
1912
+ * Create the CRPC instance directly (uses default passthrough context)
1913
+ */
1914
+ create(config) {
1915
+ return new CRPCBuilderWithContext({}).create(config);
1916
+ }
1917
+ };
1918
+ /**
1919
+ * Initial CRPC builder - configure meta and context
1920
+ */
1921
+ var CRPCBuilder = class {
1922
+ /**
1923
+ * Define the metadata type for procedures
1924
+ */
1925
+ meta() {
1926
+ return new CRPCBuilderWithMeta();
1927
+ }
1928
+ /**
1929
+ * Configure context creators for each function type
1930
+ */
1931
+ context(config) {
1932
+ return new CRPCBuilderWithContext(config);
1933
+ }
1934
+ /**
1935
+ * Create the CRPC instance directly (uses default passthrough context)
1936
+ */
1937
+ create(config) {
1938
+ return new CRPCBuilderWithContext({}).create(config);
1939
+ }
1940
+ };
1941
+ /**
1942
+ * CRPC entry point - tRPC-style object
1943
+ *
1944
+ * @example
1945
+ * ```typescript
1946
+ * // With explicit DataModel type
1947
+ * const c = initCRPC
1948
+ * .dataModel<DataModel>()
1949
+ * .context({...})
1950
+ * .create();
1951
+ *
1952
+ * // Without DataModel (uses GenericDataModel)
1953
+ * const c = initCRPC
1954
+ * .context({...})
1955
+ * .create();
1956
+ * ```
1957
+ */
1958
+ const initCRPC = {
1959
+ dataModel() {
1960
+ return new CRPCBuilder();
1961
+ },
1962
+ meta() {
1963
+ return new CRPCBuilderWithMeta();
1964
+ },
1965
+ context(config) {
1966
+ return new CRPCBuilderWithContext(config);
1967
+ },
1968
+ create(config) {
1969
+ return new CRPCBuilderWithContext({}).create(config);
1970
+ }
1971
+ };
1972
+
1973
+ //#endregion
1974
+ export { zodOutputToConvexFields as A, convexToZodFields as C, zCustomQuery as D, zCustomMutation as E, zodToConvexFields as M, zid as O, convexToZod as S, zCustomAction as T, CRPC_ERROR_CODE_TO_HTTP as _, createMiddlewareFactory as a, isCRPCError as b, createHttpRouter as c, createHttpProcedureBuilder as d, extractPathParams as f, CRPC_ERROR_CODES_BY_KEY as g, CRPCError as h, QueryProcedureBuilder as i, zodToConvex as j, zodOutputToConvex as k, createHttpRouterFactory as l, matchPathParams as m, MutationProcedureBuilder as n, initCRPC as o, handleHttpError as p, ProcedureBuilder as r, HttpRouterWithHono as s, ActionProcedureBuilder as t, extractRouteMap as u, getCRPCErrorFromUnknown as v, withSystemFields as w, toCRPCError as x, getHTTPStatusCodeFromError as y };