kitcn 0.27.4 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,11 @@
1
1
  import { n as asyncMap } from "../upstream-BCgGZX6q.js";
2
2
  import { r as partial } from "../validators-CIoUYCqO.js";
3
- import { i as defineAuth, n as createDisabledAuthRuntime, r as getGeneratedAuthDisabledReason, t as DEFAULT_AUTH_DEFINITION_PATH } from "../generated-contract-disabled-CZa0iyV0.js";
3
+ import { i as defineAuth, n as createDisabledAuthRuntime, r as getGeneratedAuthDisabledReason, t as DEFAULT_AUTH_DEFINITION_PATH } from "../generated-contract-disabled-_1Mjg9pW.js";
4
4
  import { n as createGeneratedFunctionReference, o as isQueryCtx, s as isRunMutationCtx } from "../api-entry-CkDpGYVg.js";
5
5
  import { n as customCtx, r as customMutation } from "../customFunctions-ivbc6-_g.js";
6
6
  import { l as eq } from "../filter-expression-Dydt8wS0.js";
7
7
  import { o as mergedStream, s as stream, t as getByIdWithOrmQueryFallback, u as unsetToken } from "../query-context-DOm5Xm3H.js";
8
- import { n as convex } from "../convex-plugin-DfOhBU9g.js";
8
+ import { n as convex } from "../convex-plugin-Dic0l-k8.js";
9
9
  import { v } from "convex/values";
10
10
  import { internalActionGeneric, internalMutationGeneric, internalQueryGeneric, paginationOptsValidator } from "convex/server";
11
11
  import { createAdapterFactory } from "better-auth/adapters";
@@ -36,7 +36,8 @@ const adapterArgsValidator = v.object({
36
36
  const schemaViewsCache = /* @__PURE__ */ new WeakMap();
37
37
  const EMPTY_SCHEMA_VIEWS = {
38
38
  modelNameToKey: /* @__PURE__ */ new Map(),
39
- uniqueFields: /* @__PURE__ */ new Map()
39
+ uniqueFields: /* @__PURE__ */ new Map(),
40
+ uniqueIndexes: /* @__PURE__ */ new Map()
40
41
  };
41
42
  const getSchemaViews = (betterAuthSchema) => {
42
43
  if (!betterAuthSchema || typeof betterAuthSchema !== "object") return EMPTY_SCHEMA_VIEWS;
@@ -44,15 +45,20 @@ const getSchemaViews = (betterAuthSchema) => {
44
45
  if (cached) return cached;
45
46
  const modelNameToKey = /* @__PURE__ */ new Map();
46
47
  const uniqueFields = /* @__PURE__ */ new Map();
48
+ const uniqueIndexes = /* @__PURE__ */ new Map();
47
49
  for (const [key, model] of Object.entries(betterAuthSchema)) {
48
50
  if (model?.modelName && !modelNameToKey.has(model.modelName)) modelNameToKey.set(model.modelName, key);
49
51
  const unique = /* @__PURE__ */ new Set();
50
- for (const [field, attrs] of Object.entries(model?.fields ?? {})) if (attrs?.unique) unique.add(field);
52
+ for (const [field, attrs] of Object.entries(model?.fields ?? {})) if (attrs?.unique) unique.add(attrs.fieldName ?? field);
51
53
  uniqueFields.set(key, unique);
54
+ uniqueIndexes.set(key, (model?.indexes ?? []).filter((index) => index.unique).map((index) => index.fields.map((field) => {
55
+ return (model?.fields?.[field])?.fieldName ?? field;
56
+ })));
52
57
  }
53
58
  const views = {
54
59
  modelNameToKey,
55
- uniqueFields
60
+ uniqueFields,
61
+ uniqueIndexes
56
62
  };
57
63
  schemaViewsCache.set(betterAuthSchema, views);
58
64
  return views;
@@ -62,9 +68,15 @@ const isUniqueField = (betterAuthSchema, model, field) => {
62
68
  const betterAuthModel = modelNameToKey.get(model) ?? model;
63
69
  return uniqueFields.get(betterAuthModel)?.has(field) ?? false;
64
70
  };
71
+ const getUniqueIndexes = (betterAuthSchema, model) => {
72
+ const { modelNameToKey, uniqueIndexes } = getSchemaViews(betterAuthSchema);
73
+ const betterAuthModel = modelNameToKey.get(model) ?? model;
74
+ return uniqueIndexes.get(betterAuthModel) ?? [];
75
+ };
65
76
  const hasUniqueFields = (betterAuthSchema, model, input) => {
66
77
  for (const field of Object.keys(input)) if (isUniqueField(betterAuthSchema, model, field)) return true;
67
- return false;
78
+ const inputFields = new Set(Object.keys(input));
79
+ return getUniqueIndexes(betterAuthSchema, model).some((fields) => fields.some((field) => inputFields.has(field)));
68
80
  };
69
81
  const findIndex = (schema, args) => {
70
82
  if ((args.where?.length ?? 0) > 1 && args.where?.some((w) => w.connector === "OR")) throw new Error(`OR connector not supported with multiple where statements in findIndex, split up the where statements before calling findIndex: ${JSON.stringify(args.where)}`);
@@ -136,6 +148,25 @@ const checkUniqueFields = async (ctx, schema, betterAuthSchema, table, input, do
136
148
  const existingDoc = await ctx.db.query(table).withIndex(index.indexDescriptor, (q) => q.eq(field, input[field])).unique();
137
149
  if (existingDoc && existingDoc._id !== doc?._id) throw new Error(`${table} ${field} already exists`);
138
150
  }
151
+ const nextDoc = {
152
+ ...doc,
153
+ ...input
154
+ };
155
+ for (const uniqueIndex of getUniqueIndexes(betterAuthSchema, table)) {
156
+ if (uniqueIndex.length === 1 && isUniqueField(betterAuthSchema, table, uniqueIndex[0]) || doc && !uniqueIndex.some((field) => field in input) || !uniqueIndex.every((field) => field in nextDoc)) continue;
157
+ const fields = [...uniqueIndex];
158
+ const tableSchema = schema.tables[table];
159
+ let indexes = [];
160
+ if (tableSchema) indexes = tableSchema[" indexes"] ? tableSchema[" indexes"]() : tableSchema.export().indexes;
161
+ const index = indexes.find(({ fields: indexFields }) => fields.length === indexFields.length && fields.every((field, index) => field === indexFields[index]));
162
+ if (!index) throw new Error(`No index found for ${table} ${fields.join(", ")}`);
163
+ const existingDoc = await ctx.db.query(table).withIndex(index.indexDescriptor, (q) => {
164
+ let query = q;
165
+ for (const field of fields) query = query.eq(field, nextDoc[field]);
166
+ return query;
167
+ }).unique();
168
+ if (existingDoc && existingDoc._id !== doc?._id) throw new Error(`${table} ${uniqueIndex.join(", ")} already exists`);
169
+ }
139
170
  };
140
171
  const selectFields = (doc, select) => {
141
172
  if (!doc) return null;
@@ -557,6 +588,32 @@ const updateOneHandler = async (ctx, args, schema, betterAuthSchema) => {
557
588
  }, triggerCtx);
558
589
  return toConvexSafe(normalizedUpdatedDoc);
559
590
  };
591
+ const incrementOneHandler = async (ctx, args, schema, betterAuthSchema) => {
592
+ const doc = await listOne(ctx, schema, betterAuthSchema, args.input);
593
+ if (!doc) return null;
594
+ const normalizedDoc = withBothIdFields(doc);
595
+ const update = { ...args.input.set };
596
+ for (const [field, delta] of Object.entries(args.input.increment)) {
597
+ const current = normalizedDoc[field];
598
+ if (typeof current !== "number") throw new Error(`Cannot increment non-numeric field ${field}`);
599
+ update[field] = current + delta;
600
+ }
601
+ const id = getDocId$1(normalizedDoc);
602
+ if (!id) throw new Error(`Cannot increment ${args.input.model} without an id`);
603
+ return updateOneHandler(ctx, {
604
+ input: {
605
+ model: args.input.model,
606
+ update,
607
+ where: [{
608
+ field: "_id",
609
+ operator: "eq",
610
+ value: id
611
+ }]
612
+ },
613
+ tableTriggers: args.tableTriggers,
614
+ triggerCtx: args.triggerCtx
615
+ }, schema, betterAuthSchema);
616
+ };
560
617
  const updateManyHandler = async (ctx, args, schema, betterAuthSchema) => {
561
618
  const triggerCtx = args.triggerCtx ?? ctx;
562
619
  const tableTriggers = args.tableTriggers;
@@ -565,26 +622,23 @@ const updateManyHandler = async (ctx, args, schema, betterAuthSchema) => {
565
622
  paginationOpts: args.paginationOpts
566
623
  });
567
624
  const ormTable = resolveOrmTable(ctx, schema, betterAuthSchema, args.input.model);
568
- if (args.input.update) {
569
- if (hasUniqueFields(betterAuthSchema, args.input.model, args.input.update ?? {}) && page.length > 1) throw new Error(`Attempted to set unique fields in multiple documents in ${args.input.model} with the same value. Fields: ${Object.keys(args.input.update ?? {}).join(", ")}`);
570
- await asyncMap(page, async (doc) => {
571
- const normalizedDoc = withBothIdFields(doc);
572
- const update = stripUnsupportedAuthTimestamps(serializeDatesForConvex(await applyBeforeHook(args.input.model, "update", args.input.update ?? {}, tableTriggers?.update?.before, triggerCtx)), schema, betterAuthSchema, args.input.model);
573
- await checkUniqueFields(ctx, schema, betterAuthSchema, args.input.model, update ?? {}, normalizedDoc);
574
- const hookNewDoc = serializeDatesForConvex(withBothIdFields(ormTable ? await ormUpdate(ctx, ormTable.table, normalizedDoc._id, update ?? {}) : await (async () => {
575
- await ctx.db.patch(normalizedDoc._id, update);
576
- return ctx.db.get(normalizedDoc._id);
577
- })()));
578
- const hookOldDoc = serializeDatesForConvex(normalizedDoc);
579
- const id = getDocId$1(hookNewDoc);
580
- await tableTriggers?.update?.after?.(hookNewDoc, triggerCtx);
581
- await tableTriggers?.change?.({
582
- id,
583
- newDoc: hookNewDoc,
584
- oldDoc: hookOldDoc,
585
- operation: "update"
586
- }, triggerCtx);
587
- });
625
+ if (args.input.update) for (const doc of page) {
626
+ const normalizedDoc = withBothIdFields(doc);
627
+ const update = stripUnsupportedAuthTimestamps(serializeDatesForConvex(await applyBeforeHook(args.input.model, "update", args.input.update ?? {}, tableTriggers?.update?.before, triggerCtx)), schema, betterAuthSchema, args.input.model);
628
+ await checkUniqueFields(ctx, schema, betterAuthSchema, args.input.model, update ?? {}, normalizedDoc);
629
+ const hookNewDoc = serializeDatesForConvex(withBothIdFields(ormTable ? await ormUpdate(ctx, ormTable.table, normalizedDoc._id, update ?? {}) : await (async () => {
630
+ await ctx.db.patch(normalizedDoc._id, update);
631
+ return ctx.db.get(normalizedDoc._id);
632
+ })()));
633
+ const hookOldDoc = serializeDatesForConvex(normalizedDoc);
634
+ const id = getDocId$1(hookNewDoc);
635
+ await tableTriggers?.update?.after?.(hookNewDoc, triggerCtx);
636
+ await tableTriggers?.change?.({
637
+ id,
638
+ newDoc: hookNewDoc,
639
+ oldDoc: hookOldDoc,
640
+ operation: "update"
641
+ }, triggerCtx);
588
642
  }
589
643
  return toConvexSafe({
590
644
  ...result,
@@ -592,7 +646,7 @@ const updateManyHandler = async (ctx, args, schema, betterAuthSchema) => {
592
646
  ids: page.map((doc) => withBothIdFields(doc)._id)
593
647
  });
594
648
  };
595
- const deleteOneHandler = async (ctx, args, schema, betterAuthSchema) => {
649
+ const deleteOneWithStoredDoc = async (ctx, args, schema, betterAuthSchema) => {
596
650
  const triggerCtx = args.triggerCtx ?? ctx;
597
651
  const tableTriggers = args.tableTriggers;
598
652
  const doc = await listOne(ctx, schema, betterAuthSchema, args.input);
@@ -610,7 +664,16 @@ const deleteOneHandler = async (ctx, args, schema, betterAuthSchema) => {
610
664
  oldDoc: hookDoc,
611
665
  operation: "delete"
612
666
  }, triggerCtx);
613
- return toConvexSafe(withBothIdFields(hookDoc));
667
+ return {
668
+ hookDoc: toConvexSafe(withBothIdFields(hookDoc)),
669
+ storedDoc: toConvexSafe(withBothIdFields(normalizedDoc))
670
+ };
671
+ };
672
+ const deleteOneHandler = async (ctx, args, schema, betterAuthSchema) => {
673
+ return (await deleteOneWithStoredDoc(ctx, args, schema, betterAuthSchema))?.hookDoc;
674
+ };
675
+ const consumeOneHandler = async (ctx, args, schema, betterAuthSchema) => {
676
+ return (await deleteOneWithStoredDoc(ctx, args, schema, betterAuthSchema))?.storedDoc ?? null;
614
677
  };
615
678
  const deleteManyHandler = async (ctx, args, schema, betterAuthSchema) => {
616
679
  const triggerCtx = args.triggerCtx ?? ctx;
@@ -691,7 +754,24 @@ const createApi = (schema, getAuth, options) => {
691
754
  where: v.optional(v.array(whereValidator(schema, tableName)))
692
755
  });
693
756
  })) : anyInputWithUpdate;
757
+ const incrementInput = v.object({
758
+ increment: v.record(v.string(), v.number()),
759
+ model: modelValidator,
760
+ set: v.optional(v.record(v.string(), v.any())),
761
+ where: v.optional(v.array(adapterWhereValidator))
762
+ });
694
763
  return {
764
+ consumeOne: mutationBuilder({
765
+ args: { input: deleteInput },
766
+ handler: async (ctx, args) => {
767
+ const triggerCtx = ctx;
768
+ return consumeOneHandler(ctx, {
769
+ input: args.input,
770
+ tableTriggers: resolveTableTriggers(args.input.model, triggerCtx),
771
+ triggerCtx
772
+ }, schema, getBetterAuthSchema());
773
+ }
774
+ }),
695
775
  create: mutationBuilder({
696
776
  args: {
697
777
  input: createInput,
@@ -763,6 +843,17 @@ const createApi = (schema, getAuth, options) => {
763
843
  return getAuth(ctx).api.getLatestJwks();
764
844
  }
765
845
  }),
846
+ incrementOne: mutationBuilder({
847
+ args: { input: incrementInput },
848
+ handler: async (ctx, args) => {
849
+ const triggerCtx = ctx;
850
+ return incrementOneHandler(ctx, {
851
+ input: args.input,
852
+ tableTriggers: resolveTableTriggers(args.input.model, triggerCtx),
853
+ triggerCtx
854
+ }, schema, getBetterAuthSchema());
855
+ }
856
+ }),
766
857
  rotateKeys: internalActionGeneric({
767
858
  args: {},
768
859
  handler: async (ctx) => {
@@ -800,7 +891,21 @@ const createApi = (schema, getAuth, options) => {
800
891
 
801
892
  //#endregion
802
893
  //#region src/auth/adapter.ts
803
- let didWarnExperimentalJoinsUnsupported = false;
894
+ let didWarnJoinsUnsupported = false;
895
+ const disableUnsupportedJoins = (options) => {
896
+ if (!options.advanced?.database?.joins) return;
897
+ options.advanced = {
898
+ ...options.advanced,
899
+ database: {
900
+ ...options.advanced.database,
901
+ joins: false
902
+ }
903
+ };
904
+ if (!didWarnJoinsUnsupported) {
905
+ didWarnJoinsUnsupported = true;
906
+ console.warn("[kitcn] Better Auth advanced.database.joins is not supported by the Convex adapter yet. Forcing advanced.database.joins = false.");
907
+ }
908
+ };
804
909
  const handlePagination = async (next, { countOnly, limit, numItems } = {}) => {
805
910
  const state = {
806
911
  count: 0,
@@ -908,13 +1013,13 @@ const ORM_SCHEMA_OPTIONS = Symbol.for("kitcn:OrmSchemaOptions");
908
1013
  const hasOrmSchemaMetadata = (schema) => !!schema && typeof schema === "object" && ORM_SCHEMA_OPTIONS in schema;
909
1014
  const createAuthSchema = async ({ file, schema, tables }) => {
910
1015
  if (hasOrmSchemaMetadata(schema)) {
911
- const { createSchemaOrm } = await import("../create-schema-orm-C3y6GLwQ.js");
1016
+ const { createSchemaOrm } = await import("../create-schema-orm-HcJzGCxj.js");
912
1017
  return createSchemaOrm({
913
1018
  file,
914
1019
  tables
915
1020
  });
916
1021
  }
917
- const { createSchema } = await import("../create-schema-DqhLA_UF.js");
1022
+ const { createSchema } = await import("../create-schema-ojI-OH_9.js");
918
1023
  return createSchema({
919
1024
  file,
920
1025
  tables
@@ -928,16 +1033,7 @@ const httpAdapter = (ctx, { authFunctions, debugLogs, schema }) => {
928
1033
  },
929
1034
  adapter: ({ options }) => {
930
1035
  options.telemetry = { enabled: false };
931
- if (options.experimental?.joins) {
932
- options.experimental = {
933
- ...options.experimental,
934
- joins: false
935
- };
936
- if (!didWarnExperimentalJoinsUnsupported) {
937
- didWarnExperimentalJoinsUnsupported = true;
938
- console.warn("[kitcn] Better Auth experimental.joins is not supported by the Convex adapter yet. Forcing experimental.joins = false.");
939
- }
940
- }
1036
+ disableUnsupportedJoins(options);
941
1037
  const collectIdsForOrWhere = async (data) => {
942
1038
  return dedupeDocsById((await asyncMap(data.where, async (w) => handlePagination(async ({ paginationOpts }) => await ctx.runQuery(authFunctions.findMany, {
943
1039
  model: data.model,
@@ -961,6 +1057,13 @@ const httpAdapter = (ctx, { authFunctions, debugLogs, schema }) => {
961
1057
  where: parseWhere(data.where)
962
1058
  }), { countOnly: true })).count;
963
1059
  },
1060
+ consumeOne: async (data) => {
1061
+ if (!("runMutation" in ctx)) throw new Error("ctx is not a mutation ctx");
1062
+ return await ctx.runMutation(authFunctions.consumeOne, { input: {
1063
+ model: data.model,
1064
+ where: parseWhere(data.where)
1065
+ } });
1066
+ },
964
1067
  create: async ({ data, model, select }) => {
965
1068
  if (!("runMutation" in ctx)) throw new Error("ctx is not a mutation ctx");
966
1069
  return await ctx.runMutation(authFunctions.create, {
@@ -1045,6 +1148,15 @@ const httpAdapter = (ctx, { authFunctions, debugLogs, schema }) => {
1045
1148
  where: parsedWhere
1046
1149
  });
1047
1150
  },
1151
+ incrementOne: async (data) => {
1152
+ if (!("runMutation" in ctx)) throw new Error("ctx is not a mutation ctx");
1153
+ const { set, ...input } = data;
1154
+ return await ctx.runMutation(authFunctions.incrementOne, { input: {
1155
+ ...input,
1156
+ ...set === void 0 ? {} : { set },
1157
+ where: parseWhere(data.where)
1158
+ } });
1159
+ },
1048
1160
  update: async (data) => {
1049
1161
  if (!("runMutation" in ctx)) throw new Error("ctx is not a mutation ctx");
1050
1162
  if (!data.where?.length) return null;
@@ -1097,16 +1209,7 @@ const dbAdapter = (ctx, { authFunctions, debugLogs, getBetterAuthSchema, schema
1097
1209
  },
1098
1210
  adapter: ({ options }) => {
1099
1211
  options.telemetry = { enabled: false };
1100
- if (options.experimental?.joins) {
1101
- options.experimental = {
1102
- ...options.experimental,
1103
- joins: false
1104
- };
1105
- if (!didWarnExperimentalJoinsUnsupported) {
1106
- didWarnExperimentalJoinsUnsupported = true;
1107
- console.warn("[kitcn] Better Auth experimental.joins is not supported by the Convex adapter yet. Forcing experimental.joins = false.");
1108
- }
1109
- }
1212
+ disableUnsupportedJoins(options);
1110
1213
  const collectIdsForOrWhere = async (data) => {
1111
1214
  return dedupeDocsById((await asyncMap(data.where, async (w) => handlePagination(async ({ paginationOpts }) => await findManyHandler(ctx, {
1112
1215
  model: data.model,
@@ -1130,6 +1233,13 @@ const dbAdapter = (ctx, { authFunctions, debugLogs, getBetterAuthSchema, schema
1130
1233
  where: parseWhere(data.where)
1131
1234
  }, schema, betterAuthSchema), { countOnly: true })).count;
1132
1235
  },
1236
+ consumeOne: async (data) => {
1237
+ if (!("runMutation" in ctx)) throw new Error("ctx is not a mutation ctx");
1238
+ return await ctx.runMutation(authFunctions.consumeOne, { input: {
1239
+ model: data.model,
1240
+ where: parseWhere(data.where)
1241
+ } });
1242
+ },
1133
1243
  create: async ({ data, model, select }) => {
1134
1244
  if (!("runMutation" in ctx)) throw new Error("ctx is not a mutation ctx");
1135
1245
  return await ctx.runMutation(authFunctions.create, {
@@ -1213,6 +1323,15 @@ const dbAdapter = (ctx, { authFunctions, debugLogs, getBetterAuthSchema, schema
1213
1323
  where: parseWhere(data.where)
1214
1324
  }, schema, betterAuthSchema);
1215
1325
  },
1326
+ incrementOne: async (data) => {
1327
+ if (!("runMutation" in ctx)) throw new Error("ctx is not a mutation ctx");
1328
+ const { set, ...input } = data;
1329
+ return await ctx.runMutation(authFunctions.incrementOne, { input: {
1330
+ ...input,
1331
+ ...set === void 0 ? {} : { set },
1332
+ where: parseWhere(data.where)
1333
+ } });
1334
+ },
1216
1335
  update: async (data) => {
1217
1336
  if (!data.where?.length) return null;
1218
1337
  if (data.where.every((w) => (w.operator === "eq" || w.operator === void 0) && w.connector !== "OR")) {
@@ -1333,12 +1452,14 @@ const createLazyAuthProxy = (resolve) => new Proxy({}, { get(_target, prop, rece
1333
1452
  return typeof value === "function" ? value.bind(auth) : value;
1334
1453
  } });
1335
1454
  const AUTH_RUNTIME_PROCEDURE_TYPES = {
1455
+ consumeOne: "mutation",
1336
1456
  create: "mutation",
1337
1457
  deleteMany: "mutation",
1338
1458
  deleteOne: "mutation",
1339
1459
  findMany: "query",
1340
1460
  findOne: "query",
1341
1461
  getLatestJwks: "action",
1462
+ incrementOne: "mutation",
1342
1463
  rotateKeys: "action",
1343
1464
  updateMany: "mutation",
1344
1465
  updateOne: "mutation"
@@ -1347,11 +1468,13 @@ const createGeneratedInternalFunctionReference = (name) => createGeneratedFuncti
1347
1468
  const resolveAuthFunctions = (internal, moduleName) => {
1348
1469
  const existing = internal?.[moduleName] ?? {};
1349
1470
  return {
1471
+ consumeOne: existing.consumeOne ?? createGeneratedInternalFunctionReference(`${moduleName}:consumeOne`),
1350
1472
  create: existing.create ?? createGeneratedInternalFunctionReference(`${moduleName}:create`),
1351
1473
  deleteMany: existing.deleteMany ?? createGeneratedInternalFunctionReference(`${moduleName}:deleteMany`),
1352
1474
  deleteOne: existing.deleteOne ?? createGeneratedInternalFunctionReference(`${moduleName}:deleteOne`),
1353
1475
  findMany: existing.findMany ?? createGeneratedInternalFunctionReference(`${moduleName}:findMany`),
1354
1476
  findOne: existing.findOne ?? createGeneratedInternalFunctionReference(`${moduleName}:findOne`),
1477
+ incrementOne: existing.incrementOne ?? createGeneratedInternalFunctionReference(`${moduleName}:incrementOne`),
1355
1478
  updateMany: existing.updateMany ?? createGeneratedInternalFunctionReference(`${moduleName}:updateMany`),
1356
1479
  updateOne: existing.updateOne ?? createGeneratedInternalFunctionReference(`${moduleName}:updateOne`)
1357
1480
  };
@@ -1486,4 +1609,4 @@ const getHeaders = async (ctx, session) => {
1486
1609
  };
1487
1610
 
1488
1611
  //#endregion
1489
- export { adapterArgsValidator, adapterConfig, adapterWhereValidator, checkUniqueFields, convex, createApi, createAuthRuntime, createClient, createDisabledAuthRuntime, createHandler, dbAdapter, defineAuth, deleteManyHandler, deleteOneHandler, findManyHandler, findOneHandler, getAuthUserId, getAuthUserIdentity, getGeneratedAuthDisabledReason, getHeaders, getInvalidAuthDefinitionExportReason, getSession, getSessionNetworkSignals, handlePagination, hasUniqueFields, httpAdapter, listOne, paginate, resolveGeneratedAuthDefinition, selectFields, updateManyHandler, updateOneHandler };
1612
+ export { adapterArgsValidator, adapterConfig, adapterWhereValidator, checkUniqueFields, consumeOneHandler, convex, createApi, createAuthRuntime, createClient, createDisabledAuthRuntime, createHandler, dbAdapter, defineAuth, deleteManyHandler, deleteOneHandler, findManyHandler, findOneHandler, getAuthUserId, getAuthUserIdentity, getGeneratedAuthDisabledReason, getHeaders, getInvalidAuthDefinitionExportReason, getSession, getSessionNetworkSignals, handlePagination, hasUniqueFields, httpAdapter, incrementOneHandler, listOne, paginate, resolveGeneratedAuthDefinition, selectFields, updateManyHandler, updateOneHandler };
@@ -1,4 +1,4 @@
1
- import { t as getToken } from "../../token-DcV_0fkF.js";
1
+ import { t as getToken } from "../../token-B0NKKxqP.js";
2
2
  import { n as defaultIsUnauthorized } from "../../error-CMLeCadS.js";
3
3
  import { t as createCallerFactory } from "../../caller-factory-D4pz5GcZ.js";
4
4
 
@@ -1,4 +1,4 @@
1
- import { t as getToken } from "../../../token-DcV_0fkF.js";
1
+ import { t as getToken } from "../../../token-B0NKKxqP.js";
2
2
  import { n as defaultIsUnauthorized } from "../../../error-CMLeCadS.js";
3
3
  import { t as createCallerFactory } from "../../../caller-factory-D4pz5GcZ.js";
4
4
  import { stripIndent } from "common-tags";
@@ -2896,6 +2896,24 @@ declare class GelRelationalQuery<TSchema extends TablesRelationalConfig, TTableC
2896
2896
  rls?: RlsContext | undefined, relationLoading?: {
2897
2897
  concurrency?: number;
2898
2898
  } | undefined, vectorSearchProvider?: VectorSearchProvider | undefined, configuredIndex?: PredicateWhereIndexConfig<TTableConfig> | undefined, countIndexReadiness?: Map<string, Promise<void>>);
2899
+ /**
2900
+ * Relation counts for a document the caller is already holding.
2901
+ *
2902
+ * `returning({ _count })` runs inside the mutation that just wrote the row,
2903
+ * so resolving it through `execute()` spends one `db.get` re-reading a
2904
+ * document that is already in the transaction's write set. The count engine
2905
+ * only ever reads the counted edges' source fields off its parent, and the
2906
+ * caller's document carries all of them, so the root read is pure waste.
2907
+ * Everything else `execute()` would have done to that row — the select-plan
2908
+ * assertion and the RLS select filter — still runs here.
2909
+ *
2910
+ * Reached through the static accessor below rather than exposed on the instance:
2911
+ * `GelRelationalQuery` is the declared return type of the public query
2912
+ * builders, so an instance method would land in every user's autocomplete.
2913
+ */
2914
+ private _countRelationsForHeldRow;
2915
+ /** @internal Accessor for `returning({ _count })`; see `returning-count.ts`. */
2916
+ static countRelationsForHeldRow(query: GelRelationalQuery<any, any, any>, row: Record<string, unknown>, countSelection: Record<string, unknown>): Promise<Record<string, number>>;
2899
2917
  /**
2900
2918
  * The aggregate-index runtime, registered at `createOrm()`.
2901
2919
  *
package/dist/cli.mjs CHANGED
@@ -2321,8 +2321,8 @@ const SUPPORTED_CONCAVE_CLI_VERSION = "0.0.1-alpha.14";
2321
2321
  const SUPPORTED_CONVEX_VERSION = "1.44.0";
2322
2322
  const SUPPORTED_CONVEX_MIN_VERSION = "1.42";
2323
2323
  const SUPPORTED_CONVEX_MIN_TYPE_VERSION = "1.42.3";
2324
- const SUPPORTED_BETTER_AUTH_VERSION = "1.6.18";
2325
- const SUPPORTED_BETTER_AUTH_MIN_VERSION = "1.6.11";
2324
+ const SUPPORTED_BETTER_AUTH_VERSION = "1.7.1";
2325
+ const SUPPORTED_BETTER_AUTH_MIN_VERSION = "1.7.0";
2326
2326
  const SUPPORTED_HONO_VERSION = "4.12.9";
2327
2327
  const SUPPORTED_OPENTELEMETRY_API_VERSION = "1.9.0";
2328
2328
  const SUPPORTED_TANSTACK_REACT_QUERY_VERSION = "5.95.2";
@@ -2412,6 +2412,7 @@ const SUPPORTED_DEPENDENCY_VERSIONS = {
2412
2412
  };
2413
2413
  const PINNED_CONVEX_INSTALL_SPEC = `convex@${SUPPORTED_DEPENDENCY_VERSIONS.convex.exact}`;
2414
2414
  const BETTER_AUTH_INSTALL_SPEC = `better-auth@${SUPPORTED_DEPENDENCY_VERSIONS.betterAuth.exact}`;
2415
+ const BETTER_AUTH_EXPO_INSTALL_SPEC = `@better-auth/expo@${SUPPORTED_DEPENDENCY_VERSIONS.betterAuth.exact}`;
2415
2416
  const PINNED_HONO_INSTALL_SPEC = `hono@${SUPPORTED_DEPENDENCY_VERSIONS.hono.exact}`;
2416
2417
  const OPENTELEMETRY_API_INSTALL_SPEC = `@opentelemetry/api@${SUPPORTED_DEPENDENCY_VERSIONS.opentelemetryApi.exact}`;
2417
2418
  const PINNED_TANSTACK_REACT_QUERY_INSTALL_SPEC = `@tanstack/react-query@${SUPPORTED_DEPENDENCY_VERSIONS.tanstackReactQuery.exact}`;
@@ -5916,8 +5917,20 @@ const mergedIndexFields$1 = (tables) => Object.fromEntries(Object.entries(tables
5916
5917
  if (resolved.length === index.length) indexes.push(resolved);
5917
5918
  return indexes;
5918
5919
  }, []) || [];
5919
- const specialFieldIndexes = Object.keys(specialFields$1(tables)[key] || {}).filter((index) => !manualIndexes.some((m) => Array.isArray(m) ? m[0] === index : m === index));
5920
- return [key, manualIndexes.concat(specialFieldIndexes)];
5920
+ const declaredIndexes = (table.indexes ?? []).reduce((indexes, index) => {
5921
+ const resolved = index.fields.map((fieldKey) => resolveIndexField(fieldKey)).filter((fieldName) => fieldName !== null);
5922
+ if (resolved.length === index.fields.length) indexes.push(resolved.length === 1 ? resolved[0] : resolved);
5923
+ return indexes;
5924
+ }, []);
5925
+ const explicitIndexes = manualIndexes.concat(declaredIndexes);
5926
+ const specialFieldIndexes = Object.keys(specialFields$1(tables)[key] || {}).filter((index) => !explicitIndexes.some((m) => Array.isArray(m) ? m[0] === index : m === index));
5927
+ const seen = /* @__PURE__ */ new Set();
5928
+ return [key, explicitIndexes.concat(specialFieldIndexes).filter((index) => {
5929
+ const key = (Array.isArray(index) ? index : [index]).join("\0");
5930
+ if (seen.has(key)) return false;
5931
+ seen.add(key);
5932
+ return true;
5933
+ })];
5921
5934
  }));
5922
5935
  const createSchema = async ({ exportName = "tables", file, regenerateCommand, tables }) => {
5923
5936
  const path = await import(Buffer.from("cGF0aA==", "base64").toString());
@@ -5948,7 +5961,7 @@ export const ${exportName} = {
5948
5961
  }[type];
5949
5962
  }
5950
5963
  const indexes = mergedIndexFields$1(tables)[tableKey]?.map((index) => {
5951
- const indexArray = Array.isArray(index) ? index.sort() : [index];
5964
+ const indexArray = Array.isArray(index) ? index : [index];
5952
5965
  return `.index("${indexArray.join("_")}", ${JSON.stringify(indexArray)})`;
5953
5966
  }) || [];
5954
5967
  const schema = `${modelName}: defineTable({
@@ -5999,8 +6012,20 @@ const mergedIndexFields = (tables) => Object.fromEntries(Object.entries(tables).
5999
6012
  if (resolved.length === index.length) indexes.push(resolved);
6000
6013
  return indexes;
6001
6014
  }, []) || [];
6002
- const specialFieldIndexes = Object.entries(tableSpecialFields).filter(([, fieldMeta]) => fieldMeta.unique !== true).map(([fieldName]) => fieldName).filter((index) => !manualIndexes.some((m) => Array.isArray(m) ? m[0] === index : m === index));
6003
- return [key, manualIndexes.concat(specialFieldIndexes)];
6015
+ const declaredIndexes = (table.indexes ?? []).reduce((indexes, index) => {
6016
+ const resolved = index.fields.map((fieldKey) => resolveIndexField(fieldKey)).filter((fieldName) => fieldName !== null);
6017
+ if (resolved.length === index.fields.length) indexes.push(resolved.length === 1 ? resolved[0] : resolved);
6018
+ return indexes;
6019
+ }, []);
6020
+ const explicitIndexes = manualIndexes.concat(declaredIndexes);
6021
+ const specialFieldIndexes = Object.entries(tableSpecialFields).filter(([, fieldMeta]) => fieldMeta.unique !== true).map(([fieldName]) => fieldName).filter((index) => !explicitIndexes.some((m) => Array.isArray(m) ? m[0] === index : m === index));
6022
+ const seen = /* @__PURE__ */ new Set();
6023
+ return [key, explicitIndexes.concat(specialFieldIndexes).filter((index) => {
6024
+ const key = (Array.isArray(index) ? index : [index]).join("\0");
6025
+ if (seen.has(key)) return false;
6026
+ seen.add(key);
6027
+ return true;
6028
+ })];
6004
6029
  }));
6005
6030
  const VALID_IDENTIFIER_REGEX = /^[$A-Z_][0-9A-Z_$]*$/i;
6006
6031
  const LEADING_DIGIT_REGEX = /^[0-9]/;
@@ -6152,11 +6177,19 @@ const renderSchemaOrmFile = async ({ extensionKey, exportName, file, mode, regen
6152
6177
  return ` ${key}: ${expression},`;
6153
6178
  });
6154
6179
  const indexes = mergedIndexFields(tables)[entry.key]?.map((indexSpec) => {
6155
- const indexArray = Array.isArray(indexSpec) ? [...indexSpec].sort() : [indexSpec];
6180
+ const indexArray = Array.isArray(indexSpec) ? indexSpec : [indexSpec];
6156
6181
  const indexName = indexArray.join("_");
6157
- state.ormImports.add("index");
6182
+ const indexFactory = (entry.table.indexes ?? []).some((index) => {
6183
+ if (!index.unique) return false;
6184
+ const resolvedFields = index.fields.map((fieldKey) => {
6185
+ const field = entry.table.fields[fieldKey];
6186
+ return field ? field.fieldName ?? fieldKey : null;
6187
+ }).filter((fieldName) => fieldName !== null);
6188
+ return resolvedFields.length === index.fields.length && resolvedFields.join("\0") === indexArray.join("\0");
6189
+ }) ? "uniqueIndex" : "index";
6190
+ state.ormImports.add(indexFactory);
6158
6191
  const fieldsCall = indexArray.map((fieldName) => renderPropertyAccess(entry.varName, fieldName)).join(", ");
6159
- return `index(${JSON.stringify(indexName)}).on(${fieldsCall})`;
6192
+ return `${indexFactory}(${JSON.stringify(indexName)}).on(${fieldsCall})`;
6160
6193
  }) || [];
6161
6194
  const extraConfig = indexes.length > 0 ? `,\n (${entry.varName}) => [\n ${indexes.join(",\n ")},\n ]` : "";
6162
6195
  tableBlocks.push(`export const ${entry.varName} = convexTable(\n ${JSON.stringify(entry.modelName)},\n {\n${fieldLines.join("\n")}\n }${extraConfig}\n);`);
@@ -6430,7 +6463,6 @@ const AUTH_ENV_FIELDS = [
6430
6463
  schema: "z.string().optional()"
6431
6464
  }
6432
6465
  ];
6433
- const BETTER_AUTH_EXPO_INSTALL_SPEC = "@better-auth/expo@1.6.18";
6434
6466
  const EXPO_SECURE_STORE_INSTALL_SPEC = "expo-secure-store@~55.0.8";
6435
6467
  const EXPO_NETWORK_INSTALL_SPEC = "expo-network@~55.0.8";
6436
6468
  const AUTH_FILES = [