kitcn 0.25.4 → 0.25.6

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/dist/orm/index.js CHANGED
@@ -277,7 +277,7 @@ const resolveOrmCapabilities = (capabilities) => {
277
277
  }
278
278
  return resolved;
279
279
  };
280
- const AGGREGATE_SETUP_HINT = "Generated ORM: declare an aggregateIndex(...)/rankIndex(...) in your schema and rerun `kitcn codegen`, which registers the capability in <functionsDir>/generated/server.ts. Hand-written ORM: import { aggregateCapability } from 'kitcn/orm/aggregate-index' and pass createOrm({ schema, capabilities: [aggregateCapability()] }).";
280
+ const AGGREGATE_SETUP_HINT = "Generated ORM: `kitcn codegen` registers the capability in <functionsDir>/generated/server.ts from the aggregateIndex(...)/rankIndex(...) declarations in your schema if you are seeing this from that generated file, delete it and run `kitcn codegen` again. Hand-written ORM: import { aggregateCapability } from 'kitcn/orm/aggregate-index' and pass createOrm({ schema, capabilities: [aggregateCapability()] }).";
281
281
  const missingAggregateCapabilityError = (usage) => /* @__PURE__ */ new Error(`${usage} requires the aggregate capability. ${AGGREGATE_SETUP_HINT}`);
282
282
  const requireAggregateCapability = (capabilities, usage) => {
283
283
  const aggregate = capabilities?.aggregate;
@@ -286,7 +286,7 @@ const requireAggregateCapability = (capabilities, usage) => {
286
286
  };
287
287
  const requireMigrationCapability = (capabilities, usage) => {
288
288
  const migrations = capabilities?.migrations;
289
- if (!migrations) throw new Error(`${usage} requires the migration capability. Generated ORM: add a migration under <functionsDir>/migrations and rerun \`kitcn codegen\`, which registers the capability in <functionsDir>/generated/server.ts. Hand-written ORM: import { migrationCapability } from 'kitcn/orm/migrations' and pass createOrm({ schema, capabilities: [migrationCapability()] }).`);
289
+ if (!migrations) throw new Error(`${usage} requires the migration capability. Generated ORM: \`kitcn codegen\` registers the capability in <functionsDir>/generated/server.ts once <functionsDir>/migrations/manifest.ts exists — if you are seeing this from that generated file, delete it and run \`kitcn codegen\` again. Hand-written ORM: import { migrationCapability } from 'kitcn/orm/migrations' and pass createOrm({ schema, capabilities: [migrationCapability()] }).`);
290
290
  return migrations;
291
291
  };
292
292
 
@@ -1,3 +1,3 @@
1
1
  import { C as MigrationTableName, D as defineMigrationSet, E as defineMigration, O as detectMigrationDrift, S as MigrationStep, T as buildMigrationPlan, _ as MigrationMigrateOne, a as MigrationCancelArgs, b as MigrationSet, c as MigrationStatusArgs, d as MigrationDefinition, f as MigrationDirection, g as MigrationManifestEntry, h as MigrationDriftIssue, l as createMigrationHandlers, m as MigrationDocContext, o as MigrationRunArgs, p as MigrationDoc, s as MigrationRunChunkArgs, u as MigrationAppliedState, v as MigrationPlan, w as MigrationWriteMode, x as MigrationStateMap, y as MigrationRunStatus } from "../../capabilities-DtDfpdcH.js";
2
- import { Ct as migrationCapability, dt as MIGRATION_STORAGE_TABLE_NAMES, ft as injectMigrationStorageTables, lt as MIGRATION_RUN_TABLE, mt as migrationStorageTables, pt as migrationExtension, ut as MIGRATION_STATE_TABLE } from "../../where-clause-compiler-CCMtAIdx.js";
2
+ import { Ct as migrationCapability, dt as MIGRATION_STORAGE_TABLE_NAMES, ft as injectMigrationStorageTables, lt as MIGRATION_RUN_TABLE, mt as migrationStorageTables, pt as migrationExtension, ut as MIGRATION_STATE_TABLE } from "../../where-clause-compiler-eTewPUGq.js";
3
3
  export { MIGRATION_RUN_TABLE, MIGRATION_STATE_TABLE, MIGRATION_STORAGE_TABLE_NAMES, type MigrationAppliedState, type MigrationCancelArgs, type MigrationDefinition, type MigrationDirection, type MigrationDoc, type MigrationDocContext, type MigrationDriftIssue, type MigrationManifestEntry, type MigrationMigrateOne, type MigrationPlan, type MigrationRunArgs, type MigrationRunChunkArgs, type MigrationRunStatus, type MigrationSet, type MigrationStateMap, type MigrationStatusArgs, type MigrationStep, type MigrationTableName, type MigrationWriteMode, buildMigrationPlan, createMigrationHandlers, defineMigration, defineMigrationSet, detectMigrationDrift, injectMigrationStorageTables, migrationCapability, migrationExtension, migrationStorageTables };
@@ -1,3 +1,3 @@
1
- import { n as resolvePluginOptions, t as definePlugin } from "../middleware-DIj-bwVi.js";
1
+ import { n as resolvePluginOptions, t as definePlugin } from "../middleware-BvnabcNq.js";
2
2
 
3
3
  export { definePlugin, resolvePluginOptions };
@@ -1,5 +1,5 @@
1
1
  import { i as decodeWire, o as encodeWire } from "./transformer-D8wO-kEj.js";
2
- import { _ as CRPCError } from "./builder-DoeyW4Vq.js";
2
+ import { _ as CRPCError } from "./builder-CsAw-DK8.js";
3
3
  import * as z$1 from "zod";
4
4
 
5
5
  //#region src/server/env.ts
@@ -1,6 +1,6 @@
1
1
  import { u as requireMutationCtx } from "../api-entry-CkDpGYVg.js";
2
- import { _ as CRPCError } from "../builder-DoeyW4Vq.js";
3
- import { t as definePlugin } from "../middleware-DIj-bwVi.js";
2
+ import { _ as CRPCError } from "../builder-CsAw-DK8.js";
3
+ import { t as definePlugin } from "../middleware-BvnabcNq.js";
4
4
  import { v } from "convex/values";
5
5
  import { mutationGeneric, queryGeneric } from "convex/server";
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { a as isMutationCtx, c as isSchedulerCtx, d as requireQueryCtx, f as requireRunMutationCtx, i as isActionCtx, l as requireActionCtx, n as createGeneratedFunctionReference, o as isQueryCtx, p as requireSchedulerCtx, r as getGeneratedValue, s as isRunMutationCtx, t as createApiLeaf, u as requireMutationCtx } from "../api-entry-CkDpGYVg.js";
2
2
  import { n as createLazyCaller, r as createServerCaller, t as createCallerFactory } from "../caller-factory-Dd3H7j3V.js";
3
- import { A as zid, C as toCRPCError, D as zCustomAction, E as withSystemFields, M as zodOutputToConvexFields, N as zodToConvex, O as zCustomMutation, P as zodToConvexFields, S as isCRPCError, T as convexToZodFields, _ as CRPCError, a as createMiddlewareFactory, b as getCRPCErrorFromUnknown, c as registerProcedureNameLookup, d as createHttpRouterFactory, f as extractRouteMap, g as matchPathParams, h as handleHttpError, i as QueryProcedureBuilder, j as zodOutputToConvex, k as zCustomQuery, l as HttpRouterWithHono, m as extractPathParams, n as MutationProcedureBuilder, o as initCRPC, p as createHttpProcedureBuilder, r as ProcedureBuilder, s as inferProcedureNameFromCallsite, t as ActionProcedureBuilder, u as createHttpRouter, v as CRPC_ERROR_CODES_BY_KEY, w as convexToZod, x as getHTTPStatusCodeFromError, y as CRPC_ERROR_CODE_TO_HTTP } from "../builder-DoeyW4Vq.js";
4
- import { a as createProcedureHandlerFactory, c as typedProcedureResolver, i as createProcedureCallerFactory, l as createEnv, n as createGenericCallerFactory, o as defineProcedure, r as createGenericHandlerFactory, s as getGeneratedFunctionReference, t as createGeneratedRegistryRuntime } from "../procedure-caller-Dxae9DW5.js";
3
+ import { A as zid, C as toCRPCError, D as zCustomAction, E as withSystemFields, M as zodOutputToConvexFields, N as zodToConvex, O as zCustomMutation, P as zodToConvexFields, S as isCRPCError, T as convexToZodFields, _ as CRPCError, a as createMiddlewareFactory, b as getCRPCErrorFromUnknown, c as registerProcedureNameLookup, d as createHttpRouterFactory, f as extractRouteMap, g as matchPathParams, h as handleHttpError, i as QueryProcedureBuilder, j as zodOutputToConvex, k as zCustomQuery, l as HttpRouterWithHono, m as extractPathParams, n as MutationProcedureBuilder, o as initCRPC, p as createHttpProcedureBuilder, r as ProcedureBuilder, s as inferProcedureNameFromCallsite, t as ActionProcedureBuilder, u as createHttpRouter, v as CRPC_ERROR_CODES_BY_KEY, w as convexToZod, x as getHTTPStatusCodeFromError, y as CRPC_ERROR_CODE_TO_HTTP } from "../builder-CsAw-DK8.js";
4
+ import { a as createProcedureHandlerFactory, c as typedProcedureResolver, i as createProcedureCallerFactory, l as createEnv, n as createGenericCallerFactory, o as defineProcedure, r as createGenericHandlerFactory, s as getGeneratedFunctionReference, t as createGeneratedRegistryRuntime } from "../procedure-caller-BR-Wb0si.js";
5
5
 
6
6
  export { ActionProcedureBuilder, CRPCError, CRPC_ERROR_CODES_BY_KEY, CRPC_ERROR_CODE_TO_HTTP, HttpRouterWithHono, MutationProcedureBuilder, ProcedureBuilder, QueryProcedureBuilder, convexToZod, convexToZodFields, createApiLeaf, createCallerFactory, createEnv, createGeneratedFunctionReference, createGeneratedRegistryRuntime, createGenericCallerFactory, createGenericHandlerFactory, createHttpProcedureBuilder, createHttpRouter, createHttpRouterFactory, createLazyCaller, createMiddlewareFactory, createProcedureCallerFactory, createProcedureHandlerFactory, createServerCaller, defineProcedure, extractPathParams, extractRouteMap, getCRPCErrorFromUnknown, getGeneratedFunctionReference, getGeneratedValue, getHTTPStatusCodeFromError, handleHttpError, inferProcedureNameFromCallsite, initCRPC, isActionCtx, isCRPCError, isMutationCtx, isQueryCtx, isRunMutationCtx, isSchedulerCtx, matchPathParams, registerProcedureNameLookup, requireActionCtx, requireMutationCtx, requireQueryCtx, requireRunMutationCtx, requireSchedulerCtx, toCRPCError, typedProcedureResolver, withSystemFields, zCustomAction, zCustomMutation, zCustomQuery, zid, zodOutputToConvex, zodOutputToConvexFields, zodToConvex, zodToConvexFields };
package/dist/watcher.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as generateMeta, d as PARSE_SNAPSHOT_SUFFIX, i as resolveConfiguredBackend, n as withLocalCodegenEnv, o as getConvexConfig, r as loadCliConfig, u as logger } from "./local-env-Dkh4a_BK.mjs";
2
+ import { a as generateMeta, d as PARSE_SNAPSHOT_SUFFIX, i as resolveConfiguredBackend, n as withLocalCodegenEnv, o as getConvexConfig, r as loadCliConfig, u as logger } from "./local-env-CiPqNKS_.mjs";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
 
@@ -111,6 +111,15 @@ declare const migrationStorageTables: {
111
111
  fieldName: "cursor";
112
112
  };
113
113
  };
114
+ direction: ConvexTextBuilderInitial<""> & {
115
+ _: {
116
+ tableName: "migration_state";
117
+ };
118
+ } & {
119
+ _: {
120
+ fieldName: "direction";
121
+ };
122
+ };
114
123
  migrationId: ConvexTextBuilderInitial<""> & {
115
124
  _: {
116
125
  notNull: true;
@@ -150,15 +159,6 @@ declare const migrationStorageTables: {
150
159
  fieldName: "applied";
151
160
  };
152
161
  };
153
- direction: ConvexTextBuilderInitial<""> & {
154
- _: {
155
- tableName: "migration_state";
156
- };
157
- } & {
158
- _: {
159
- fieldName: "direction";
160
- };
161
- };
162
162
  runId: ConvexTextBuilderInitial<""> & {
163
163
  _: {
164
164
  tableName: "migration_state";
@@ -1008,7 +1008,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1008
1008
  readonly aggregate_bucket: ConvexTableWithColumns<{
1009
1009
  name: "aggregate_bucket";
1010
1010
  columns: {
1011
- count: ConvexNumberBuilderInitial<""> & {
1011
+ updatedAt: ConvexNumberBuilderInitial<""> & {
1012
1012
  _: {
1013
1013
  notNull: true;
1014
1014
  };
@@ -1018,10 +1018,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1018
1018
  };
1019
1019
  } & {
1020
1020
  _: {
1021
- fieldName: "count";
1021
+ fieldName: "updatedAt";
1022
1022
  };
1023
1023
  };
1024
- updatedAt: ConvexNumberBuilderInitial<""> & {
1024
+ count: ConvexNumberBuilderInitial<""> & {
1025
1025
  _: {
1026
1026
  notNull: true;
1027
1027
  };
@@ -1031,7 +1031,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1031
1031
  };
1032
1032
  } & {
1033
1033
  _: {
1034
- fieldName: "updatedAt";
1034
+ fieldName: "count";
1035
1035
  };
1036
1036
  };
1037
1037
  indexName: ConvexTextBuilderInitial<""> & {
@@ -1133,7 +1133,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1133
1133
  readonly aggregate_member: ConvexTableWithColumns<{
1134
1134
  name: "aggregate_member";
1135
1135
  columns: {
1136
- updatedAt: ConvexNumberBuilderInitial<""> & {
1136
+ kind: ConvexTextBuilderInitial<""> & {
1137
1137
  _: {
1138
1138
  notNull: true;
1139
1139
  };
@@ -1143,10 +1143,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1143
1143
  };
1144
1144
  } & {
1145
1145
  _: {
1146
- fieldName: "updatedAt";
1146
+ fieldName: "kind";
1147
1147
  };
1148
1148
  };
1149
- kind: ConvexTextBuilderInitial<""> & {
1149
+ updatedAt: ConvexNumberBuilderInitial<""> & {
1150
1150
  _: {
1151
1151
  notNull: true;
1152
1152
  };
@@ -1156,7 +1156,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1156
1156
  };
1157
1157
  } & {
1158
1158
  _: {
1159
- fieldName: "kind";
1159
+ fieldName: "updatedAt";
1160
1160
  };
1161
1161
  };
1162
1162
  indexName: ConvexTextBuilderInitial<""> & {
@@ -1323,7 +1323,11 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1323
1323
  readonly aggregate_extrema: ConvexTableWithColumns<{
1324
1324
  name: "aggregate_extrema";
1325
1325
  columns: {
1326
- count: ConvexNumberBuilderInitial<""> & {
1326
+ value: ConvexCustomBuilderInitial<"", convex_values0.VAny<any, "required", string>> & {
1327
+ _: {
1328
+ $type: convex_values0.Value;
1329
+ };
1330
+ } & {
1327
1331
  _: {
1328
1332
  notNull: true;
1329
1333
  };
@@ -1333,7 +1337,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1333
1337
  };
1334
1338
  } & {
1335
1339
  _: {
1336
- fieldName: "count";
1340
+ fieldName: "value";
1337
1341
  };
1338
1342
  };
1339
1343
  updatedAt: ConvexNumberBuilderInitial<""> & {
@@ -1349,11 +1353,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1349
1353
  fieldName: "updatedAt";
1350
1354
  };
1351
1355
  };
1352
- value: ConvexCustomBuilderInitial<"", convex_values0.VAny<any, "required", string>> & {
1353
- _: {
1354
- $type: convex_values0.Value;
1355
- };
1356
- } & {
1356
+ count: ConvexNumberBuilderInitial<""> & {
1357
1357
  _: {
1358
1358
  notNull: true;
1359
1359
  };
@@ -1363,7 +1363,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1363
1363
  };
1364
1364
  } & {
1365
1365
  _: {
1366
- fieldName: "value";
1366
+ fieldName: "count";
1367
1367
  };
1368
1368
  };
1369
1369
  indexName: ConvexTextBuilderInitial<""> & {
@@ -1589,6 +1589,19 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1589
1589
  fieldName: "status";
1590
1590
  };
1591
1591
  };
1592
+ kind: ConvexTextBuilderInitial<""> & {
1593
+ _: {
1594
+ notNull: true;
1595
+ };
1596
+ } & {
1597
+ _: {
1598
+ tableName: "aggregate_state";
1599
+ };
1600
+ } & {
1601
+ _: {
1602
+ fieldName: "kind";
1603
+ };
1604
+ };
1592
1605
  cursor: ConvexTextBuilderInitial<""> & {
1593
1606
  _: {
1594
1607
  tableName: "aggregate_state";
@@ -1655,19 +1668,6 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1655
1668
  fieldName: "lastError";
1656
1669
  };
1657
1670
  };
1658
- kind: ConvexTextBuilderInitial<""> & {
1659
- _: {
1660
- notNull: true;
1661
- };
1662
- } & {
1663
- _: {
1664
- tableName: "aggregate_state";
1665
- };
1666
- } & {
1667
- _: {
1668
- fieldName: "kind";
1669
- };
1670
- };
1671
1671
  indexName: ConvexTextBuilderInitial<""> & {
1672
1672
  _: {
1673
1673
  notNull: true;
@@ -1753,6 +1753,15 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1753
1753
  fieldName: "cursor";
1754
1754
  };
1755
1755
  };
1756
+ direction: ConvexTextBuilderInitial<""> & {
1757
+ _: {
1758
+ tableName: "migration_state";
1759
+ };
1760
+ } & {
1761
+ _: {
1762
+ fieldName: "direction";
1763
+ };
1764
+ };
1756
1765
  migrationId: ConvexTextBuilderInitial<""> & {
1757
1766
  _: {
1758
1767
  notNull: true;
@@ -1792,15 +1801,6 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1792
1801
  fieldName: "applied";
1793
1802
  };
1794
1803
  };
1795
- direction: ConvexTextBuilderInitial<""> & {
1796
- _: {
1797
- tableName: "migration_state";
1798
- };
1799
- } & {
1800
- _: {
1801
- fieldName: "direction";
1802
- };
1803
- };
1804
1804
  runId: ConvexTextBuilderInitial<""> & {
1805
1805
  _: {
1806
1806
  tableName: "migration_state";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kitcn",
3
- "version": "0.25.4",
3
+ "version": "0.25.6",
4
4
  "description": "kitcn - React Query integration and CLI tools for Convex",
5
5
  "keywords": [
6
6
  "convex",
@@ -47,6 +47,7 @@
47
47
  "intent": "./bin/intent.js"
48
48
  },
49
49
  "files": [
50
+ "CHANGELOG.md",
50
51
  "dist",
51
52
  "skills",
52
53
  "bin",
@@ -32,34 +32,35 @@ Default assumption:
32
32
  Only remember these non-parity deltas:
33
33
  1. Procedure input root must be `z.object(...)` (no primitive root args).
34
34
  2. No `z.void()` outputs; omit `.output(...)` for no-value mutations.
35
- 3. Stacked `.input(...)` calls merge input shapes.
36
- 4. `.paginated({ limit, item })` must be before `.query()` and auto-adds `input.cursor` + `input.limit`, output `{ page, continueCursor, isDone }`.
37
- 5. Metadata is codegen’d onto `@convex/api` leaves (`api.namespace.fn.meta`) so never put secrets in `.meta(...)`; chaining `.meta(...)` is shallow merge and supports `defaultMeta`.
38
- 6. Auth metadata drives client behavior: `auth: "optional"` waits for auth load then runs, `auth: "required"` waits then skips when logged out.
39
- 7. `ctx.orm` enforces constraints + RLS; `ctx.db` bypasses them.
40
- 8. Non-paginated `findMany()` must be explicitly sized (`limit`, cursor mode, schema `defaultLimit`, or explicit `allowFullScan`).
41
- 9. Predicate `where` requires explicit `.withIndex(...)`; no implicit full scan fallback.
42
- 10. Cursor pagination uses the first `orderBy` field; index that field for stable paging.
43
- 11. `maxScan` applies to cursor mode only; `allowFullScan` is for non-cursor full-scan opt-in.
44
- 12. String operators / `columns` projection / many-relation subfilters can run post-fetch; bound result size early.
45
- 13. Search mode is relevance-ordered and does not support `orderBy`; vector mode has stricter limits (no cursor/offset/top-level where/order).
46
- 14. Update/delete without `where` throws unless `allowFullScan()`.
47
- 15. `count()`, `aggregate()`, and `groupBy()` require a matching `aggregateIndex`. Use `groupBy({ by, _count, _sum })` instead of multiple `.count()` calls or `findMany` + manual JS grouping. Every `by` field must be finite-constrained (`eq`/`in`/`isNull`) in `where`. See `references/features/aggregates.md`.
48
- 16. cRPC React queries are real-time by default (`subscribe: true`); never use `queryClient.invalidateQueries` for these subscribed paths.
49
- 17. In RSC, `prefetch` hydrates client, `caller` is server-only and not hydrated, `preloadQuery` hydrates but can cause stale split ownership if also rendered client-side.
50
- 18. Better Auth Next.js shortcut is `convexBetterAuth(...)`; generic server-only shortcut is `createCallerFactory(...)`.
51
- 19. On the kitcn auth client path, use `createAuthMutations(authClient)` wrappers so logout unsubscribes auth queries before sign out. Raw Convex preset keeps a smaller plain `authClient`.
52
- 20. **NEVER** use `ctx.runQuery`/`ctx.runMutation`/`ctx.runAction` directly for module-to-module calls. Use the generated runtime helpers from `convex/functions/generated/<module>.runtime`.
53
- 21. **`create<Module>Handler(ctx)`** is the default in queries/mutations: zero overhead, query/mutation ctx only, and no redundant validation or middleware.
54
- 22. **`create<Module>Caller(ctx)`** is for actions and HTTP routes. Action procedures live under `caller.actions.*`; scheduling lives under `caller.schedule.now|after|at|cancel`. Use `requireActionCtx(ctx)` only for true `ActionCtx` callbacks; use `requireSchedulerCtx(ctx)` when mutation or action contexts can schedule. Each caller/handler eagerly loads its module, so split large modules.
55
- 23. API types (`Api`, `ApiInputs`, `ApiOutputs`, `Select`, `Insert`, `TableName`) import from `@convex/api` no manual `inferApiInputs<typeof api>`.
56
- 24. HTTP router must export as `httpRouter` (not `appRouter`) for codegen.
57
- 25. Server wiring imports come from `convex/functions/generated/` directory: `getAuth`, `defineAuth` from `generated/auth`; `initCRPC`, `QueryCtx`, `MutationCtx`, `OrmCtx` from `generated/server`; `create<Module>Caller`, `create<Module>Handler` from `generated/<module>.runtime`. No manual `convex/lib/orm.ts`.
58
- 26. `defineAuth(() => ({ ...options, triggers }))` replaces split `getAuthOptions` + `authTriggers`. Trigger callbacks are doc-first: `beforeCreate(data)`, `onCreate(doc)`, `onUpdate(newDoc, oldDoc)` no `ctx` first param.
59
- 27. Internal auth functions at `internal.generated.*` (not `internal.auth.*`).
60
- 28. Async mutation batching is the default (codegen wires it). Customize per call: `execute({ batchSize, delayMs })`. Opt into sync: `execute({ mode: 'sync' })` or `defineSchema(..., { defaults: { mutationExecutionMode: 'sync' } })`. Relevant defaults: `mutationBatchSize`, `mutationLeafBatchSize`, `mutationMaxRows`, `mutationScheduleCallCap`.
61
- 29. Polymorphic unions are schema-first: use `actionType: discriminator({ variants, as? })` in `convexTable(...)`. Query config does not include a `polymorphic` option. Writes stay flat; reads synthesize nested `details` (or custom alias). Use `withVariants: true` to auto-load all `one()` relations on discriminator tables.
62
- 30. Do not add manual ORM mutation batching loops in app/plugin code by default. Convex runtime batching already handles mutation execution. Prefer set-based deletes/updates over per-row loops. Only add explicit chunking when batching external side effects (for example Resend API calls) or bounded cleanup sweeps.
35
+ 3. `.output(...)` parses the handler's value as-is and substitutes nothing: a handler must return the schema's *input* type, so `z.string().nullable()` needs an explicit `null` (`?? null`), not `undefined`. Model absent values as `.nullable()`, never a top-level `.optional()` — Convex wires `undefined` as `null` and cannot express top-level optionality, so `.output(z.string().optional())` publishes `v.string()` and the deployment rejects the `null` whenever the handler returns `undefined`. `.optional()` inside an object is fine. The low-level `returns:` option on `zCustomQuery`/`zCustomMutation`/`zCustomAction` differs — it substitutes `null` for `undefined` before parsing.
36
+ 4. Stacked `.input(...)` calls merge input shapes.
37
+ 5. `.paginated({ limit, item })` must be before `.query()` and auto-adds `input.cursor` + `input.limit`, output `{ page, continueCursor, isDone }`.
38
+ 6. Metadata is codegen’d onto `@convex/api` leaves (`api.namespace.fn.meta`) so never put secrets in `.meta(...)`; chaining `.meta(...)` is shallow merge and supports `defaultMeta`.
39
+ 7. Auth metadata drives client behavior: `auth: "optional"` waits for auth load then runs, `auth: "required"` waits then skips when logged out.
40
+ 8. `ctx.orm` enforces constraints + RLS; `ctx.db` bypasses them.
41
+ 9. Non-paginated `findMany()` must be explicitly sized (`limit`, cursor mode, schema `defaultLimit`, or explicit `allowFullScan`).
42
+ 10. Predicate `where` requires explicit `.withIndex(...)`; no implicit full scan fallback.
43
+ 11. Cursor pagination uses the first `orderBy` field; index that field for stable paging.
44
+ 12. `maxScan` applies to cursor mode only; `allowFullScan` is for non-cursor full-scan opt-in.
45
+ 13. String operators / `columns` projection / many-relation subfilters can run post-fetch; bound result size early.
46
+ 14. Search mode is relevance-ordered and does not support `orderBy`; vector mode has stricter limits (no cursor/offset/top-level where/order).
47
+ 15. Update/delete without `where` throws unless `allowFullScan()`.
48
+ 16. `count()`, `aggregate()`, and `groupBy()` require a matching `aggregateIndex`. Use `groupBy({ by, _count, _sum })` instead of multiple `.count()` calls or `findMany` + manual JS grouping. Every `by` field must be finite-constrained (`eq`/`in`/`isNull`) in `where`. See `references/features/aggregates.md`.
49
+ 17. cRPC React queries are real-time by default (`subscribe: true`); never use `queryClient.invalidateQueries` for these subscribed paths.
50
+ 18. In RSC, `prefetch` hydrates client, `caller` is server-only and not hydrated, `preloadQuery` hydrates but can cause stale split ownership if also rendered client-side.
51
+ 19. Better Auth Next.js shortcut is `convexBetterAuth(...)`; generic server-only shortcut is `createCallerFactory(...)`.
52
+ 20. On the kitcn auth client path, use `createAuthMutations(authClient)` wrappers so logout unsubscribes auth queries before sign out. Raw Convex preset keeps a smaller plain `authClient`.
53
+ 21. **NEVER** use `ctx.runQuery`/`ctx.runMutation`/`ctx.runAction` directly for module-to-module calls. Use the generated runtime helpers from `convex/functions/generated/<module>.runtime`.
54
+ 22. **`create<Module>Handler(ctx)`** is the default in queries/mutations: zero overhead, query/mutation ctx only, and no redundant validation or middleware.
55
+ 23. **`create<Module>Caller(ctx)`** is for actions and HTTP routes. Action procedures live under `caller.actions.*`; scheduling lives under `caller.schedule.now|after|at|cancel`. Use `requireActionCtx(ctx)` only for true `ActionCtx` callbacks; use `requireSchedulerCtx(ctx)` when mutation or action contexts can schedule. Each caller/handler eagerly loads its module, so split large modules.
56
+ 24. API types (`Api`, `ApiInputs`, `ApiOutputs`, `Select`, `Insert`, `TableName`) import from `@convex/api` — no manual `inferApiInputs<typeof api>`.
57
+ 25. HTTP router must export as `httpRouter` (not `appRouter`) for codegen.
58
+ 26. Server wiring imports come from `convex/functions/generated/` directory: `getAuth`, `defineAuth` from `generated/auth`; `initCRPC`, `QueryCtx`, `MutationCtx`, `OrmCtx` from `generated/server`; `create<Module>Caller`, `create<Module>Handler` from `generated/<module>.runtime`. No manual `convex/lib/orm.ts`.
59
+ 27. `defineAuth(() => ({ ...options, triggers }))` replaces split `getAuthOptions` + `authTriggers`. Trigger callbacks are doc-first: `beforeCreate(data)`, `onCreate(doc)`, `onUpdate(newDoc, oldDoc)` — no `ctx` first param.
60
+ 28. Internal auth functions at `internal.generated.*` (not `internal.auth.*`).
61
+ 29. Async mutation batching is the default (codegen wires it). Customize per call: `execute({ batchSize, delayMs })`. Opt into sync: `execute({ mode: 'sync' })` or `defineSchema(..., { defaults: { mutationExecutionMode: 'sync' } })`. Relevant defaults: `mutationBatchSize`, `mutationLeafBatchSize`, `mutationMaxRows`, `mutationScheduleCallCap`.
62
+ 30. Polymorphic unions are schema-first: use `actionType: discriminator({ variants, as? })` in `convexTable(...)`. Query config does not include a `polymorphic` option. Writes stay flat; reads synthesize nested `details` (or custom alias). Use `withVariants: true` to auto-load all `one()` relations on discriminator tables.
63
+ 31. Do not add manual ORM mutation batching loops in app/plugin code by default. Convex runtime batching already handles mutation execution. Prefer set-based deletes/updates over per-row loops. Only add explicit chunking when batching external side effects (for example Resend API calls) or bounded cleanup sweeps.
63
64
  ## Directory Boundary
64
65
  Use `references/setup/` when the task needs:
65
66
  1. Project/file structure setup → `setup/index.md` + `setup/server.md`
@@ -314,7 +315,10 @@ Use this map consistently:
314
315
  4. `NOT_FOUND`: missing or inaccessible resource.
315
316
  5. `CONFLICT`: duplicate or conflicting write.
316
317
  6. `TOO_MANY_REQUESTS`: rate limit.
317
- 7. `INTERNAL_SERVER_ERROR`: unexpected failures only.
318
+ 7. `INTERNAL_SERVER_ERROR`: unexpected failures only. cRPC also raises it for a
319
+ failed `.output(...)` parse, with message `Output validation failed` and
320
+ sanitized structural Zod issues in `error.data.ZodError`. Custom issue
321
+ messages and fields stay server-side because they can contain handler output.
318
322
  8. Add small custom `data` payloads on `CRPCError` when the client needs
319
323
  domain metadata like conflicting ids. Read them on the client from
320
324
  `error.data`.
@@ -454,6 +458,7 @@ Before calling a feature done:
454
458
  | Infinite list with TanStack native hook directly | Use `useInfiniteQuery` from `kitcn/react` |
455
459
  | Primitive root input (`z.string()`) | Use root `z.object(...)` input schema |
456
460
  | Returning nothing with `z.void()` | Omit explicit output |
461
+ | Returning a possibly-missing lookup under `.output(...nullable())` | Coalesce it: `?? null`. `.output(...)` substitutes nothing for `undefined` |
457
462
  | Manual pagination wrappers for infinite endpoints | Use `.paginated({ limit, item })` |
458
463
  | Synthetic Convex IDs in tests (`"missing-id"`) | Use inserted IDs or semantic lookup keys |
459
464
  | Aggregates disabled but helper/config still present | Remove aggregate helper + `defineTriggers` handlers + app config together |
@@ -141,6 +141,7 @@ bunx kitcn add resend
141
141
  - `convex/functions/schema.ts`
142
142
  - `convex/functions/http.ts`
143
143
  - `convex/functions/generated/server.ts`
144
+ - `convex/functions/generated/procedure-names.gen.ts`
144
145
  - `convex/lib/crpc.ts`
145
146
  - `convex/lib/get-env.ts`
146
147
  - `convex/shared/api.ts`
@@ -218,6 +218,15 @@ This generates:
218
218
  - `convex/functions/generated/` directory
219
219
  - `convex/shared/api.ts`
220
220
 
221
+ Everything under `convex/functions/generated/` is codegen-owned. Never edit it,
222
+ and never hand-repair it. `convex/functions/generated/server.ts` is rewritten
223
+ from the schema before codegen reads any app module.
224
+
225
+ `convex/functions/generated/procedure-names.gen.ts` holds the procedure-name
226
+ lookup. It is the only generated output that depends on scanning procedures, so
227
+ only default-scope runs rebuild it; `kitcn codegen --scope auth|orm` preserves
228
+ the recorded lookup.
229
+
221
230
  Agent command policy:
222
231
 
223
232
  1. Default to `bunx kitcn dev`.