@neutralauth/internal-auth 0.10.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +39 -0
  3. package/dist/auth-config.d.ts +43 -0
  4. package/dist/auth-config.d.ts.map +1 -0
  5. package/dist/auth-config.js +43 -0
  6. package/dist/auth-config.js.map +1 -0
  7. package/dist/auth-options.d.ts +3 -0
  8. package/dist/auth-options.d.ts.map +1 -0
  9. package/dist/auth-options.js +40 -0
  10. package/dist/auth-options.js.map +1 -0
  11. package/dist/auth.d.ts +2 -0
  12. package/dist/auth.d.ts.map +1 -0
  13. package/dist/auth.js +4 -0
  14. package/dist/auth.js.map +1 -0
  15. package/dist/client/adapter-utils.d.ts +66 -0
  16. package/dist/client/adapter-utils.d.ts.map +1 -0
  17. package/dist/client/adapter-utils.js +437 -0
  18. package/dist/client/adapter-utils.js.map +1 -0
  19. package/dist/client/adapter.d.ts +14 -0
  20. package/dist/client/adapter.d.ts.map +1 -0
  21. package/dist/client/adapter.js +274 -0
  22. package/dist/client/adapter.js.map +1 -0
  23. package/dist/client/create-api.d.ts +141 -0
  24. package/dist/client/create-api.d.ts.map +1 -0
  25. package/dist/client/create-api.js +205 -0
  26. package/dist/client/create-api.js.map +1 -0
  27. package/dist/client/create-client.d.ts +183 -0
  28. package/dist/client/create-client.d.ts.map +1 -0
  29. package/dist/client/create-client.js +311 -0
  30. package/dist/client/create-client.js.map +1 -0
  31. package/dist/client/create-schema.d.ts +19 -0
  32. package/dist/client/create-schema.d.ts.map +1 -0
  33. package/dist/client/create-schema.js +114 -0
  34. package/dist/client/create-schema.js.map +1 -0
  35. package/dist/client/index.d.ts +7 -0
  36. package/dist/client/index.d.ts.map +1 -0
  37. package/dist/client/index.js +10 -0
  38. package/dist/client/index.js.map +1 -0
  39. package/dist/client/plugins/index.d.ts +3 -0
  40. package/dist/client/plugins/index.d.ts.map +1 -0
  41. package/dist/client/plugins/index.js +3 -0
  42. package/dist/client/plugins/index.js.map +1 -0
  43. package/dist/component/_generated/api.d.ts +36 -0
  44. package/dist/component/_generated/api.d.ts.map +1 -0
  45. package/dist/component/_generated/api.js +31 -0
  46. package/dist/component/_generated/api.js.map +1 -0
  47. package/dist/component/_generated/component.d.ts +787 -0
  48. package/dist/component/_generated/component.d.ts.map +1 -0
  49. package/dist/component/_generated/component.js +11 -0
  50. package/dist/component/_generated/component.js.map +1 -0
  51. package/dist/component/_generated/dataModel.d.ts +46 -0
  52. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  53. package/dist/component/_generated/dataModel.js +11 -0
  54. package/dist/component/_generated/dataModel.js.map +1 -0
  55. package/dist/component/_generated/server.d.ts +121 -0
  56. package/dist/component/_generated/server.d.ts.map +1 -0
  57. package/dist/component/_generated/server.js +78 -0
  58. package/dist/component/_generated/server.js.map +1 -0
  59. package/dist/component/adapter.d.ts +130 -0
  60. package/dist/component/adapter.d.ts.map +1 -0
  61. package/dist/component/adapter.js +5 -0
  62. package/dist/component/adapter.js.map +1 -0
  63. package/dist/component/adapterTest.d.ts +10 -0
  64. package/dist/component/adapterTest.d.ts.map +1 -0
  65. package/dist/component/adapterTest.js +409 -0
  66. package/dist/component/adapterTest.js.map +1 -0
  67. package/dist/component/convex.config.d.ts +3 -0
  68. package/dist/component/convex.config.d.ts.map +1 -0
  69. package/dist/component/convex.config.js +4 -0
  70. package/dist/component/convex.config.js.map +1 -0
  71. package/dist/component/schema.d.ts +474 -0
  72. package/dist/component/schema.d.ts.map +1 -0
  73. package/dist/component/schema.js +139 -0
  74. package/dist/component/schema.js.map +1 -0
  75. package/dist/nextjs/client.d.ts +4 -0
  76. package/dist/nextjs/client.d.ts.map +1 -0
  77. package/dist/nextjs/client.js +37 -0
  78. package/dist/nextjs/client.js.map +1 -0
  79. package/dist/nextjs/index.d.ts +22 -0
  80. package/dist/nextjs/index.d.ts.map +1 -0
  81. package/dist/nextjs/index.js +98 -0
  82. package/dist/nextjs/index.js.map +1 -0
  83. package/dist/plugins/convex/client.d.ts +6 -0
  84. package/dist/plugins/convex/client.d.ts.map +1 -0
  85. package/dist/plugins/convex/client.js +7 -0
  86. package/dist/plugins/convex/client.js.map +1 -0
  87. package/dist/plugins/convex/index.d.ts +322 -0
  88. package/dist/plugins/convex/index.d.ts.map +1 -0
  89. package/dist/plugins/convex/index.js +422 -0
  90. package/dist/plugins/convex/index.js.map +1 -0
  91. package/dist/plugins/cross-domain/client.d.ts +132 -0
  92. package/dist/plugins/cross-domain/client.d.ts.map +1 -0
  93. package/dist/plugins/cross-domain/client.js +192 -0
  94. package/dist/plugins/cross-domain/client.js.map +1 -0
  95. package/dist/plugins/cross-domain/index.d.ts +51 -0
  96. package/dist/plugins/cross-domain/index.d.ts.map +1 -0
  97. package/dist/plugins/cross-domain/index.js +173 -0
  98. package/dist/plugins/cross-domain/index.js.map +1 -0
  99. package/dist/plugins/index.d.ts +3 -0
  100. package/dist/plugins/index.d.ts.map +1 -0
  101. package/dist/plugins/index.js +3 -0
  102. package/dist/plugins/index.js.map +1 -0
  103. package/dist/react/index.d.ts +80 -0
  104. package/dist/react/index.d.ts.map +1 -0
  105. package/dist/react/index.js +190 -0
  106. package/dist/react/index.js.map +1 -0
  107. package/dist/react-start/index.d.ts +13 -0
  108. package/dist/react-start/index.d.ts.map +1 -0
  109. package/dist/react-start/index.js +101 -0
  110. package/dist/react-start/index.js.map +1 -0
  111. package/dist/utils/index.d.ts +33 -0
  112. package/dist/utils/index.d.ts.map +1 -0
  113. package/dist/utils/index.js +91 -0
  114. package/dist/utils/index.js.map +1 -0
  115. package/package.json +208 -0
  116. package/src/auth-config.ts +80 -0
  117. package/src/auth-options.ts +54 -0
  118. package/src/auth.ts +4 -0
  119. package/src/client/adapter-utils.ts +639 -0
  120. package/src/client/adapter.test.ts +83 -0
  121. package/src/client/adapter.ts +363 -0
  122. package/src/client/create-api.ts +339 -0
  123. package/src/client/create-client.ts +452 -0
  124. package/src/client/create-schema.ts +166 -0
  125. package/src/client/index.ts +22 -0
  126. package/src/client/plugins/index.ts +2 -0
  127. package/src/component/_generated/api.ts +52 -0
  128. package/src/component/_generated/component.ts +2008 -0
  129. package/src/component/_generated/dataModel.ts +60 -0
  130. package/src/component/_generated/server.ts +161 -0
  131. package/src/component/adapter.ts +13 -0
  132. package/src/component/adapterTest.ts +505 -0
  133. package/src/component/convex.config.ts +5 -0
  134. package/src/component/schema.ts +142 -0
  135. package/src/nextjs/client.tsx +54 -0
  136. package/src/nextjs/index.ts +152 -0
  137. package/src/plugins/convex/client.ts +9 -0
  138. package/src/plugins/convex/index.ts +596 -0
  139. package/src/plugins/cross-domain/client.test.ts +217 -0
  140. package/src/plugins/cross-domain/client.ts +234 -0
  141. package/src/plugins/cross-domain/index.ts +199 -0
  142. package/src/plugins/index.ts +2 -0
  143. package/src/react/index.tsx +304 -0
  144. package/src/react-start/index.ts +153 -0
  145. package/src/react-start/vite-env.d.ts +2 -0
  146. package/src/test.ts +18 -0
  147. package/src/utils/index.ts +171 -0
@@ -0,0 +1,83 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ import { describe } from "vitest";
4
+ import type { runAdapterTest } from "better-auth/adapters/test";
5
+ import { convexTest } from "convex-test";
6
+ import { api } from "../component/_generated/api.js";
7
+ import schema from "../component/schema.js";
8
+ import { createClient } from "./create-client.js";
9
+ import type { DataModel } from "../component/_generated/dataModel.js";
10
+ import type { BetterAuthOptions } from "better-auth/types";
11
+ import type { GenericCtx } from "./index.js";
12
+
13
+ export const getAdapter: (
14
+ ctx: GenericCtx<DataModel>
15
+ ) => Parameters<typeof runAdapterTest>[0]["getAdapter"] =
16
+ (ctx: GenericCtx<DataModel>) =>
17
+ async (opts?: Omit<BetterAuthOptions, "database">) => {
18
+ const authComponent = createClient<DataModel>(api as any, {
19
+ verbose: false,
20
+ });
21
+ const adapterFactory = authComponent.adapter(ctx);
22
+ return adapterFactory(opts ?? {});
23
+ };
24
+
25
+ describe("Better Auth Adapter Tests", async () => {
26
+ const status = {
27
+ active: "active",
28
+ only: "only",
29
+ notSupported: "not supported",
30
+ } as const;
31
+ const tests: Record<string, (typeof status)[keyof typeof status]> = {
32
+ CREATE_MODEL: status.active,
33
+ CREATE_MODEL_SHOULD_ALWAYS_RETURN_AN_ID: status.active,
34
+ FIND_MODEL: status.active,
35
+ FIND_MODEL_WITHOUT_ID: status.active,
36
+ FIND_MODEL_WITH_SELECT: status.active,
37
+ // Requires a custom schema - we fake success by overriding custom user
38
+ // schema in the test adapter because this test creates a user that other
39
+ // tests rely on.
40
+ FIND_MODEL_WITH_MODIFIED_FIELD_NAME: status.active,
41
+ UPDATE_MODEL: status.active,
42
+ SHOULD_FIND_MANY: status.active,
43
+ SHOULD_FIND_MANY_WITH_WHERE: status.active,
44
+ SHOULD_FIND_MANY_WITH_OPERATORS: status.active,
45
+ SHOULD_WORK_WITH_REFERENCE_FIELDS: status.active,
46
+ SHOULD_FIND_MANY_WITH_NOT_IN_OPERATOR: status.active,
47
+ SHOULD_FIND_MANY_WITH_SORT_BY: status.active,
48
+ SHOULD_FIND_MANY_WITH_LIMIT: status.active,
49
+ SHOULD_UPDATE_WITH_MULTIPLE_WHERE: status.active,
50
+ DELETE_MODEL: status.active,
51
+ SHOULD_DELETE_MANY: status.active,
52
+ SHOULD_NOT_THROW_ON_DELETE_RECORD_NOT_FOUND: status.active,
53
+ SHOULD_NOT_THROW_ON_RECORD_NOT_FOUND: status.active,
54
+ SHOULD_FIND_MANY_WITH_CONTAINS_OPERATOR: status.active,
55
+ SHOULD_SEARCH_USERS_WITH_STARTS_WITH: status.active,
56
+ SHOULD_SEARCH_USERS_WITH_ENDS_WITH: status.active,
57
+ // Use local install and Convex paginated queries
58
+ SHOULD_FIND_MANY_WITH_OFFSET: status.notSupported,
59
+ // Convex generates ids on insert
60
+ SHOULD_PREFER_GENERATE_ID_IF_PROVIDED: status.notSupported,
61
+ // Transactions are inherent for auth.api and not possible for authClient
62
+ SHOULD_ROLLBACK_FAILING_TRANSACTION: status.notSupported,
63
+ SHOULD_RETURN_TRANSACTION_RESULT: status.notSupported,
64
+ SHOULD_FIND_MANY_WITH_CONNECTORS: status.active,
65
+ };
66
+
67
+ const disableTests = Object.fromEntries(
68
+ Object.entries(tests).map((entry, idx, arr) => {
69
+ if (arr.some((e) => e[1] === status.only)) {
70
+ return [entry[0], !(entry[1] === status.only)];
71
+ }
72
+ return [entry[0], !(entry[1] === status.active)];
73
+ })
74
+ );
75
+
76
+ const t = convexTest(schema, import.meta.glob("../component/**/*.*s"));
77
+ await t.action(api.adapterTest.runTests, { disableTests });
78
+ });
79
+
80
+ describe("Convex Adapter Tests", async () => {
81
+ const t = convexTest(schema, import.meta.glob("../component/**/*.*s"));
82
+ await t.action(api.adapterTest.runCustomTests);
83
+ });
@@ -0,0 +1,363 @@
1
+ import { createAdapterFactory } from "better-auth/adapters";
2
+ import type { DBAdapterDebugLogOption } from "better-auth/adapters";
3
+ import { createFunctionHandle } from "convex/server";
4
+ import type {
5
+ FunctionHandle,
6
+ GenericActionCtx,
7
+ GenericDataModel,
8
+ PaginationOptions,
9
+ PaginationResult,
10
+ SchemaDefinition,
11
+ WithoutSystemFields,
12
+ } from "convex/server";
13
+ import type { SetOptional } from "type-fest";
14
+ import type defaultSchema from "../component/schema.js";
15
+ import type { Where } from "better-auth/types";
16
+ import { asyncMap } from "convex-helpers";
17
+ import { prop, sortBy, unique } from "remeda";
18
+ import { isRunMutationCtx } from "../utils/index.js";
19
+ import type { Doc, TableNames } from "../component/_generated/dataModel.js";
20
+ import type { ComponentApi } from "../component/_generated/component.js";
21
+ import type { AuthFunctions, GenericCtx, Triggers } from "./index.js";
22
+
23
+ const handlePagination = async (
24
+ next: ({
25
+ paginationOpts,
26
+ }: {
27
+ paginationOpts: PaginationOptions;
28
+ }) => Promise<
29
+ SetOptional<PaginationResult<any>, "page"> & { count?: number }
30
+ >,
31
+ { limit, numItems }: { limit?: number; numItems?: number } = {}
32
+ ) => {
33
+ const state: {
34
+ isDone: boolean;
35
+ cursor: string | null;
36
+ docs: any[];
37
+ count: number;
38
+ } = {
39
+ isDone: false,
40
+ cursor: null,
41
+ docs: [],
42
+ count: 0,
43
+ };
44
+ const onResult = (
45
+ result: SetOptional<PaginationResult<any>, "page"> & { count?: number }
46
+ ) => {
47
+ state.cursor =
48
+ result.pageStatus === "SplitRecommended" ||
49
+ result.pageStatus === "SplitRequired"
50
+ ? (result.splitCursor ?? result.continueCursor)
51
+ : result.continueCursor;
52
+ if (result.page) {
53
+ state.docs.push(...result.page);
54
+ state.isDone = (limit && state.docs.length >= limit) || result.isDone;
55
+ return;
56
+ }
57
+ // Update and delete only return a count
58
+ if (result.count) {
59
+ state.count += result.count;
60
+ state.isDone = (limit && state.count >= limit) || result.isDone;
61
+ return;
62
+ }
63
+ state.isDone = result.isDone;
64
+ };
65
+
66
+ do {
67
+ const result = await next({
68
+ paginationOpts: {
69
+ numItems: Math.min(
70
+ numItems ?? 200,
71
+ (limit ?? 200) - state.docs.length,
72
+ 200
73
+ ),
74
+ cursor: state.cursor,
75
+ },
76
+ });
77
+ onResult(result);
78
+ } while (!state.isDone);
79
+ return state;
80
+ };
81
+
82
+ type ConvexCleanedWhere<TableName extends TableNames = TableNames> = Where & {
83
+ value: string | number | boolean | string[] | number[] | null;
84
+ field: keyof WithoutSystemFields<Doc<TableName>> & string;
85
+ };
86
+
87
+ const parseWhere = (
88
+ where?: (Where & { join?: undefined }) | (Where & { join?: undefined })[]
89
+ ): ConvexCleanedWhere[] => {
90
+ if (!where) {
91
+ return [];
92
+ }
93
+ const whereArray = Array.isArray(where) ? where : [where];
94
+ return whereArray.map((w) => {
95
+ if (w.value instanceof Date) {
96
+ return {
97
+ ...w,
98
+ value: w.value.getTime(),
99
+ };
100
+ }
101
+ return w;
102
+ }) as ConvexCleanedWhere[];
103
+ };
104
+
105
+ export const convexAdapter = <
106
+ DataModel extends GenericDataModel,
107
+ Ctx extends GenericCtx<DataModel> = GenericActionCtx<DataModel>,
108
+ Schema extends SchemaDefinition<any, any> = typeof defaultSchema,
109
+ >(
110
+ ctx: Ctx,
111
+ api: {
112
+ adapter: ComponentApi["adapter"];
113
+ adapterTest?: ComponentApi["adapterTest"];
114
+ },
115
+ config: {
116
+ debugLogs?: DBAdapterDebugLogOption;
117
+ authFunctions?: AuthFunctions;
118
+ triggers?: Triggers<DataModel, Schema>;
119
+ } = {}
120
+ ) => {
121
+ return createAdapterFactory({
122
+ config: {
123
+ adapterId: "convex",
124
+ adapterName: "Convex Adapter",
125
+ debugLogs: config.debugLogs || false,
126
+ disableIdGeneration: true,
127
+ transaction: false,
128
+ supportsNumericIds: false,
129
+ supportsJSON: false,
130
+ supportsDates: false,
131
+ supportsArrays: true,
132
+ usePlural: false,
133
+ mapKeysTransformInput: {
134
+ id: "_id",
135
+ },
136
+ mapKeysTransformOutput: {
137
+ _id: "id",
138
+ },
139
+ // Convert dates to numbers. This aligns with how
140
+ // Convex stores _creationTime and avoids a breaking change.
141
+ customTransformInput: ({ data, fieldAttributes }) => {
142
+ if (data && fieldAttributes.type === "date") {
143
+ return new Date(data).getTime();
144
+ }
145
+ return data;
146
+ },
147
+ customTransformOutput: ({ data, fieldAttributes }) => {
148
+ if (data && fieldAttributes.type === "date") {
149
+ return new Date(data);
150
+ }
151
+ return data;
152
+ },
153
+ },
154
+ adapter: ({ options }) => {
155
+ // Disable telemetry in all cases because it requires Node
156
+ options.telemetry = { enabled: false };
157
+ return {
158
+ id: "convex",
159
+ options: {
160
+ isRunMutationCtx: isRunMutationCtx(ctx),
161
+ },
162
+ createSchema: async ({ file, tables }) => {
163
+ const { createSchema } = await import("./create-schema.js");
164
+ return createSchema({ file, tables });
165
+ },
166
+ create: async ({ model, data, select }): Promise<any> => {
167
+ if (!("runMutation" in ctx)) {
168
+ throw new Error("ctx is not a mutation ctx");
169
+ }
170
+ const onCreateHandle =
171
+ config.authFunctions?.onCreate && config.triggers?.[model]?.onCreate
172
+ ? ((await createFunctionHandle(
173
+ config.authFunctions.onCreate
174
+ )) as FunctionHandle<"mutation">)
175
+ : undefined;
176
+ return ctx.runMutation(api.adapter.create, {
177
+ input: { model: model as any, data },
178
+ select,
179
+ onCreateHandle: onCreateHandle,
180
+ });
181
+ },
182
+ findOne: async (data): Promise<any> => {
183
+ if (data.where?.every((w) => w.connector === "OR")) {
184
+ for (const w of data.where) {
185
+ const result = await ctx.runQuery(api.adapter.findOne, {
186
+ ...data,
187
+ model: data.model as TableNames,
188
+ where: parseWhere(w),
189
+ });
190
+ if (result) {
191
+ return result;
192
+ }
193
+ }
194
+ }
195
+ return await ctx.runQuery(api.adapter.findOne, {
196
+ ...data,
197
+ model: data.model as TableNames,
198
+ where: parseWhere(data.where),
199
+ });
200
+ },
201
+ findMany: async (data): Promise<any[]> => {
202
+ if (data.offset) {
203
+ throw new Error("offset not supported");
204
+ }
205
+
206
+ if (data.where?.some((w) => w.connector === "OR")) {
207
+ const results = await asyncMap(data.where, async (w) =>
208
+ handlePagination(
209
+ async ({ paginationOpts }) => {
210
+ return await ctx.runQuery(api.adapter.findMany, {
211
+ ...data,
212
+ model: data.model as TableNames,
213
+ where: parseWhere(w),
214
+ paginationOpts,
215
+ });
216
+ },
217
+ { limit: data.limit }
218
+ )
219
+ );
220
+ const docs = unique(results.flatMap((r) => r.docs));
221
+ if (data.sortBy) {
222
+ return sortBy(docs, [
223
+ prop(data.sortBy.field),
224
+ data.sortBy.direction,
225
+ ]);
226
+ }
227
+ return docs;
228
+ }
229
+
230
+ const result = await handlePagination(
231
+ async ({ paginationOpts }) => {
232
+ return await ctx.runQuery(api.adapter.findMany, {
233
+ ...data,
234
+ model: data.model as TableNames,
235
+ where: parseWhere(data.where),
236
+ paginationOpts,
237
+ });
238
+ },
239
+ { limit: data.limit }
240
+ );
241
+ return result.docs;
242
+ },
243
+ count: async (data) => {
244
+ // Yes, count is just findMany returning a number.
245
+ if (data.where?.some((w) => w.connector === "OR")) {
246
+ const results = await asyncMap(data.where, async (w) =>
247
+ handlePagination(async ({ paginationOpts }) => {
248
+ return await ctx.runQuery(api.adapter.findMany, {
249
+ ...data,
250
+ model: data.model as TableNames,
251
+ where: parseWhere(w),
252
+ paginationOpts,
253
+ });
254
+ })
255
+ );
256
+ const docs = unique(results.flatMap((r) => r.docs));
257
+ return docs.length;
258
+ }
259
+
260
+ const result = await handlePagination(async ({ paginationOpts }) => {
261
+ return await ctx.runQuery(api.adapter.findMany, {
262
+ ...data,
263
+ model: data.model as TableNames,
264
+ where: parseWhere(data.where),
265
+ paginationOpts,
266
+ });
267
+ });
268
+ return result.docs.length;
269
+ },
270
+ update: async (data): Promise<any> => {
271
+ if (!("runMutation" in ctx)) {
272
+ throw new Error("ctx is not a mutation ctx");
273
+ }
274
+ if (data.where?.length === 1 && data.where[0].operator === "eq") {
275
+ const onUpdateHandle =
276
+ config.authFunctions?.onUpdate &&
277
+ config.triggers?.[data.model]?.onUpdate
278
+ ? ((await createFunctionHandle(
279
+ config.authFunctions.onUpdate
280
+ )) as FunctionHandle<"mutation">)
281
+ : undefined;
282
+ return ctx.runMutation(api.adapter.updateOne, {
283
+ input: {
284
+ model: data.model as TableNames,
285
+ where: parseWhere(data.where),
286
+ update: data.update as any,
287
+ },
288
+ onUpdateHandle: onUpdateHandle,
289
+ });
290
+ }
291
+ throw new Error("where clause not supported");
292
+ },
293
+ delete: async (data) => {
294
+ if (!("runMutation" in ctx)) {
295
+ throw new Error("ctx is not a mutation ctx");
296
+ }
297
+ const onDeleteHandle =
298
+ config.authFunctions?.onDelete &&
299
+ config.triggers?.[data.model]?.onDelete
300
+ ? ((await createFunctionHandle(
301
+ config.authFunctions.onDelete
302
+ )) as FunctionHandle<"mutation">)
303
+ : undefined;
304
+ await ctx.runMutation(api.adapter.deleteOne, {
305
+ input: {
306
+ model: data.model as TableNames,
307
+ where: parseWhere(data.where),
308
+ },
309
+ onDeleteHandle: onDeleteHandle,
310
+ });
311
+ },
312
+ deleteMany: async (data) => {
313
+ if (!("runMutation" in ctx)) {
314
+ throw new Error("ctx is not a mutation ctx");
315
+ }
316
+ const onDeleteHandle =
317
+ config.authFunctions?.onDelete &&
318
+ config.triggers?.[data.model as TableNames]?.onDelete
319
+ ? ((await createFunctionHandle(
320
+ config.authFunctions.onDelete
321
+ )) as FunctionHandle<"mutation">)
322
+ : undefined;
323
+ const result = await handlePagination(async ({ paginationOpts }) => {
324
+ return await ctx.runMutation(api.adapter.deleteMany, {
325
+ input: {
326
+ ...data,
327
+ model: data.model as TableNames,
328
+ where: parseWhere(data.where),
329
+ },
330
+ paginationOpts,
331
+ onDeleteHandle: onDeleteHandle,
332
+ });
333
+ });
334
+ return result.count;
335
+ },
336
+ updateMany: async (data) => {
337
+ if (!("runMutation" in ctx)) {
338
+ throw new Error("ctx is not a mutation ctx");
339
+ }
340
+ const onUpdateHandle =
341
+ config.authFunctions?.onUpdate &&
342
+ config.triggers?.[data.model]?.onUpdate
343
+ ? ((await createFunctionHandle(
344
+ config.authFunctions.onUpdate
345
+ )) as FunctionHandle<"mutation">)
346
+ : undefined;
347
+ const result = await handlePagination(async ({ paginationOpts }) => {
348
+ return await ctx.runMutation(api.adapter.updateMany, {
349
+ input: {
350
+ ...data,
351
+ model: data.model as TableNames,
352
+ where: parseWhere(data.where),
353
+ },
354
+ paginationOpts,
355
+ onUpdateHandle: onUpdateHandle,
356
+ });
357
+ });
358
+ return result.count;
359
+ },
360
+ };
361
+ },
362
+ });
363
+ };