kitcn 0.25.3 → 0.25.5

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.
@@ -1,5 +1,5 @@
1
1
  import { Bn as ConvexTextBuilderInitial, Xt as ConvexTableWithColumns } from "../capabilities-DtDfpdcH.js";
2
- import { C as ConvexNumberBuilderInitial, E as ConvexIdBuilderInitial, N as ConvexCustomBuilderInitial } from "../where-clause-compiler-Bke7ULoY.js";
2
+ import { C as ConvexNumberBuilderInitial, E as ConvexIdBuilderInitial, N as ConvexCustomBuilderInitial } from "../where-clause-compiler-DlRUDuMx.js";
3
3
  import * as convex_values0 from "convex/values";
4
4
  import { GenericId, Infer, Value } from "convex/values";
5
5
  import { DocumentByName, GenericDataModel, GenericDatabaseReader, GenericDatabaseWriter, TableNamesInDataModel } from "convex/server";
@@ -1,2 +1,2 @@
1
- import { S as defineAuth, _ as GenericAuthBeforeResult, b as GenericAuthTriggerHandlers, g as BetterAuthOptionsWithoutDatabase, i as getGeneratedAuthDisabledReason, n as GeneratedAuthDisabledReasonKind, r as createDisabledAuthRuntime, t as AuthRuntime, v as GenericAuthDefinition, x as GenericAuthTriggers, y as GenericAuthTriggerChange } from "../../generated-contract-disabled-SzH57bhp.js";
1
+ import { S as defineAuth, _ as GenericAuthBeforeResult, b as GenericAuthTriggerHandlers, g as BetterAuthOptionsWithoutDatabase, i as getGeneratedAuthDisabledReason, n as GeneratedAuthDisabledReasonKind, r as createDisabledAuthRuntime, t as AuthRuntime, v as GenericAuthDefinition, x as GenericAuthTriggers, y as GenericAuthTriggerChange } from "../../generated-contract-disabled-B3ByVG3_.js";
2
2
  export { type AuthRuntime, BetterAuthOptionsWithoutDatabase, type GeneratedAuthDisabledReasonKind, GenericAuthBeforeResult, GenericAuthDefinition, GenericAuthTriggerChange, GenericAuthTriggerHandlers, GenericAuthTriggers, createDisabledAuthRuntime, defineAuth, getGeneratedAuthDisabledReason };
@@ -1,7 +1,7 @@
1
1
  import { a as QueryCtxWithPreferredOrmQueryTable, n as LookupByIdResultByCtx, t as DocByCtx } from "../query-context-DJONf8X5.js";
2
2
  import { t as GetAuth } from "../types-Bf3XQex5.js";
3
3
  import { t as GenericCtx } from "../context-utils-DwZ3Cam1.js";
4
- import { S as defineAuth, _ as GenericAuthBeforeResult, a as AuthFunctions, b as GenericAuthTriggerHandlers, c as createApi, d as deleteOneHandler, f as findManyHandler, g as BetterAuthOptionsWithoutDatabase, h as updateOneHandler, i as getGeneratedAuthDisabledReason, l as createHandler, m as updateManyHandler, n as GeneratedAuthDisabledReasonKind, o as Triggers, p as findOneHandler, r as createDisabledAuthRuntime, s as createClient, t as AuthRuntime, u as deleteManyHandler, v as GenericAuthDefinition, x as GenericAuthTriggers, y as GenericAuthTriggerChange } from "../generated-contract-disabled-SzH57bhp.js";
4
+ import { S as defineAuth, _ as GenericAuthBeforeResult, a as AuthFunctions, b as GenericAuthTriggerHandlers, c as createApi, d as deleteOneHandler, f as findManyHandler, g as BetterAuthOptionsWithoutDatabase, h as updateOneHandler, i as getGeneratedAuthDisabledReason, l as createHandler, m as updateManyHandler, n as GeneratedAuthDisabledReasonKind, o as Triggers, p as findOneHandler, r as createDisabledAuthRuntime, s as createClient, t as AuthRuntime, u as deleteManyHandler, v as GenericAuthDefinition, x as GenericAuthTriggers, y as GenericAuthTriggerChange } from "../generated-contract-disabled-B3ByVG3_.js";
5
5
  import * as convex_values0 from "convex/values";
6
6
  import { Infer } from "convex/values";
7
7
  import { AuthConfig, DocumentByName, GenericDataModel, GenericMutationCtx, GenericQueryCtx, GenericSchema, PaginationOptions, PaginationResult, SchemaDefinition, TableNamesInDataModel } from "convex/server";
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as Columns, D as TableName, E as RlsPolicies, O as createSystemFields, S as getRankIndexes, T as OrmSchemaExtensions, _ as loadEsbuild, a as generateMeta, b as getAggregateIndexes, c as resolveSchemaDefaultExport, f as createProjectJiti, g as loadDotenv, h as loadClackPrompts, i as resolveConfiguredBackend, l as schemaDeclaresAggregateIndexes, m as loadBabelParser, n as withLocalCodegenEnv, o as getConvexConfig, p as CRPC_BUILDER_STUB_SOURCE, r as loadCliConfig, s as collectSchemaTables, t as getLocalBackendEnvVars, u as logger, v as highlighter, w as EnableRLS, x as getIndexes, y as isColorEnabled } from "./local-env-Dkh4a_BK.mjs";
2
+ import { C as Columns, D as TableName, E as RlsPolicies, O as createSystemFields, S as getRankIndexes, T as OrmSchemaExtensions, _ as loadEsbuild, a as generateMeta, b as getAggregateIndexes, c as resolveSchemaDefaultExport, f as createProjectJiti, g as loadDotenv, h as loadClackPrompts, i as resolveConfiguredBackend, l as schemaDeclaresAggregateIndexes, m as loadBabelParser, n as withLocalCodegenEnv, o as getConvexConfig, p as CRPC_BUILDER_STUB_SOURCE, r as loadCliConfig, s as collectSchemaTables, t as getLocalBackendEnvVars, u as logger, v as highlighter, w as EnableRLS, x as getIndexes, y as isColorEnabled } from "./local-env-CiPqNKS_.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import fs, { existsSync, readFileSync } from "node:fs";
5
5
  import path, { basename, delimiter, dirname, extname, isAbsolute, join, posix, relative, resolve } from "node:path";
@@ -270,16 +270,16 @@ declare const createApi: <Schema extends SchemaDefinition<any, any>, DataModel e
270
270
  value: string | number | boolean | string[] | number[] | null;
271
271
  field: string;
272
272
  }[] | undefined;
273
- model: string;
274
273
  update: {
275
274
  [x: string]: unknown;
276
275
  [x: number]: unknown;
277
276
  [x: symbol]: unknown;
278
277
  };
278
+ model: string;
279
279
  } | {
280
280
  where?: any[] | undefined;
281
- model: string;
282
281
  update: any;
282
+ model: string;
283
283
  };
284
284
  paginationOpts: {
285
285
  id?: number;
@@ -305,16 +305,16 @@ declare const createApi: <Schema extends SchemaDefinition<any, any>, DataModel e
305
305
  value: string | number | boolean | string[] | number[] | null;
306
306
  field: string;
307
307
  }[] | undefined;
308
- model: string;
309
308
  update: {
310
309
  [x: string]: unknown;
311
310
  [x: number]: unknown;
312
311
  [x: symbol]: unknown;
313
312
  };
313
+ model: string;
314
314
  } | {
315
315
  where?: any[] | undefined;
316
- model: string;
317
316
  update: any;
317
+ model: string;
318
318
  };
319
319
  }, Promise<any>>;
320
320
  };
@@ -473,8 +473,23 @@ export class CRPCError extends Error {
473
473
  }
474
474
  }
475
475
 
476
- export const createEnv = ({ schema }) => () =>
477
- typeof schema?.parse === "function" ? schema.parse(process.env) : process.env;
476
+ export const createEnv = ({ schema }) => () => {
477
+ if (typeof schema?.parse !== "function") return process.env;
478
+ if (globalThis.__KITCN_CODEGEN__ !== true || !schema.shape) {
479
+ return schema.parse(process.env);
480
+ }
481
+ const fallback = Object.fromEntries(
482
+ Object.entries(schema.shape).map(([key, zodType]) => {
483
+ const result = zodType?.safeParse?.(undefined);
484
+ if (result?.success) return [key, result.data];
485
+ if (Array.isArray(zodType?.options) && zodType.options.length > 0) {
486
+ return [key, zodType.options[0]];
487
+ }
488
+ return [key, ""];
489
+ })
490
+ );
491
+ return schema.parse({ ...fallback, ...process.env });
492
+ };
478
493
  export const createHttpRouter = (_app, httpRouter) => httpRouter ?? {};
479
494
  export const createCallerFactory = () => () => ({});
480
495
  export const createApiLeaf = (fnOrRoot, pathOrMeta, maybeMeta) => {
@@ -2587,6 +2602,9 @@ const TS_EXTENSION_RE = /\.ts$/;
2587
2602
  /** Pattern to detect default exports in auth contract files. */
2588
2603
  const DEFAULT_EXPORT_RE = /\bexport\s+default\b/;
2589
2604
  const MISSING_KITCN_IMPORT_RE = /Cannot find (?:module|package) ['"]kitcn(?:\/[^'"]+)?['"]/;
2605
+ const LEGACY_PROCEDURE_LOOKUP_START_RE = /\bregisterProcedureNameLookup\s*\(\s*(\{)/;
2606
+ const LEGACY_PROCEDURE_FILE_RE = /("(?:\\.|[^"\\])*")\s*:\s*\[([\s\S]*?)\]\s*,?/g;
2607
+ const LEGACY_PROCEDURE_ENTRY_RE = /\{\s*column:\s*(\d+)\s*,\s*line:\s*(\d+)\s*,\s*name:\s*("(?:\\.|[^"\\])*")\s*\}/g;
2590
2608
  const RUNTIME_CALLER_RESERVED_EXPORTS = new Set(["actions", "schedule"]);
2591
2609
  const DEFAULT_TRIM_SEGMENTS = ["plugins", "generated"];
2592
2610
  const CODEGEN_SCOPES$1 = new Set([
@@ -2784,6 +2802,59 @@ function emitProcedureNameLookupLiteral(lookup) {
2784
2802
  return ` ${JSON.stringify(file)}: [${items}],`;
2785
2803
  }).join("\n")}\n}`;
2786
2804
  }
2805
+ function extractObjectLiteral(source, startIndex) {
2806
+ let depth = 0;
2807
+ let quote = null;
2808
+ let escaped = false;
2809
+ for (let index = startIndex; index < source.length; index += 1) {
2810
+ const character = source[index];
2811
+ if (quote) {
2812
+ if (escaped) escaped = false;
2813
+ else if (character === "\\") escaped = true;
2814
+ else if (character === quote) quote = null;
2815
+ continue;
2816
+ }
2817
+ if (character === "\"" || character === "'") quote = character;
2818
+ else if (character === "{") depth += 1;
2819
+ else if (character === "}") {
2820
+ depth -= 1;
2821
+ if (depth === 0) return source.slice(startIndex, index + 1);
2822
+ }
2823
+ }
2824
+ return null;
2825
+ }
2826
+ function readLegacyProcedureNameLookup(serverOutputFile) {
2827
+ if (!fs.existsSync(serverOutputFile)) return;
2828
+ const source = fs.readFileSync(serverOutputFile, "utf8");
2829
+ const startMatch = LEGACY_PROCEDURE_LOOKUP_START_RE.exec(source);
2830
+ if (!startMatch || startMatch.index === void 0) return;
2831
+ const literal = extractObjectLiteral(source, startMatch.index + startMatch[0].lastIndexOf("{"));
2832
+ if (!literal) return;
2833
+ if (literal.trim() === "{}") return {};
2834
+ const lookup = {};
2835
+ for (const fileMatch of literal.matchAll(LEGACY_PROCEDURE_FILE_RE)) {
2836
+ const fileLiteral = fileMatch[1];
2837
+ const entriesLiteral = fileMatch[2];
2838
+ if (!fileLiteral || entriesLiteral === void 0) return;
2839
+ const file = JSON.parse(fileLiteral);
2840
+ if (typeof file !== "string") return;
2841
+ const entries = [];
2842
+ for (const entryMatch of entriesLiteral.matchAll(LEGACY_PROCEDURE_ENTRY_RE)) {
2843
+ const nameLiteral = entryMatch[3];
2844
+ if (!nameLiteral) return;
2845
+ const name = JSON.parse(nameLiteral);
2846
+ if (typeof name !== "string") return;
2847
+ entries.push({
2848
+ column: Number(entryMatch[1]),
2849
+ line: Number(entryMatch[2]),
2850
+ name
2851
+ });
2852
+ }
2853
+ if (entries.length === 0) return;
2854
+ lookup[file] = entries;
2855
+ }
2856
+ return Object.keys(lookup).length > 0 ? lookup : void 0;
2857
+ }
2787
2858
  function formatKey(key) {
2788
2859
  return VALID_IDENTIFIER_RE.test(key) ? key : `'${key}'`;
2789
2860
  }
@@ -2877,6 +2948,20 @@ function getModuleImportPath(outputFile, functionsDir, moduleName) {
2877
2948
  const moduleFile = path.join(functionsDir, moduleName);
2878
2949
  return ensureRelativeImportPath(normalizeImportPath(path.relative(path.dirname(outputFile), moduleFile)));
2879
2950
  }
2951
+ /**
2952
+ * Convex's own generated server module. `convex codegen` writes it, and kitcn
2953
+ * codegen runs before it on a first bootstrap, so it can legitimately be
2954
+ * missing.
2955
+ */
2956
+ function getConvexGeneratedServerFile(functionsDir) {
2957
+ const base = path.join(functionsDir, "_generated", "server");
2958
+ return [
2959
+ ".js",
2960
+ ".ts",
2961
+ ".mjs",
2962
+ ".cjs"
2963
+ ].map((extension) => `${base}${extension}`).find((candidate) => fs.existsSync(candidate));
2964
+ }
2880
2965
  function getRuntimeApiImportPath(outputFile, functionsDir) {
2881
2966
  const runtimeApiFile = path.join(functionsDir, "_generated", "api.js");
2882
2967
  return ensureRelativeImportPath(normalizeImportPath(path.relative(path.dirname(outputFile), runtimeApiFile)));
@@ -2931,6 +3016,17 @@ function getGeneratedAuthOutputFile(functionsDir) {
2931
3016
  function getGeneratedMigrationsHelperOutputFile(functionsDir) {
2932
3017
  return path.join(functionsDir, GENERATED_DIR, "migrations.gen.ts");
2933
3018
  }
3019
+ /**
3020
+ * The only parse-derived input to `generated/server.ts`, split into its own
3021
+ * module so `server.ts` stays fully determined by pre-parse facts and can be
3022
+ * written before codegen evaluates the modules that import it.
3023
+ *
3024
+ * Two dots in the basename keep Convex's entry-point walker from deploying it
3025
+ * as a function module, matching `migrations.gen.ts`.
3026
+ */
3027
+ function getGeneratedProcedureNamesOutputFile(functionsDir) {
3028
+ return path.join(functionsDir, GENERATED_DIR, "procedure-names.gen.ts");
3029
+ }
2934
3030
  function getLegacyGeneratedOutputFile(functionsDir) {
2935
3031
  return path.join(functionsDir, "generated.ts");
2936
3032
  }
@@ -2992,6 +3088,19 @@ export const getAuth = () => ({} as Record<string, unknown>);
2992
3088
  export const auth = {} as Record<string, unknown>;
2993
3089
  `;
2994
3090
  }
3091
+ /**
3092
+ * Pure data, zero imports: nothing here can throw while codegen evaluates the
3093
+ * project, and the value export survives tree-shaking even when the app sets
3094
+ * `"sideEffects": false` (a bare side-effect import would not).
3095
+ */
3096
+ function emitGeneratedProcedureNamesFile(procedureNameLookup) {
3097
+ return `// biome-ignore-all format: generated
3098
+ // This file is auto-generated by kitcn
3099
+ // Do not edit manually. Run \`kitcn codegen\` to regenerate.
3100
+
3101
+ export const procedureNames = ${emitProcedureNameLookupLiteral(procedureNameLookup)};
3102
+ `;
3103
+ }
2995
3104
  function emitGeneratedMigrationsPlaceholderFile() {
2996
3105
  return `// biome-ignore-all format: generated
2997
3106
  /* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-unused-vars */
@@ -3010,16 +3119,25 @@ function writeFileIfChanged(filePath, content) {
3010
3119
  }
3011
3120
  function ensureGeneratedSupportPlaceholders(functionsDir, options) {
3012
3121
  const createdPlaceholderFiles = [];
3122
+ const replacedFiles = [];
3013
3123
  const serverOutputFile = getGeneratedServerOutputFile(functionsDir);
3014
3124
  const authOutputFile = getGeneratedAuthOutputFile(functionsDir);
3015
3125
  const migrationsHelperOutputFile = getGeneratedMigrationsHelperOutputFile(functionsDir);
3126
+ const procedureNamesOutputFile = getGeneratedProcedureNamesOutputFile(functionsDir);
3016
3127
  const generatedDir = path.dirname(serverOutputFile);
3017
3128
  fs.mkdirSync(generatedDir, { recursive: true });
3018
3129
  const includeAuth = options?.includeAuth ?? true;
3019
3130
  if (!fs.existsSync(serverOutputFile)) {
3020
3131
  writeFileIfChanged(serverOutputFile, emitGeneratedServerPlaceholderFile(functionsDir));
3021
3132
  createdPlaceholderFiles.push(serverOutputFile);
3133
+ } else if (options?.replaceServer) {
3134
+ const content = fs.readFileSync(serverOutputFile, "utf8");
3135
+ if (writeFileIfChanged(serverOutputFile, emitGeneratedServerPlaceholderFile(functionsDir))) replacedFiles.push({
3136
+ content,
3137
+ filePath: serverOutputFile
3138
+ });
3022
3139
  }
3140
+ if (!fs.existsSync(procedureNamesOutputFile)) writeFileIfChanged(procedureNamesOutputFile, emitGeneratedProcedureNamesFile(options?.procedureNameLookup ?? {}));
3023
3141
  if (includeAuth && !fs.existsSync(authOutputFile)) {
3024
3142
  writeFileIfChanged(authOutputFile, emitGeneratedAuthPlaceholderFile());
3025
3143
  createdPlaceholderFiles.push(authOutputFile);
@@ -3028,7 +3146,22 @@ function ensureGeneratedSupportPlaceholders(functionsDir, options) {
3028
3146
  writeFileIfChanged(migrationsHelperOutputFile, emitGeneratedMigrationsPlaceholderFile());
3029
3147
  createdPlaceholderFiles.push(migrationsHelperOutputFile);
3030
3148
  }
3031
- return createdPlaceholderFiles;
3149
+ return {
3150
+ createdFiles: createdPlaceholderFiles,
3151
+ replacedFiles
3152
+ };
3153
+ }
3154
+ async function withCodegenParseSentinel(callback) {
3155
+ const globals = globalThis;
3156
+ const hadSentinel = Object.hasOwn(globals, "__KITCN_CODEGEN__");
3157
+ const previousSentinel = globals.__KITCN_CODEGEN__;
3158
+ globals.__KITCN_CODEGEN__ = true;
3159
+ try {
3160
+ return await callback();
3161
+ } finally {
3162
+ if (hadSentinel) globals.__KITCN_CODEGEN__ = previousSentinel;
3163
+ else delete globals.__KITCN_CODEGEN__;
3164
+ }
3032
3165
  }
3033
3166
  function emitGeneratedRuntimePlaceholderFile(exportNames) {
3034
3167
  const { callerExportName, handlerExportName } = exportNames;
@@ -3086,8 +3219,7 @@ async function resolveSchemaMetadataForCodegen(functionsDir, debug, createJitiIn
3086
3219
  hasTriggers
3087
3220
  };
3088
3221
  } catch (error) {
3089
- if (debug) logger.warn(`⚠️ Failed to load schema extensions from ${schemaPath}: ${error.message}`);
3090
- return EMPTY_SCHEMA_METADATA;
3222
+ throw new Error(`kitcn codegen could not load ${schemaPath}: ${error.message}`, { cause: error });
3091
3223
  }
3092
3224
  }
3093
3225
  /**
@@ -3108,7 +3240,13 @@ function cleanupGeneratedPluginArtifacts(functionsDir) {
3108
3240
  force: true
3109
3241
  });
3110
3242
  }
3111
- function emitGeneratedServerFile(outputFile, functionsDir, hasOrmSchema, hasAggregateIndexes, hasMigrationsManifest, procedureNameLookup) {
3243
+ /**
3244
+ * Every input here is known before codegen evaluates any project module, so
3245
+ * this file is written first and is authoritative: a stale copy on disk is
3246
+ * replaced before anything can import it. The parse-derived procedure-name
3247
+ * lookup lives in `procedure-names.gen.ts` to keep that true.
3248
+ */
3249
+ function emitGeneratedServerFile(outputFile, functionsDir, hasOrmSchema, hasAggregateIndexes, hasMigrationsManifest) {
3112
3250
  const asSingleQuotedImport = (importPath) => `'${importPath.replaceAll("'", "\\'")}'`;
3113
3251
  const serverTypesImportPath = getServerTypesImportPath(outputFile, functionsDir);
3114
3252
  const dataModelImportPath = getDataModelImportPath(outputFile, functionsDir);
@@ -3124,7 +3262,7 @@ function emitGeneratedServerFile(outputFile, functionsDir, hasOrmSchema, hasAggr
3124
3262
  const capabilityEntries = [...hasAggregateIndexes ? ["aggregateCapability()"] : [], ...hasMigrationsManifest ? ["migrationCapability()"] : []];
3125
3263
  const capabilitiesConfigLine = capabilityEntries.length > 0 ? ` capabilities: [${capabilityEntries.join(", ")}],\n` : "";
3126
3264
  const functionsDirHint = normalizeImportPath(path.relative(process.cwd(), functionsDir)) || "convex";
3127
- const procedureNameLookupLiteral = emitProcedureNameLookupLiteral(procedureNameLookup);
3265
+ const procedureNamesImportLiteral = asSingleQuotedImport(ensureRelativeImportPath(normalizeImportPath(path.relative(path.dirname(outputFile), getGeneratedProcedureNamesOutputFile(functionsDir))).replace(TS_EXTENSION_RE, "")));
3128
3266
  if (!hasOrmSchema) return `// biome-ignore-all format: generated
3129
3267
  // This file is auto-generated by kitcn
3130
3268
  // Do not edit manually. Run \`kitcn codegen\` to regenerate.
@@ -3140,6 +3278,7 @@ import type {
3140
3278
  QueryCtx as ServerQueryCtx,
3141
3279
  } from ${serverTypesImportLiteral};
3142
3280
  import { httpAction, internalMutation } from ${serverTypesImportLiteral};
3281
+ import { procedureNames } from ${procedureNamesImportLiteral};
3143
3282
 
3144
3283
  export type QueryCtx = ServerQueryCtx;
3145
3284
  export type MutationCtx = ServerMutationCtx;
@@ -3147,10 +3286,7 @@ export type ActionCtx = ServerActionCtx;
3147
3286
  export type GenericCtx = QueryCtx | MutationCtx | ActionCtx;
3148
3287
  export type OrmCtx<Ctx = QueryCtx> = Ctx;
3149
3288
 
3150
- registerProcedureNameLookup(
3151
- ${procedureNameLookupLiteral},
3152
- ${JSON.stringify(functionsDirHint)}
3153
- );
3289
+ registerProcedureNameLookup(procedureNames, ${JSON.stringify(functionsDirHint)});
3154
3290
 
3155
3291
  export function withOrm<Ctx extends ServerQueryCtx | ServerMutationCtx>(ctx: Ctx): OrmCtx<Ctx> {
3156
3292
  return ctx as OrmCtx<Ctx>;
@@ -3187,6 +3323,7 @@ import type {
3187
3323
  } from ${serverTypesImportLiteral};
3188
3324
  import { httpAction, internalMutation } from ${serverTypesImportLiteral};
3189
3325
  import schema from ${schemaImportLiteral};
3326
+ import { procedureNames } from ${procedureNamesImportLiteral};
3190
3327
  ${migrationsImportLine}
3191
3328
 
3192
3329
  ${`const ormFunctions: OrmFunctions = {
@@ -3198,10 +3335,7 @@ ${`const ormFunctions: OrmFunctions = {
3198
3335
  };`}
3199
3336
  const ormSchema = schema;
3200
3337
 
3201
- registerProcedureNameLookup(
3202
- ${procedureNameLookupLiteral},
3203
- ${JSON.stringify(functionsDirHint)}
3204
- );
3338
+ registerProcedureNameLookup(procedureNames, ${JSON.stringify(functionsDirHint)});
3205
3339
 
3206
3340
  export const orm = createOrm({
3207
3341
  schema: ormSchema,
@@ -3745,6 +3879,7 @@ async function generateMeta(sharedDir, options) {
3745
3879
  const crpcOutputFile = getGeneratedCrpcOutputFile(functionsDir);
3746
3880
  const authOutputFile = getGeneratedAuthOutputFile(functionsDir);
3747
3881
  const migrationsHelperOutputFile = getGeneratedMigrationsHelperOutputFile(functionsDir);
3882
+ const procedureNamesOutputFile = getGeneratedProcedureNamesOutputFile(functionsDir);
3748
3883
  const legacyGeneratedMigrationsOutputFile = path.join(functionsDir, GENERATED_DIR, "migrations.ts");
3749
3884
  const legacyGeneratedMigrationsRuntimeOutputFile = path.join(functionsDir, GENERATED_DIR, "migrations.runtime.ts");
3750
3885
  const legacyGeneratedMigrationsUnderscoreOutputFile = path.join(functionsDir, GENERATED_DIR, "_migrations.ts");
@@ -3761,7 +3896,10 @@ async function generateMeta(sharedDir, options) {
3761
3896
  const procedureNameLookup = {};
3762
3897
  const fatalParseFailures = [];
3763
3898
  let createdRuntimePlaceholders = [];
3764
- let createdSupportPlaceholders = [];
3899
+ let supportPlaceholderState = {
3900
+ createdFiles: [],
3901
+ replacedFiles: []
3902
+ };
3765
3903
  const runtimeFilesPreservedFromParseFailures = /* @__PURE__ */ new Set();
3766
3904
  let totalFunctions = 0;
3767
3905
  const authFilePath = path.join(functionsDir, "auth.ts");
@@ -3773,7 +3911,7 @@ async function generateMeta(sharedDir, options) {
3773
3911
  };
3774
3912
  let sharedJitiInstance;
3775
3913
  const getSharedJitiInstance = () => sharedJitiInstance ??= createProjectJiti();
3776
- const schemaMetadata = await resolveSchemaMetadataForCodegen(functionsDir, debug, getSharedJitiInstance);
3914
+ const schemaMetadata = await withCodegenParseSentinel(() => resolveSchemaMetadataForCodegen(functionsDir, debug, getSharedJitiInstance));
3777
3915
  const hasOrmSchemaMetadata = schemaMetadata.hasOrmSchema;
3778
3916
  const hasRelationsMetadata = schemaMetadata.hasRelations;
3779
3917
  const hasRelationsExport = hasNamedExport(path.join(functionsDir, "schema.ts"), "relations");
@@ -3783,7 +3921,14 @@ async function generateMeta(sharedDir, options) {
3783
3921
  if (hasRelationsExport) throw new Error("Codegen error: do not export `relations` from schema.ts. Chain relations on the default schema export with `defineSchema(...).relations(...)`.");
3784
3922
  if (hasSchemaTriggersExport || hasDedicatedTriggersExport) throw new Error("Codegen error: do not export `triggers` from schema.ts or triggers.ts. Chain triggers on the default schema export with `defineSchema(...).relations(...).triggers(...)`.");
3785
3923
  const hasOrmSchema = hasOrmSchemaMetadata;
3786
- createdSupportPlaceholders = ensureGeneratedSupportPlaceholders(functionsDir, { includeAuth: generateAuth });
3924
+ const convexGeneratedServerFile = getConvexGeneratedServerFile(functionsDir);
3925
+ supportPlaceholderState = ensureGeneratedSupportPlaceholders(functionsDir, {
3926
+ includeAuth: generateAuth,
3927
+ procedureNameLookup: fs.existsSync(procedureNamesOutputFile) ? void 0 : readLegacyProcedureNameLookup(serverOutputFile),
3928
+ replaceServer: convexGeneratedServerFile === void 0
3929
+ });
3930
+ const emitServerFile = () => writeFileIfChanged(serverOutputFile, emitGeneratedServerFile(serverOutputFile, functionsDir, hasOrmSchema, schemaMetadata.hasAggregateIndexes, hasMigrationsManifest));
3931
+ if (convexGeneratedServerFile) emitServerFile();
3787
3932
  if (generateApi) {
3788
3933
  globalThis.__KITCN_CODEGEN__ = true;
3789
3934
  try {
@@ -3844,7 +3989,8 @@ async function generateMeta(sharedDir, options) {
3844
3989
  }
3845
3990
  if (fatalParseFailures.length > 0) {
3846
3991
  for (const createdRuntimePlaceholder of createdRuntimePlaceholders) fs.rmSync(createdRuntimePlaceholder, { force: true });
3847
- for (const createdSupportPlaceholder of createdSupportPlaceholders) fs.rmSync(createdSupportPlaceholder, { force: true });
3992
+ for (const createdSupportPlaceholder of supportPlaceholderState.createdFiles) fs.rmSync(createdSupportPlaceholder, { force: true });
3993
+ for (const replacedSupportFile of supportPlaceholderState.replacedFiles) fs.writeFileSync(replacedSupportFile.filePath, replacedSupportFile.content, "utf8");
3848
3994
  const failureSummary = fatalParseFailures.map(({ file, error }) => `- ${file}: ${error instanceof Error ? error.message : String(error)}`).join("\n");
3849
3995
  throw new Error(`kitcn codegen aborted because module parsing failed:\n${failureSummary}`);
3850
3996
  }
@@ -3906,10 +4052,10 @@ ${optionalTypeExports}
3906
4052
  if (!fs.existsSync(outputDirname)) fs.mkdirSync(outputDirname, { recursive: true });
3907
4053
  writeFileIfChanged(outputFile, output);
3908
4054
  } else fs.rmSync(outputFile, { force: true });
3909
- const serverOutput = emitGeneratedServerFile(serverOutputFile, functionsDir, hasOrmSchema, schemaMetadata.hasAggregateIndexes, hasMigrationsManifest, procedureNameLookup);
3910
4055
  const generatedOutputDirname = path.dirname(serverOutputFile);
3911
4056
  if (!fs.existsSync(generatedOutputDirname)) fs.mkdirSync(generatedOutputDirname, { recursive: true });
3912
- writeFileIfChanged(serverOutputFile, serverOutput);
4057
+ emitServerFile();
4058
+ if (generateApi) writeFileIfChanged(procedureNamesOutputFile, emitGeneratedProcedureNamesFile(procedureNameLookup));
3913
4059
  if (hasOrmSchema) writeFileIfChanged(aggregateOutputFile, emitGeneratedAggregateFile(aggregateOutputFile, functionsDir));
3914
4060
  else fs.rmSync(aggregateOutputFile, { force: true });
3915
4061
  fs.rmSync(ormOutputFile, { force: true });
@@ -1,6 +1,6 @@
1
1
  import { t as DirectAggregate } from "../../runtime-BdqTbgKh.js";
2
2
  import { a as Columns } from "../../table-CX2lnX7e.js";
3
- import { Y as normalizeTemporalComparableValue, _t as PUBLIC_CREATED_AT_FIELD, c as AGGREGATE_ERROR, f as createError, gt as INTERNAL_CREATION_TIME_FIELD, i as AGGREGATE_STATE_TABLE, l as COUNT_ERROR, n as AGGREGATE_EXTREMA_TABLE, o as getAggregateIndexDefinitions, ot as mapWithConcurrency, r as AGGREGATE_MEMBER_TABLE, s as getRankIndexDefinitions, t as AGGREGATE_BUCKET_TABLE, vt as usesSystemCreatedAtAlias } from "../../schema-D8sVYuYO.js";
3
+ import { Y as normalizeTemporalComparableValue, bt as PUBLIC_CREATED_AT_FIELD, c as AGGREGATE_ERROR, f as createError, i as AGGREGATE_STATE_TABLE, l as COUNT_ERROR, lt as mapWithConcurrency, n as AGGREGATE_EXTREMA_TABLE, o as getAggregateIndexDefinitions, r as AGGREGATE_MEMBER_TABLE, s as getRankIndexDefinitions, t as AGGREGATE_BUCKET_TABLE, xt as usesSystemCreatedAtAlias, yt as INTERNAL_CREATION_TIME_FIELD } from "../../schema-e0wbZ_Ax.js";
4
4
 
5
5
  //#region src/orm/aggregate-index/runtime.ts
6
6
  const UNDEFINED_SENTINEL = "__kitcnUndefined";
@@ -1,5 +1,5 @@
1
1
  import { $n as BinaryExpression, $t as OrmLifecycleOperation, A as DatabaseWithMutations, An as ConvexCheckConfig, Ar as AnyColumn, At as VectorQueryConfig, B as RlsContext, Bn as ConvexTextBuilderInitial, Br as IsUnique, Bt as RelationsBuilderColumnConfig, C as MigrationTableName, Cn as aggregateIndex, Cr as notBetween, Ct as OrderDirection, D as defineMigrationSet, Dn as uniqueIndex, Dt as ReturningResult, E as defineMigration, En as searchIndex, Er as startsWith, Et as ReturningAll, Fn as ConvexUniqueConstraintConfig, Fr as ColumnBuilderWithTableName, Ft as ExtractTablesWithRelations, Gt as defineRelations, H as EdgeMetadata, In as check, Ir as ColumnDataType, It as ManyConfig, Jt as ConvexDeletionConfig, Kt as defineRelationsPart, Ln as foreignKey, Lr as DrizzleEntity, Lt as OneConfig, M as OrmReader$1, Mn as ConvexForeignKeyConfig, Mr as ColumnBuilderBaseConfig, Mt as unsetToken, N as OrmWriter$1, Nn as ConvexUniqueConstraintBuilder, Nr as ColumnBuilderRuntimeConfig, O as detectMigrationDrift, On as vectorIndex, Or as SystemFields, Ot as ReturningSelection, Pn as ConvexUniqueConstraintBuilderOn, Pr as ColumnBuilderTypeConfig, Pt as ExtractTablesFromSchema, Qn as TableName, Qt as OrmLifecycleChange, Rn as unique, Rr as HasDefault, Rt as RelationsBuilder, S as MigrationStep, Sn as ConvexVectorIndexConfig, Sr as not, St as OrderByClause, T as buildMigrationPlan, Tn as rankIndex, Tr as or, Tt as PredicateWhereIndexConfig, U as extractRelationsConfig, Un as Brand, Ut as TableRelationalConfig, V as RlsMode, Vn as text, Vr as NotNull, Wn as Columns, Wt as TablesRelationalConfig, Xn as OrmSchemaRelations, Xt as ConvexTableWithColumns, Yn as OrmSchemaExtensions, Yt as ConvexTable, Zn as OrmSchemaTriggers, Zt as DiscriminatorBuilderConfig, _ as MigrationMigrateOne, _n as ConvexSearchIndexBuilder, _r as isNull, _t as MutationPaginateConfig, an as RlsPolicyConfig, ar as and, at as CountConfig, b as MigrationSet, bn as ConvexVectorIndexBuilder, br as lte, bt as MutationReturning, cn as RlsRole, cr as endsWith, ct as FilterOperators, d as MigrationDefinition, dn as ConvexAggregateIndexBuilder, dr as gt, dt as InferModelFromColumns, en as TableConfig, er as ExpressionVisitor, et as AggregateConfig, f as MigrationDirection, fn as ConvexAggregateIndexBuilderOn, fr as gte, ft as InferSelectModel, g as MigrationManifestEntry, gn as ConvexRankIndexBuilderOn, gr as isNotNull, gt as MutationExecutionMode, h as MigrationDriftIssue, hn as ConvexRankIndexBuilder, hr as isFieldReference, ht as MutationExecuteResult, i as OrmMigrationCapability, in as RlsPolicy, ir as UnaryExpression, it as BuildRelationResult, j as DatabaseWithQuery, jn as ConvexForeignKeyBuilder, jr as ColumnBuilder, jt as VectorSearchProvider, kn as ConvexCheckBuilder, kt as UpdateSet, ln as RlsRoleConfig, lr as eq, lt as GetColumnData, m as MigrationDocContext, mn as ConvexIndexBuilderOn, mr as inArray, mt as MutationExecuteConfig, n as OrmCapabilities, nn as deletion, nr as FilterExpression, nt as AggregateResult, on as RlsPolicyToOption, or as between, ot as CountResult, p as MigrationDoc, pn as ConvexIndexBuilder, pr as ilike, pt as InsertValue, qn as OrmSchemaExtensionTables, qt as ConvexDeletionBuilder, r as OrmCapability, rn as discriminator, rr as LogicalExpression, rt as BuildQueryResult, sn as rlsPolicy, sr as contains, st as DBQueryConfig, t as OrmAggregateCapability, tn as convexTable, tr as FieldReference, tt as AggregateFieldValue, u as MigrationAppliedState, un as rlsRole, ur as fieldRef, ut as InferInsertModel, v as MigrationPlan, vn as ConvexSearchIndexBuilderOn, vr as like, vt as MutationPaginatedResult, w as MigrationWriteMode, wn as index, wr as notInArray, wt as PaginatedResult, x as MigrationStateMap, xn as ConvexVectorIndexBuilderOn, xr as ne, xt as MutationRunMode, y as MigrationRunStatus, yn as ConvexSearchIndexConfig, yr as lt, yt as MutationResult, zn as ConvexTextBuilder, zr as IsPrimaryKey, zt as RelationsBuilderColumnBase } from "../capabilities-DtDfpdcH.js";
2
- import { $ as OrmClientWithApi$1, A as ConvexDateMode, B as ConvexBytesBuilderInitial, C as ConvexNumberBuilderInitial, D as id, E as ConvexIdBuilderInitial, F as custom, G as ConvexBigIntBuilder, H as ConvexBooleanBuilder, I as json, J as CreateOrmOptions, K as ConvexBigIntBuilderInitial, L as objectOf, M as ConvexCustomBuilder, N as ConvexCustomBuilderInitial, O as ConvexDateBuilder, P as arrayOf, Q as OrmClientBase$1, R as unionOf, S as ConvexNumberBuilder, St as defineTriggers, T as ConvexIdBuilder, U as ConvexBooleanBuilderInitial, V as bytes, W as boolean, X as GenericOrmCtx$1, Y as GenericOrm$1, Z as OrmApiResult, _ as ConvexTimestampMode, _t as OrmBeforeResult, a as requireSchemaRelations, at as ScheduledMutationBatchArgs, b as ConvexTextEnumBuilderInitial, bt as OrmTriggerContext, c as TableConfigResult, ct as scheduledDeleteFactory, d as OrmNotFoundError, et as OrmFunctions, f as ConvexVectorBuilder, g as ConvexTimestampBuilderInitial, gt as defineSchemaExtension, h as ConvexTimestampBuilder, ht as SchemaExtension, i as getSchemaTriggers, it as createOrm, j as date, k as ConvexDateBuilderInitial, l as getTableColumns, m as vector, n as defineSchema, nt as OrmWriterCtx, o as asc, ot as scheduledMutationBatchFactory, p as ConvexVectorBuilderInitial, q as bigint, r as getSchemaRelations, rt as ResolveOrmSchema, s as desc, st as ScheduledDeleteArgs, t as WhereClauseResult, tt as OrmReaderCtx, u as getTableConfig, v as timestamp, vt as OrmTableTriggers, w as integer, x as textEnum, xt as OrmTriggers, y as ConvexTextEnumBuilder, yt as OrmTriggerChange, z as ConvexBytesBuilder } from "../where-clause-compiler-Bke7ULoY.js";
2
+ import { $ as OrmClientWithApi$1, A as ConvexDateMode, B as ConvexBytesBuilderInitial, C as ConvexNumberBuilderInitial, D as id, E as ConvexIdBuilderInitial, F as custom, G as ConvexBigIntBuilder, H as ConvexBooleanBuilder, I as json, J as CreateOrmOptions, K as ConvexBigIntBuilderInitial, L as objectOf, M as ConvexCustomBuilder, N as ConvexCustomBuilderInitial, O as ConvexDateBuilder, P as arrayOf, Q as OrmClientBase$1, R as unionOf, S as ConvexNumberBuilder, St as defineTriggers, T as ConvexIdBuilder, U as ConvexBooleanBuilderInitial, V as bytes, W as boolean, X as GenericOrmCtx$1, Y as GenericOrm$1, Z as OrmApiResult, _ as ConvexTimestampMode, _t as OrmBeforeResult, a as requireSchemaRelations, at as ScheduledMutationBatchArgs, b as ConvexTextEnumBuilderInitial, bt as OrmTriggerContext, c as TableConfigResult, ct as scheduledDeleteFactory, d as OrmNotFoundError, et as OrmFunctions, f as ConvexVectorBuilder, g as ConvexTimestampBuilderInitial, gt as defineSchemaExtension, h as ConvexTimestampBuilder, ht as SchemaExtension, i as getSchemaTriggers, it as createOrm, j as date, k as ConvexDateBuilderInitial, l as getTableColumns, m as vector, n as defineSchema, nt as OrmWriterCtx, o as asc, ot as scheduledMutationBatchFactory, p as ConvexVectorBuilderInitial, q as bigint, r as getSchemaRelations, rt as ResolveOrmSchema, s as desc, st as ScheduledDeleteArgs, t as WhereClauseResult, tt as OrmReaderCtx, u as getTableConfig, v as timestamp, vt as OrmTableTriggers, w as integer, x as textEnum, xt as OrmTriggers, y as ConvexTextEnumBuilder, yt as OrmTriggerChange, z as ConvexBytesBuilder } from "../where-clause-compiler-DlRUDuMx.js";
3
3
  import { i as pretendRequired, n as deprecated, r as pretend } from "../validators-wOIjhkfN.js";
4
4
  import { a as QueryCtxWithPreferredOrmQueryTable, i as QueryCtxWithOrmQueryTable, n as LookupByIdResultByCtx, o as getByIdWithOrmQueryFallback, r as QueryCtxWithOptionalOrmQueryTable, t as DocByCtx } from "../query-context-DJONf8X5.js";
5
5
  import { DefineSchemaOptions, GenericDatabaseReader, GenericDatabaseWriter, GenericSchema, SchemaDefinition } from "convex/server";
package/dist/orm/index.js CHANGED
@@ -4,7 +4,7 @@ import { a as pretendRequired, i as pretend, n as deprecated } from "../validato
4
4
  import { t as id } from "../id-CuSfWa5q.js";
5
5
  import { A as or, C as matchLikePattern, D as notIlike, E as notBetween, O as notInArray, S as lte, T as not, _ as isFieldReference, a as between, b as like, c as endsWith, d as filterValueInList, f as filterValuesEqual, g as inArray, h as ilike, i as arrayOverlaps, j as startsWith, k as notLike, l as eq, m as gte, n as arrayContained, o as column, p as gt, r as arrayContains, s as contains, t as and, u as fieldRef, v as isNotNull, w as ne, x as lt, y as isNull } from "../filter-expression-Dydt8wS0.js";
6
6
  import { a as indexKeyWithinBounds, c as streamIndexRange, i as getIndexFields, l as isUnsetToken, n as EmptyStream, o as mergedStream, r as QueryStream, s as stream, t as getByIdWithOrmQueryFallback, u as unsetToken } from "../query-context-DOm5Xm3H.js";
7
- import { $ as serializeFilterExpression, A as ensureNonNullValues, B as getMutationExecutionMode, C as deserializeFilterExpression, D as enforcePolymorphicWrite, E as enforceForeignKeys, F as getChecks, G as getUniqueIndexes, H as getTableColumns$2, I as getColumnName$1, J as normalizeDateFieldsForWrite, K as hardDeleteRow, L as getForeignKeys, M as evaluateCheckConstraintTriState, N as evaluateFilter, O as enforceUniqueIndexes, P as extractPrimaryIdLookup, Q as selectReturningRowWithHydration, R as getMutationAsyncDelayMs, S as decodeUndefinedDeep, T as enforceCheckConstraints, U as getTableDeleteConfig, V as getOrmContext, W as getTableName, X as patchReferencingRows, Y as normalizeTemporalComparableValue, Z as resolveOrmRuntimeDefaults, _ as applyIncomingForeignKeyActionsOnUpdate, _t as PUBLIC_CREATED_AT_FIELD, a as aggregateExtension, at as markLifecycleHookedTables, b as collectMutationRowsBounded, c as AGGREGATE_ERROR, ct as findRelationIndex, d as createCountError, dt as getAggregateIndexes, et as softDeleteRow, ft as getIndexes, g as applyIncomingForeignKeyActionsOnDelete, gt as INTERNAL_CREATION_TIME_FIELD, h as applyDefaults, ht as CREATED_AT_MIGRATION_MESSAGE, it as hasLifecycleHooks, j as ensureNullableColumns, k as ensureDefaultColumns, l as COUNT_ERROR, lt as findSearchIndexByName, m as ensureCountAllowedForRls, mt as resolveIndexOrderPushdown, nt as takeRowsWithinByteBudget, o as getAggregateIndexDefinitions, ot as mapWithConcurrency, p as ensureAggregateAllowedForRls, pt as getRankIndexes, q as hydrateDateFieldsForRead, rt as toConvexFilter, s as getRankIndexDefinitions, st as findIndexForColumns, tt as splitReturningSelection, u as createAggregateError, ut as findVectorIndexByName, v as buildForeignKeyGraph, vt as usesSystemCreatedAtAlias, w as encodeUndefinedDeep, x as collectPrimaryIdLookupRows, y as canUsePrimaryIdLookupCursor, z as getMutationCollectionLimits } from "../schema-D8sVYuYO.js";
7
+ import { $ as serializeFilterExpression, A as ensureNonNullValues, B as getMutationExecutionMode, C as deserializeFilterExpression, D as enforcePolymorphicWrite, E as enforceForeignKeys, F as getChecks, G as getUniqueIndexes, H as getTableColumns$2, I as getColumnName$1, J as normalizeDateFieldsForWrite, K as hardDeleteRow, L as getForeignKeys, M as evaluateCheckConstraintTriState, N as evaluateFilter, O as enforceUniqueIndexes, P as extractPrimaryIdLookup, Q as selectReturningRowWithHydration, R as getMutationAsyncDelayMs, S as decodeUndefinedDeep, T as enforceCheckConstraints, U as getTableDeleteConfig, V as getOrmContext, W as getTableName, X as patchReferencingRows, Y as normalizeTemporalComparableValue, Z as resolveOrmRuntimeDefaults, _ as applyIncomingForeignKeyActionsOnUpdate, _t as resolveIndexOrderPushdown, a as aggregateExtension, at as markLifecycleHookedTables, b as collectMutationRowsBounded, bt as PUBLIC_CREATED_AT_FIELD, c as AGGREGATE_ERROR, ct as isConvexEnforceableFilter, d as createCountError, dt as findRelationIndex, et as softDeleteRow, ft as findSearchIndexByName, g as applyIncomingForeignKeyActionsOnDelete, gt as getRankIndexes, h as applyDefaults, ht as getIndexes, it as hasLifecycleHooks, j as ensureNullableColumns, k as ensureDefaultColumns, l as COUNT_ERROR, lt as mapWithConcurrency, m as ensureCountAllowedForRls, mt as getAggregateIndexes, nt as takeRowsWithinByteBudget, o as getAggregateIndexDefinitions, ot as compileConvexFilter, p as ensureAggregateAllowedForRls, pt as findVectorIndexByName, q as hydrateDateFieldsForRead, rt as toConvexFilter, s as getRankIndexDefinitions, st as convexAnd, tt as splitReturningSelection, u as createAggregateError, ut as findIndexForColumns, v as buildForeignKeyGraph, vt as CREATED_AT_MIGRATION_MESSAGE, w as encodeUndefinedDeep, x as collectPrimaryIdLookupRows, xt as usesSystemCreatedAtAlias, y as canUsePrimaryIdLookupCursor, yt as INTERNAL_CREATION_TIME_FIELD, z as getMutationCollectionLimits } from "../schema-e0wbZ_Ax.js";
8
8
  import { t as defineSchemaExtension } from "../extensions-Blzsyekm.js";
9
9
  import { compareValues, v } from "convex/values";
10
10
  import { defineSchema as defineSchema$1, internalActionGeneric, internalMutationGeneric } from "convex/server";
@@ -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
 
@@ -1270,24 +1270,6 @@ var WhereClauseCompiler = class {
1270
1270
 
1271
1271
  //#endregion
1272
1272
  //#region src/orm/query.ts
1273
- /**
1274
- * Operators that Convex's `.filter()` cannot express, so `_toConvexExpression`
1275
- * compiles them to a `() => true` placeholder and `_evaluatePostFetchFilter`
1276
- * applies the real predicate in JavaScript after the rows are read.
1277
- * Keep in sync with the string/array cases in `_toConvexExpression`.
1278
- */
1279
- const POST_FETCH_ONLY_OPERATORS = new Set([
1280
- "like",
1281
- "ilike",
1282
- "notLike",
1283
- "notIlike",
1284
- "startsWith",
1285
- "endsWith",
1286
- "contains",
1287
- "arrayContains",
1288
- "arrayContained",
1289
- "arrayOverlaps"
1290
- ]);
1291
1273
  const DEFAULT_RELATION_FAN_OUT_MAX_KEYS = 1e3;
1292
1274
  /**
1293
1275
  * How many child rows the bounded relation stream filters at a time. Batching
@@ -1743,14 +1725,7 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
1743
1725
  * expression before relying on it.
1744
1726
  */
1745
1727
  _isConvexEnforceableFilter(filter) {
1746
- if (filter.type === "binary") return !POST_FETCH_ONLY_OPERATORS.has(filter.operator);
1747
- if (filter.type === "unary") {
1748
- const [operand] = filter.operands;
1749
- if (isFieldReference(operand)) return true;
1750
- return this._isConvexEnforceableFilter(operand);
1751
- }
1752
- if (filter.type === "logical") return filter.operands.every((operand) => this._isConvexEnforceableFilter(operand));
1753
- return true;
1728
+ return isConvexEnforceableFilter(filter);
1754
1729
  }
1755
1730
  /**
1756
1731
  * Evaluate a filter expression against a fetched row
@@ -4098,14 +4073,7 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
4098
4073
  return indexQuery;
4099
4074
  });
4100
4075
  if (probeBound !== void 0 && probeOrderDirection) probeQuery = probeQuery.order(probeOrderDirection);
4101
- if (convexProbeFilters.length > 0) probeQuery = probeQuery.filter((q) => {
4102
- let result = null;
4103
- for (const filter of convexProbeFilters) {
4104
- const expr = this._toConvexExpression(filter)(q);
4105
- result = result ? q.and(result, expr) : expr;
4106
- }
4107
- return result ?? q;
4108
- });
4076
+ if (convexProbeFilters.length > 0) probeQuery = probeQuery.filter((q) => convexAnd(q, convexProbeFilters.map((filter) => this._toConvexExpression(filter)(q))));
4109
4077
  return probeBound === void 0 ? await probeQuery.collect() : await probeQuery.take(probeBound);
4110
4078
  }));
4111
4079
  let rows = Array.from(new Map(probeRows.flat().map((row) => [String(row._id), row])).values());
@@ -4220,14 +4188,7 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
4220
4188
  splitCursor: paginationResult.splitCursor
4221
4189
  };
4222
4190
  }
4223
- if (convexPostFilters.length > 0) query = query.filter((q) => {
4224
- let result = null;
4225
- for (const filter of convexPostFilters) {
4226
- const expr = this._toConvexExpression(filter)(q);
4227
- result = result ? q.and(result, expr) : expr;
4228
- }
4229
- return result ?? q;
4230
- });
4191
+ if (convexPostFilters.length > 0) query = query.filter((q) => convexAnd(q, convexPostFilters.map((filter) => this._toConvexExpression(filter)(q))));
4231
4192
  if (queryConfig.order && primaryOrder) {
4232
4193
  if (needsPostFetchSortForPrimary) {
4233
4194
  if (strict) throw new Error(`Pagination: Field '${primaryOrder.field}' has no index. Add an index or disable strict.`);
@@ -4252,14 +4213,7 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
4252
4213
  const convexPostFilters = queryConfig.postFilters.filter((filter) => this._isConvexEnforceableFilter(filter));
4253
4214
  const hasResidualPostFilter = convexPostFilters.length !== queryConfig.postFilters.length;
4254
4215
  const hasPostFetchMembership = this._hasSearchDisallowedRelationFilter(whereFilter, this.tableConfig) || this.rls?.mode !== "skip" && isRlsEnabled(this.tableConfig.table);
4255
- if (convexPostFilters.length > 0) query = query.filter((q) => {
4256
- let result = null;
4257
- for (const filter of convexPostFilters) {
4258
- const expr = this._toConvexExpression(filter)(q);
4259
- result = result ? q.and(result, expr) : expr;
4260
- }
4261
- return result ?? q;
4262
- });
4216
+ if (convexPostFilters.length > 0) query = query.filter((q) => convexAnd(q, convexPostFilters.map((filter) => this._toConvexExpression(filter)(q))));
4263
4217
  const offset = config.offset ?? 0;
4264
4218
  if (typeof offset !== "number") throw new Error("Only numeric offset is supported in kitcn ORM.");
4265
4219
  const limit = this._resolveNonPaginatedLimit(config);
@@ -4375,9 +4329,7 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
4375
4329
  return builder;
4376
4330
  }
4377
4331
  _buildFilterPredicate(q, fields, values) {
4378
- let expression = q.eq(q.field(fields[0]), values[0]);
4379
- for (let i = 1; i < fields.length; i += 1) expression = q.and(expression, q.eq(q.field(fields[i]), values[i]));
4380
- return expression;
4332
+ return convexAnd(q, fields.map((field, index) => q.eq(q.field(field), values[index])));
4381
4333
  }
4382
4334
  _queryByFields(query, fields, values, indexName) {
4383
4335
  if (indexName) return query.withIndex(indexName, (q) => this._buildIndexPredicate(q, fields, values));
@@ -4421,79 +4373,10 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
4421
4373
  * Uses visitor pattern to traverse expression tree
4422
4374
  */
4423
4375
  _toConvexExpression(expression) {
4424
- const visitor = {
4425
- visitBinary: (expr) => {
4426
- const [field, value] = expr.operands;
4427
- if (!isFieldReference(field)) throw new Error("Binary expression must have FieldReference as first operand");
4428
- const fieldName = field.fieldName;
4429
- const normalizedValue = this._normalizeComparableValue(fieldName, value);
4430
- switch (expr.operator) {
4431
- case "eq": return (q) => q.eq(q.field(fieldName), normalizedValue);
4432
- case "ne": return (q) => q.neq(q.field(fieldName), normalizedValue);
4433
- case "gt": return (q) => q.gt(q.field(fieldName), normalizedValue);
4434
- case "gte": return (q) => q.gte(q.field(fieldName), normalizedValue);
4435
- case "lt": return (q) => q.lt(q.field(fieldName), normalizedValue);
4436
- case "lte": return (q) => q.lte(q.field(fieldName), normalizedValue);
4437
- case "inArray": {
4438
- const values = normalizedValue;
4439
- return (q) => {
4440
- if (values.length === 0) return q.eq(q.field("_id"), "__better_convex_never__");
4441
- return values.map((v) => q.eq(q.field(fieldName), v)).reduce((acc, cond) => q.or(acc, cond));
4442
- };
4443
- }
4444
- case "notInArray": {
4445
- const values = normalizedValue;
4446
- return (q) => {
4447
- return values.map((v) => q.neq(q.field(fieldName), v)).reduce((acc, cond) => q.and(acc, cond));
4448
- };
4449
- }
4450
- case "like":
4451
- case "ilike":
4452
- case "notLike":
4453
- case "notIlike":
4454
- case "startsWith":
4455
- case "endsWith":
4456
- case "contains":
4457
- case "arrayContains":
4458
- case "arrayContained":
4459
- case "arrayOverlaps": return () => true;
4460
- default: throw new Error(`Unsupported binary operator: ${expr.operator}`);
4461
- }
4462
- },
4463
- visitLogical: (expr) => {
4464
- const operandFns = expr.operands.map((op) => op.accept(visitor));
4465
- if (expr.operator === "and") return (q) => {
4466
- let result = operandFns[0](q);
4467
- for (let i = 1; i < operandFns.length; i++) result = q.and(result, operandFns[i](q));
4468
- return result;
4469
- };
4470
- if (expr.operator === "or") return (q) => {
4471
- let result = operandFns[0](q);
4472
- for (let i = 1; i < operandFns.length; i++) result = q.or(result, operandFns[i](q));
4473
- return result;
4474
- };
4475
- throw new Error(`Unsupported logical operator: ${expr.operator}`);
4476
- },
4477
- visitUnary: (expr) => {
4478
- const operand = expr.operands[0];
4479
- if (expr.operator === "not") {
4480
- const operandFn = operand.accept(visitor);
4481
- return (q) => q.not(operandFn(q));
4482
- }
4483
- if (expr.operator === "isNull") {
4484
- if (!isFieldReference(operand)) throw new Error("isNull must operate on a field reference");
4485
- const fieldName = operand.fieldName;
4486
- return (q) => q.or(q.eq(q.field(fieldName), null), q.eq(q.field(fieldName), void 0));
4487
- }
4488
- if (expr.operator === "isNotNull") {
4489
- if (!isFieldReference(operand)) throw new Error("isNotNull must operate on a field reference");
4490
- const fieldName = operand.fieldName;
4491
- return (q) => q.and(q.neq(q.field(fieldName), null), q.neq(q.field(fieldName), void 0));
4492
- }
4493
- throw new Error(`Unsupported unary operator: ${expr.operator}`);
4494
- }
4495
- };
4496
- return expression.accept(visitor);
4376
+ return compileConvexFilter(expression, {
4377
+ normalizeValue: (fieldName, value) => this._normalizeComparableValue(fieldName, value),
4378
+ nullMatchesUndefined: true
4379
+ });
4497
4380
  }
4498
4381
  /**
4499
4382
  * Get edge metadata for a target table
@@ -5755,14 +5638,7 @@ var ConvexInsertBuilder = class extends QueryPromise {
5755
5638
  else {
5756
5639
  if (!allowFullScan) throw new Error("onConflict requires allowFullScan: true when no index is available.");
5757
5640
  if (strict) console.warn("onConflict running without index (allowFullScan: true).");
5758
- query = query.filter((q) => {
5759
- let expr = q.eq(q.field(filterValuePairs[0][0]), filterValuePairs[0][1]);
5760
- for (let i = 1; i < filterValuePairs.length; i++) {
5761
- const [field, fieldValue] = filterValuePairs[i];
5762
- expr = q.and(expr, q.eq(q.field(field), fieldValue));
5763
- }
5764
- return expr;
5765
- });
5641
+ query = query.filter((q) => convexAnd(q, filterValuePairs.map(([field, fieldValue]) => q.eq(q.field(field), fieldValue))));
5766
5642
  }
5767
5643
  const row = await query.first();
5768
5644
  return row ? row : null;
@@ -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-Bke7ULoY.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-DlRUDuMx.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 };
@@ -125,6 +125,138 @@ async function mapWithConcurrency(items, limit, worker) {
125
125
  return results;
126
126
  }
127
127
 
128
+ //#endregion
129
+ //#region src/orm/convex-filter-compiler.ts
130
+ /**
131
+ * Operators Convex's `.filter()` cannot express, so they compile to a
132
+ * `() => true` placeholder and the real predicate runs in JavaScript after the
133
+ * rows are read. Callers that push a compiled expression into Convex must
134
+ * first check `isConvexEnforceableFilter`: a `true` placeholder makes a
135
+ * downstream `take()` spend its budget on unfiltered rows, and a surrounding
136
+ * `NOT` turns it into `q.not(true)`, which matches nothing.
137
+ */
138
+ const POST_FETCH_ONLY_OPERATORS = new Set([
139
+ "like",
140
+ "ilike",
141
+ "notLike",
142
+ "notIlike",
143
+ "startsWith",
144
+ "endsWith",
145
+ "contains",
146
+ "arrayContains",
147
+ "arrayContained",
148
+ "arrayOverlaps"
149
+ ]);
150
+ /**
151
+ * Compared against `_id`, which is a Convex id and can never equal a plain
152
+ * string, so `eq` against it is unsatisfiable. Convex's expression grammar has
153
+ * no literal boolean, so this is how `in []` says "match nothing".
154
+ */
155
+ const NEVER_MATCH_SENTINEL = "__better_convex_never__";
156
+ /**
157
+ * Convex's `q.or` / `q.and` are variadic — `or(...exprs)` serializes to a flat
158
+ * `{ $or: [...] }` (see `convex/src/server/impl/filter_builder_impl.ts`).
159
+ * Folding them pairwise instead nests one `$or` per operand, so the serialized
160
+ * filter's JSON depth grows as `2N + 1` and the backend rejects the whole query
161
+ * with `Received invalid json: recursion limit exceeded` once the list passes a
162
+ * few dozen entries. Always combine in one variadic call.
163
+ */
164
+ function convexOr(q, expressions) {
165
+ return expressions.length === 1 ? expressions[0] : q.or(...expressions);
166
+ }
167
+ /** Flat `$and` counterpart of {@link convexOr}. */
168
+ function convexAnd(q, expressions) {
169
+ return expressions.length === 1 ? expressions[0] : q.and(...expressions);
170
+ }
171
+ /**
172
+ * Whether Convex can carry the whole expression in `.filter()`, or some part of
173
+ * it compiles to a `() => true` placeholder that only JavaScript can enforce.
174
+ */
175
+ function isConvexEnforceableFilter(filter) {
176
+ if (filter.type === "binary") return !POST_FETCH_ONLY_OPERATORS.has(filter.operator);
177
+ if (filter.type === "unary") {
178
+ const [operand] = filter.operands;
179
+ if (isFieldReference(operand)) return true;
180
+ return isConvexEnforceableFilter(operand);
181
+ }
182
+ if (filter.type === "logical") return filter.operands.every((operand) => isConvexEnforceableFilter(operand));
183
+ return true;
184
+ }
185
+ /**
186
+ * Compile a filter expression to a Convex `.filter()` callback.
187
+ *
188
+ * @param expression - Filter expression tree
189
+ * @param options - Per-lane semantics; see {@link ConvexFilterCompilerOptions}
190
+ */
191
+ function compileConvexFilter(expression, options = {}) {
192
+ const { normalizeValue, nullMatchesUndefined = false } = options;
193
+ const visitor = {
194
+ visitBinary: (expr) => {
195
+ const [field, value] = expr.operands;
196
+ if (!isFieldReference(field)) throw new Error("Binary expression must have FieldReference as first operand");
197
+ const fieldName = field.fieldName;
198
+ const normalizedValue = normalizeValue ? normalizeValue(fieldName, value) : value;
199
+ switch (expr.operator) {
200
+ case "eq": return (q) => q.eq(q.field(fieldName), normalizedValue);
201
+ case "ne": return (q) => q.neq(q.field(fieldName), normalizedValue);
202
+ case "gt": return (q) => q.gt(q.field(fieldName), normalizedValue);
203
+ case "gte": return (q) => q.gte(q.field(fieldName), normalizedValue);
204
+ case "lt": return (q) => q.lt(q.field(fieldName), normalizedValue);
205
+ case "lte": return (q) => q.lte(q.field(fieldName), normalizedValue);
206
+ case "inArray": {
207
+ const values = normalizedValue;
208
+ return (q) => {
209
+ if (values.length === 0) return q.eq(q.field("_id"), NEVER_MATCH_SENTINEL);
210
+ return convexOr(q, values.map((v) => q.eq(q.field(fieldName), v)));
211
+ };
212
+ }
213
+ case "notInArray": {
214
+ const values = normalizedValue;
215
+ return (q) => convexAnd(q, values.map((v) => q.neq(q.field(fieldName), v)));
216
+ }
217
+ case "like":
218
+ case "ilike":
219
+ case "notLike":
220
+ case "notIlike":
221
+ case "startsWith":
222
+ case "endsWith":
223
+ case "contains":
224
+ case "arrayContains":
225
+ case "arrayContained":
226
+ case "arrayOverlaps": return () => true;
227
+ default: throw new Error(`Unsupported binary operator: ${expr.operator}`);
228
+ }
229
+ },
230
+ visitLogical: (expr) => {
231
+ const operandFns = expr.operands.map((op) => op.accept(visitor));
232
+ if (expr.operator === "and") return (q) => convexAnd(q, operandFns.map((fn) => fn(q)));
233
+ if (expr.operator === "or") return (q) => convexOr(q, operandFns.map((fn) => fn(q)));
234
+ throw new Error(`Unsupported logical operator: ${expr.operator}`);
235
+ },
236
+ visitUnary: (expr) => {
237
+ const operand = expr.operands[0];
238
+ if (expr.operator === "not") {
239
+ const operandFn = operand.accept(visitor);
240
+ return (q) => q.not(operandFn(q));
241
+ }
242
+ if (expr.operator === "isNull") {
243
+ if (!isFieldReference(operand)) throw new Error("isNull must operate on a field reference");
244
+ const fieldName = operand.fieldName;
245
+ if (!nullMatchesUndefined) return (q) => q.eq(q.field(fieldName), null);
246
+ return (q) => q.or(q.eq(q.field(fieldName), null), q.eq(q.field(fieldName), void 0));
247
+ }
248
+ if (expr.operator === "isNotNull") {
249
+ if (!isFieldReference(operand)) throw new Error("isNotNull must operate on a field reference");
250
+ const fieldName = operand.fieldName;
251
+ if (!nullMatchesUndefined) return (q) => q.neq(q.field(fieldName), null);
252
+ return (q) => q.and(q.neq(q.field(fieldName), null), q.neq(q.field(fieldName), void 0));
253
+ }
254
+ throw new Error(`Unsupported unary operator: ${expr.operator}`);
255
+ }
256
+ };
257
+ return expression.accept(visitor);
258
+ }
259
+
128
260
  //#endregion
129
261
  //#region src/orm/write-fanout.ts
130
262
  /**
@@ -385,7 +517,9 @@ const deserializeFilterExpression = (expression) => {
385
517
  }
386
518
  if (expression.type === "logical") {
387
519
  const logical = expression;
388
- return createLogicalExpression(logical.operator, logical.operands.map((operand) => deserializeFilterExpression(operand)).filter((operand) => !!operand));
520
+ const operands = logical.operands.map((operand) => deserializeFilterExpression(operand)).filter((operand) => !!operand);
521
+ if (operands.length === 0) throw new Error("Serialized logical expression requires at least one operand.");
522
+ return createLogicalExpression(logical.operator, operands);
389
523
  }
390
524
  const unary = expression;
391
525
  const operand = unary.operand;
@@ -754,9 +888,7 @@ function buildIndexPredicate(q, columns, values) {
754
888
  return builder;
755
889
  }
756
890
  function buildFilterPredicate(q, columns, values) {
757
- let expr = q.eq(q.field(columns[0]), values[0]);
758
- for (let i = 1; i < columns.length; i++) expr = q.and(expr, q.eq(q.field(columns[i]), values[i]));
759
- return expr;
891
+ return convexAnd(q, columns.map((column, index) => q.eq(q.field(column), values[index])));
760
892
  }
761
893
  function ensureNullableColumns(table, columns, context) {
762
894
  for (const columnName of columns) {
@@ -1197,78 +1329,7 @@ function enforceCheckConstraints(table, candidate) {
1197
1329
  for (const check of checks) if (evaluateCheckConstraintTriState(candidate, check.expression) === false) throw new Error(`Check constraint '${check.name}' violation on '${tableName}'.`);
1198
1330
  }
1199
1331
  function toConvexFilter(expression) {
1200
- const visitor = {
1201
- visitBinary: (expr) => {
1202
- const [field, value] = expr.operands;
1203
- if (!isFieldReference(field)) throw new Error("Binary expression must have FieldReference as first operand");
1204
- const fieldName = field.fieldName;
1205
- switch (expr.operator) {
1206
- case "eq": return (q) => q.eq(q.field(fieldName), value);
1207
- case "ne": return (q) => q.neq(q.field(fieldName), value);
1208
- case "gt": return (q) => q.gt(q.field(fieldName), value);
1209
- case "gte": return (q) => q.gte(q.field(fieldName), value);
1210
- case "lt": return (q) => q.lt(q.field(fieldName), value);
1211
- case "lte": return (q) => q.lte(q.field(fieldName), value);
1212
- case "inArray": {
1213
- const values = value;
1214
- return (q) => {
1215
- if (values.length === 0) return q.eq(q.field("_id"), "__better_convex_never__");
1216
- return values.map((v) => q.eq(q.field(fieldName), v)).reduce((acc, cond) => q.or(acc, cond));
1217
- };
1218
- }
1219
- case "notInArray": {
1220
- const values = value;
1221
- return (q) => {
1222
- return values.map((v) => q.neq(q.field(fieldName), v)).reduce((acc, cond) => q.and(acc, cond));
1223
- };
1224
- }
1225
- case "like":
1226
- case "ilike":
1227
- case "notLike":
1228
- case "notIlike":
1229
- case "startsWith":
1230
- case "endsWith":
1231
- case "contains":
1232
- case "arrayContains":
1233
- case "arrayContained":
1234
- case "arrayOverlaps": return () => true;
1235
- default: throw new Error(`Unsupported binary operator: ${expr.operator}`);
1236
- }
1237
- },
1238
- visitLogical: (expr) => {
1239
- const operandFns = expr.operands.map((op) => op.accept(visitor));
1240
- if (expr.operator === "and") return (q) => {
1241
- let result = operandFns[0](q);
1242
- for (let i = 1; i < operandFns.length; i++) result = q.and(result, operandFns[i](q));
1243
- return result;
1244
- };
1245
- if (expr.operator === "or") return (q) => {
1246
- let result = operandFns[0](q);
1247
- for (let i = 1; i < operandFns.length; i++) result = q.or(result, operandFns[i](q));
1248
- return result;
1249
- };
1250
- throw new Error(`Unsupported logical operator: ${expr.operator}`);
1251
- },
1252
- visitUnary: (expr) => {
1253
- const operand = expr.operands[0];
1254
- if (expr.operator === "not") {
1255
- const operandFn = operand.accept(visitor);
1256
- return (q) => q.not(operandFn(q));
1257
- }
1258
- if (expr.operator === "isNull") {
1259
- if (!isFieldReference(operand)) throw new Error("isNull must operate on a field reference");
1260
- const fieldName = operand.fieldName;
1261
- return (q) => q.eq(q.field(fieldName), null);
1262
- }
1263
- if (expr.operator === "isNotNull") {
1264
- if (!isFieldReference(operand)) throw new Error("isNotNull must operate on a field reference");
1265
- const fieldName = operand.fieldName;
1266
- return (q) => q.neq(q.field(fieldName), null);
1267
- }
1268
- throw new Error(`Unsupported unary operator: ${expr.operator}`);
1269
- }
1270
- };
1271
- return expression.accept(visitor);
1332
+ return compileConvexFilter(expression);
1272
1333
  }
1273
1334
 
1274
1335
  //#endregion
@@ -1422,4 +1483,4 @@ function aggregateExtension() {
1422
1483
  }
1423
1484
 
1424
1485
  //#endregion
1425
- export { serializeFilterExpression as $, ensureNonNullValues as A, getMutationExecutionMode as B, deserializeFilterExpression as C, enforcePolymorphicWrite as D, enforceForeignKeys as E, getChecks as F, getUniqueIndexes as G, getTableColumns as H, getColumnName as I, normalizeDateFieldsForWrite as J, hardDeleteRow as K, getForeignKeys as L, evaluateCheckConstraintTriState as M, evaluateFilter as N, enforceUniqueIndexes as O, extractPrimaryIdLookup as P, selectReturningRowWithHydration as Q, getMutationAsyncDelayMs as R, decodeUndefinedDeep as S, enforceCheckConstraints as T, getTableDeleteConfig as U, getOrmContext as V, getTableName as W, patchReferencingRows as X, normalizeTemporalComparableValue as Y, resolveOrmRuntimeDefaults as Z, applyIncomingForeignKeyActionsOnUpdate as _, PUBLIC_CREATED_AT_FIELD as _t, aggregateExtension as a, markLifecycleHookedTables as at, collectMutationRowsBounded as b, AGGREGATE_ERROR as c, findRelationIndex as ct, createCountError as d, getAggregateIndexes as dt, softDeleteRow as et, createError as f, getIndexes as ft, applyIncomingForeignKeyActionsOnDelete as g, INTERNAL_CREATION_TIME_FIELD as gt, applyDefaults as h, CREATED_AT_MIGRATION_MESSAGE as ht, AGGREGATE_STATE_TABLE as i, hasLifecycleHooks as it, ensureNullableColumns as j, ensureDefaultColumns as k, COUNT_ERROR as l, findSearchIndexByName as lt, ensureCountAllowedForRls as m, resolveIndexOrderPushdown as mt, AGGREGATE_EXTREMA_TABLE as n, takeRowsWithinByteBudget as nt, getAggregateIndexDefinitions as o, mapWithConcurrency as ot, ensureAggregateAllowedForRls as p, getRankIndexes as pt, hydrateDateFieldsForRead as q, AGGREGATE_MEMBER_TABLE as r, toConvexFilter as rt, getRankIndexDefinitions as s, findIndexForColumns as st, AGGREGATE_BUCKET_TABLE as t, splitReturningSelection as tt, createAggregateError as u, findVectorIndexByName as ut, buildForeignKeyGraph as v, usesSystemCreatedAtAlias as vt, encodeUndefinedDeep as w, collectPrimaryIdLookupRows as x, canUsePrimaryIdLookupCursor as y, getMutationCollectionLimits as z };
1486
+ export { serializeFilterExpression as $, ensureNonNullValues as A, getMutationExecutionMode as B, deserializeFilterExpression as C, enforcePolymorphicWrite as D, enforceForeignKeys as E, getChecks as F, getUniqueIndexes as G, getTableColumns as H, getColumnName as I, normalizeDateFieldsForWrite as J, hardDeleteRow as K, getForeignKeys as L, evaluateCheckConstraintTriState as M, evaluateFilter as N, enforceUniqueIndexes as O, extractPrimaryIdLookup as P, selectReturningRowWithHydration as Q, getMutationAsyncDelayMs as R, decodeUndefinedDeep as S, enforceCheckConstraints as T, getTableDeleteConfig as U, getOrmContext as V, getTableName as W, patchReferencingRows as X, normalizeTemporalComparableValue as Y, resolveOrmRuntimeDefaults as Z, applyIncomingForeignKeyActionsOnUpdate as _, resolveIndexOrderPushdown as _t, aggregateExtension as a, markLifecycleHookedTables as at, collectMutationRowsBounded as b, PUBLIC_CREATED_AT_FIELD as bt, AGGREGATE_ERROR as c, isConvexEnforceableFilter as ct, createCountError as d, findRelationIndex as dt, softDeleteRow as et, createError as f, findSearchIndexByName as ft, applyIncomingForeignKeyActionsOnDelete as g, getRankIndexes as gt, applyDefaults as h, getIndexes as ht, AGGREGATE_STATE_TABLE as i, hasLifecycleHooks as it, ensureNullableColumns as j, ensureDefaultColumns as k, COUNT_ERROR as l, mapWithConcurrency as lt, ensureCountAllowedForRls as m, getAggregateIndexes as mt, AGGREGATE_EXTREMA_TABLE as n, takeRowsWithinByteBudget as nt, getAggregateIndexDefinitions as o, compileConvexFilter as ot, ensureAggregateAllowedForRls as p, findVectorIndexByName as pt, hydrateDateFieldsForRead as q, AGGREGATE_MEMBER_TABLE as r, toConvexFilter as rt, getRankIndexDefinitions as s, convexAnd as st, AGGREGATE_BUCKET_TABLE as t, splitReturningSelection as tt, createAggregateError as u, findIndexForColumns as ut, buildForeignKeyGraph as v, CREATED_AT_MIGRATION_MESSAGE as vt, encodeUndefinedDeep as w, collectPrimaryIdLookupRows as x, usesSystemCreatedAtAlias as xt, canUsePrimaryIdLookupCursor as y, INTERNAL_CREATION_TIME_FIELD as yt, getMutationCollectionLimits as z };
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
 
@@ -1021,7 +1021,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1021
1021
  fieldName: "updatedAt";
1022
1022
  };
1023
1023
  };
1024
- count: ConvexNumberBuilderInitial<""> & {
1024
+ indexName: ConvexTextBuilderInitial<""> & {
1025
1025
  _: {
1026
1026
  notNull: true;
1027
1027
  };
@@ -1031,10 +1031,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1031
1031
  };
1032
1032
  } & {
1033
1033
  _: {
1034
- fieldName: "count";
1034
+ fieldName: "indexName";
1035
1035
  };
1036
1036
  };
1037
- indexName: ConvexTextBuilderInitial<""> & {
1037
+ tableKey: ConvexTextBuilderInitial<""> & {
1038
1038
  _: {
1039
1039
  notNull: true;
1040
1040
  };
@@ -1044,10 +1044,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1044
1044
  };
1045
1045
  } & {
1046
1046
  _: {
1047
- fieldName: "indexName";
1047
+ fieldName: "tableKey";
1048
1048
  };
1049
1049
  };
1050
- tableKey: ConvexTextBuilderInitial<""> & {
1050
+ count: ConvexNumberBuilderInitial<""> & {
1051
1051
  _: {
1052
1052
  notNull: true;
1053
1053
  };
@@ -1057,7 +1057,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1057
1057
  };
1058
1058
  } & {
1059
1059
  _: {
1060
- fieldName: "tableKey";
1060
+ fieldName: "count";
1061
1061
  };
1062
1062
  };
1063
1063
  keyHash: ConvexTextBuilderInitial<""> & {
@@ -1336,11 +1336,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1336
1336
  fieldName: "updatedAt";
1337
1337
  };
1338
1338
  };
1339
- value: ConvexCustomBuilderInitial<"", convex_values0.VAny<any, "required", string>> & {
1340
- _: {
1341
- $type: convex_values0.Value;
1342
- };
1343
- } & {
1339
+ indexName: ConvexTextBuilderInitial<""> & {
1344
1340
  _: {
1345
1341
  notNull: true;
1346
1342
  };
@@ -1350,10 +1346,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1350
1346
  };
1351
1347
  } & {
1352
1348
  _: {
1353
- fieldName: "value";
1349
+ fieldName: "indexName";
1354
1350
  };
1355
1351
  };
1356
- count: ConvexNumberBuilderInitial<""> & {
1352
+ tableKey: ConvexTextBuilderInitial<""> & {
1357
1353
  _: {
1358
1354
  notNull: true;
1359
1355
  };
@@ -1363,10 +1359,14 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1363
1359
  };
1364
1360
  } & {
1365
1361
  _: {
1366
- fieldName: "count";
1362
+ fieldName: "tableKey";
1367
1363
  };
1368
1364
  };
1369
- indexName: ConvexTextBuilderInitial<""> & {
1365
+ value: ConvexCustomBuilderInitial<"", convex_values0.VAny<any, "required", string>> & {
1366
+ _: {
1367
+ $type: convex_values0.Value;
1368
+ };
1369
+ } & {
1370
1370
  _: {
1371
1371
  notNull: true;
1372
1372
  };
@@ -1376,10 +1376,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1376
1376
  };
1377
1377
  } & {
1378
1378
  _: {
1379
- fieldName: "indexName";
1379
+ fieldName: "value";
1380
1380
  };
1381
1381
  };
1382
- tableKey: ConvexTextBuilderInitial<""> & {
1382
+ count: ConvexNumberBuilderInitial<""> & {
1383
1383
  _: {
1384
1384
  notNull: true;
1385
1385
  };
@@ -1389,7 +1389,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1389
1389
  };
1390
1390
  } & {
1391
1391
  _: {
1392
- fieldName: "tableKey";
1392
+ fieldName: "count";
1393
1393
  };
1394
1394
  };
1395
1395
  keyHash: ConvexTextBuilderInitial<""> & {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kitcn",
3
- "version": "0.25.3",
3
+ "version": "0.25.5",
4
4
  "description": "kitcn - React Query integration and CLI tools for Convex",
5
5
  "keywords": [
6
6
  "convex",
@@ -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`.