@onmax/nuxt-better-auth 0.0.2-alpha.15 → 0.0.2-alpha.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onmax/nuxt-better-auth",
3
- "version": "0.0.2-alpha.15",
3
+ "version": "0.0.2-alpha.17",
4
4
  "configKey": "auth",
5
5
  "compatibility": {
6
6
  "nuxt": ">=3.0.0"
package/dist/module.mjs CHANGED
@@ -8,9 +8,10 @@ import { join, dirname } from 'pathe';
8
8
  import { toRouteMatcher, createRouter } from 'radix3';
9
9
  import { isCI, isTest } from 'std-env';
10
10
  import { generateDrizzleSchema as generateDrizzleSchema$1 } from '@better-auth/cli/api';
11
+ import { getAuthTables } from 'better-auth/db';
11
12
  export { defineClientAuth, defineServerAuth } from '../dist/runtime/config.js';
12
13
 
13
- const version = "0.0.2-alpha.15";
14
+ const version = "0.0.2-alpha.17";
14
15
 
15
16
  function setupDevTools(nuxt) {
16
17
  nuxt.hook("devtools:customTabs", (tabs) => {
@@ -56,6 +57,101 @@ async function generateDrizzleSchema(authOptions, dialect, schemaOptions) {
56
57
  }
57
58
  return result.code;
58
59
  }
60
+ const convexIndexFields = {
61
+ account: ["accountId", ["accountId", "providerId"], ["providerId", "userId"]],
62
+ rateLimit: ["key"],
63
+ session: ["expiresAt", ["expiresAt", "userId"]],
64
+ verification: ["expiresAt", "identifier"],
65
+ user: [["email", "name"], "name", "userId"],
66
+ passkey: ["credentialID"],
67
+ oauthConsent: [["clientId", "userId"]]
68
+ };
69
+ function getConvexSpecialFields(tables) {
70
+ return Object.fromEntries(
71
+ Object.entries(tables).map(([key, table]) => {
72
+ const fields = Object.fromEntries(
73
+ Object.entries(table.fields).map(([fieldKey, field]) => [
74
+ field.fieldName ?? fieldKey,
75
+ {
76
+ ...field.sortable ? { sortable: true } : {},
77
+ ...field.unique ? { unique: true } : {},
78
+ ...field.references ? { references: field.references } : {}
79
+ }
80
+ ]).filter(([_key, value]) => typeof value === "object" ? Object.keys(value).length > 0 : true)
81
+ );
82
+ return [key, fields];
83
+ }).filter(([_key, value]) => typeof value === "object" ? Object.keys(value).length > 0 : true)
84
+ );
85
+ }
86
+ function getMergedConvexIndexFields(tables) {
87
+ return Object.fromEntries(
88
+ Object.entries(tables).map(([key, table]) => {
89
+ const manualIndexes = convexIndexFields[key]?.map((index) => {
90
+ return typeof index === "string" ? table.fields[index]?.fieldName ?? index : index.map((i) => table.fields[i]?.fieldName ?? i);
91
+ }) || [];
92
+ const specialFieldsObj = getConvexSpecialFields(tables);
93
+ const specialFieldIndexes = Object.keys(specialFieldsObj[key] || {}).filter(
94
+ (index) => !manualIndexes.some((m) => Array.isArray(m) ? m[0] === index : m === index)
95
+ );
96
+ return [key, manualIndexes.concat(specialFieldIndexes)];
97
+ })
98
+ );
99
+ }
100
+ async function generateConvexSchema(authOptions) {
101
+ const tables = getAuthTables(authOptions);
102
+ let code = `/**
103
+ * Auto-generated Better Auth tables for Convex.
104
+ * Import these tables in your convex/schema.ts:
105
+ *
106
+ * import { defineSchema } from 'convex/server'
107
+ * import { authTables } from './_generated/auth-tables'
108
+ *
109
+ * export default defineSchema({ ...authTables, ...yourTables })
110
+ */
111
+
112
+ import { defineTable } from 'convex/server'
113
+ import { v } from 'convex/values'
114
+
115
+ export const authTables = {
116
+ `;
117
+ const getType = (_name, field) => {
118
+ const type = field.type;
119
+ const typeMap = {
120
+ "string": "v.string()",
121
+ "boolean": "v.boolean()",
122
+ "number": "v.number()",
123
+ "date": "v.number()",
124
+ "json": "v.string()",
125
+ "number[]": "v.array(v.number())",
126
+ "string[]": "v.array(v.string())"
127
+ };
128
+ return typeMap[type];
129
+ };
130
+ for (const tableKey in tables) {
131
+ const table = tables[tableKey];
132
+ const modelName = table.modelName;
133
+ const fields = Object.fromEntries(Object.entries(table.fields).filter(([key]) => key !== "id"));
134
+ const indexes = getMergedConvexIndexFields(tables)[tableKey]?.map((index) => {
135
+ const indexArray = Array.isArray(index) ? index.sort() : [index];
136
+ const indexName = indexArray.join("_");
137
+ return `.index('${indexName}', ${JSON.stringify(indexArray)})`;
138
+ }) || [];
139
+ const schema = `${modelName}: defineTable({
140
+ ${Object.keys(fields).map((field) => {
141
+ const attr = fields[field];
142
+ const type = getType(field, attr);
143
+ const optional = (fieldSchema) => attr.required ? fieldSchema : `v.optional(v.union(v.null(), ${fieldSchema}))`;
144
+ return ` ${attr.fieldName ?? field}: ${optional(type)},`;
145
+ }).join("\n")}
146
+ })${indexes.length > 0 ? `
147
+ ${indexes.join("\n ")}` : ""},
148
+ `;
149
+ code += ` ${schema}`;
150
+ }
151
+ code += `}
152
+ `;
153
+ return code;
154
+ }
59
155
  async function loadUserAuthConfig(configPath, throwOnError = false) {
60
156
  const { createJiti } = await import('jiti');
61
157
  const { defineServerAuth } = await import('../dist/runtime/config.js');
@@ -105,6 +201,19 @@ function getHubCasing(hub) {
105
201
  return hub.db.casing;
106
202
  }
107
203
  const consola = consola$1.withTag("nuxt-better-auth");
204
+ function resolveConvexUrl(nuxt) {
205
+ const convexConfig = nuxt.options.convex;
206
+ if (convexConfig?.url)
207
+ return convexConfig.url;
208
+ const runtimeUrl = nuxt.options.runtimeConfig.public?.convex?.url;
209
+ if (runtimeUrl)
210
+ return runtimeUrl;
211
+ if (process.env.CONVEX_URL)
212
+ return process.env.CONVEX_URL;
213
+ if (process.env.NUXT_PUBLIC_CONVEX_URL)
214
+ return process.env.NUXT_PUBLIC_CONVEX_URL;
215
+ return "";
216
+ }
108
217
  const generateSecret = () => randomBytes(32).toString("hex");
109
218
  function readEnvFile(rootDir) {
110
219
  const envPath = join(rootDir, ".env");
@@ -226,6 +335,12 @@ export default defineClientAuth({})
226
335
  const hasNuxtHub = hasNuxtModule("@nuxthub/core", nuxt);
227
336
  const hub = hasNuxtHub ? nuxt.options.hub : void 0;
228
337
  const hasHubDb = !clientOnly && hasNuxtHub && !!hub?.db;
338
+ const hasConvex = hasNuxtModule("nuxt-convex", nuxt);
339
+ const convexUrl = resolveConvexUrl(nuxt);
340
+ const hasConvexDb = !clientOnly && hasConvex && !!convexUrl && !hasHubDb;
341
+ if (hasConvexDb) {
342
+ consola.info("Detected Convex - using Convex HTTP adapter for Better Auth database");
343
+ }
229
344
  let secondaryStorageEnabled = options.secondaryStorage ?? false;
230
345
  if (secondaryStorageEnabled && clientOnly) {
231
346
  consola.warn("secondaryStorage is not available in clientOnly mode. Disabling.");
@@ -237,7 +352,7 @@ export default defineClientAuth({})
237
352
  nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
238
353
  nuxt.options.runtimeConfig.public.auth = defu(nuxt.options.runtimeConfig.public.auth, {
239
354
  redirects: { login: options.redirects?.login ?? "/login", guest: options.redirects?.guest ?? "/" },
240
- useDatabase: hasHubDb,
355
+ useDatabase: hasHubDb || hasConvexDb,
241
356
  clientOnly
242
357
  });
243
358
  if (clientOnly) {
@@ -269,7 +384,7 @@ export default defineClientAuth({})
269
384
  if (secondaryStorageEnabled && !nuxt.options.alias["hub:kv"]) {
270
385
  throw new Error("[nuxt-better-auth] hub:kv not found. Ensure @nuxthub/core is loaded before this module and hub.kv is enabled.");
271
386
  }
272
- const secondaryStorageCode = secondaryStorageEnabled ? `import { kv } from '../hub/kv.mjs'
387
+ const secondaryStorageCode = secondaryStorageEnabled ? `import { kv } from 'hub:kv'
273
388
  export function createSecondaryStorage() {
274
389
  return {
275
390
  get: async (key) => kv.get(\`_auth:\${key}\`),
@@ -285,13 +400,34 @@ export function createSecondaryStorage() {
285
400
  const hubDialect = getHubDialect(hub) ?? "sqlite";
286
401
  const usePlural = options.schema?.usePlural ?? false;
287
402
  const camelCase = (options.schema?.casing ?? getHubCasing(hub)) !== "snake_case";
288
- const databaseCode = hasHubDb ? `import { db, schema } from '../hub/db.mjs'
403
+ let databaseCode;
404
+ if (hasHubDb) {
405
+ databaseCode = `import { db, schema } from 'hub:db'
289
406
  import { drizzleAdapter } from 'better-auth/adapters/drizzle'
290
407
  const rawDialect = '${hubDialect}'
291
408
  const dialect = rawDialect === 'postgresql' ? 'pg' : rawDialect
292
409
  export function createDatabase() { return drizzleAdapter(db, { provider: dialect, schema, usePlural: ${usePlural}, camelCase: ${camelCase} }) }
293
- export { db }` : `export function createDatabase() { return undefined }
410
+ export { db }`;
411
+ } else if (hasConvexDb) {
412
+ nuxt.options.runtimeConfig.betterAuth = defu(
413
+ nuxt.options.runtimeConfig.betterAuth || {},
414
+ { convexUrl }
415
+ );
416
+ databaseCode = `import { useRuntimeConfig } from '#imports'
417
+ import { createConvexHttpAdapter } from '@onmax/nuxt-better-auth/adapters/convex'
418
+ import { api } from '#convex/api'
419
+
420
+ export function createDatabase() {
421
+ const config = useRuntimeConfig()
422
+ const convexUrl = config.betterAuth?.convexUrl || config.public?.convex?.url
423
+ if (!convexUrl) throw new Error('[nuxt-better-auth] CONVEX_URL not configured')
424
+ return createConvexHttpAdapter({ url: convexUrl, api: api.auth })
425
+ }
294
426
  export const db = undefined`;
427
+ } else {
428
+ databaseCode = `export function createDatabase() { return undefined }
429
+ export const db = undefined`;
430
+ }
295
431
  const databaseTemplate = addTemplate({ filename: "better-auth/database.mjs", getContents: () => databaseCode, write: true });
296
432
  nuxt.options.alias["#auth/database"] = databaseTemplate.dst;
297
433
  addTypeTemplate({
@@ -411,6 +547,9 @@ declare module '#nuxt-better-auth' {
411
547
  if (hasHubDb) {
412
548
  await setupBetterAuthSchema(nuxt, serverConfigPath, options);
413
549
  }
550
+ if (hasConvexDb) {
551
+ await setupConvexAuthSchema(nuxt, serverConfigPath);
552
+ }
414
553
  const isProduction = process.env.NODE_ENV === "production" || !nuxt.options.dev;
415
554
  if (!isProduction && !clientOnly) {
416
555
  if (!hasNuxtModule("@nuxt/ui"))
@@ -491,5 +630,26 @@ async function setupBetterAuthSchema(nuxt, serverConfigPath, options) {
491
630
  }
492
631
  });
493
632
  }
633
+ async function setupConvexAuthSchema(nuxt, serverConfigPath) {
634
+ const isProduction = !nuxt.options.dev;
635
+ try {
636
+ const configFile = `${serverConfigPath}.ts`;
637
+ const userConfig = await loadUserAuthConfig(configFile, isProduction);
638
+ const authOptions = { ...userConfig };
639
+ const schemaCode = await generateConvexSchema(authOptions);
640
+ const schemaDir = join(nuxt.options.buildDir, "better-auth");
641
+ const schemaPath = join(schemaDir, "auth-tables.convex.ts");
642
+ await mkdir(schemaDir, { recursive: true });
643
+ await writeFile(schemaPath, schemaCode);
644
+ addTemplate({ filename: "better-auth/auth-tables.convex.ts", getContents: () => schemaCode, write: true });
645
+ nuxt.options.alias["#auth/convex-schema"] = schemaPath;
646
+ consola.info("Generated Convex auth schema at .nuxt/better-auth/auth-tables.convex.ts");
647
+ } catch (error) {
648
+ if (isProduction) {
649
+ throw error;
650
+ }
651
+ consola.error("Failed to generate Convex schema:", error);
652
+ }
653
+ }
494
654
 
495
655
  export { module$1 as default };
@@ -0,0 +1,111 @@
1
+ import type { FunctionReference } from 'convex/server';
2
+ interface ConvexCleanedWhere {
3
+ field: string;
4
+ value: string | number | boolean | string[] | number[] | null;
5
+ operator?: 'lt' | 'lte' | 'gt' | 'gte' | 'eq' | 'in' | 'not_in' | 'ne' | 'contains' | 'starts_with' | 'ends_with';
6
+ connector?: 'AND' | 'OR';
7
+ }
8
+ interface PaginationResult<T> {
9
+ page: T[];
10
+ isDone: boolean;
11
+ continueCursor: string | null;
12
+ splitCursor?: string;
13
+ pageStatus?: 'SplitRecommended' | 'SplitRequired' | string;
14
+ count?: number;
15
+ }
16
+ interface ConvexAuthApi {
17
+ create: FunctionReference<'mutation', 'public', {
18
+ input: {
19
+ model: string;
20
+ data: Record<string, unknown>;
21
+ };
22
+ select?: string[];
23
+ }, unknown>;
24
+ findOne: FunctionReference<'query', 'public', {
25
+ model: string;
26
+ where?: ConvexCleanedWhere[];
27
+ select?: string[];
28
+ }, unknown>;
29
+ findMany: FunctionReference<'query', 'public', {
30
+ model: string;
31
+ where?: ConvexCleanedWhere[];
32
+ limit?: number;
33
+ sortBy?: {
34
+ direction: 'asc' | 'desc';
35
+ field: string;
36
+ };
37
+ paginationOpts: {
38
+ numItems: number;
39
+ cursor: string | null;
40
+ };
41
+ }, PaginationResult<unknown>>;
42
+ updateOne: FunctionReference<'mutation', 'public', {
43
+ input: {
44
+ model: string;
45
+ where?: ConvexCleanedWhere[];
46
+ update: Record<string, unknown>;
47
+ };
48
+ }, unknown>;
49
+ updateMany: FunctionReference<'mutation', 'public', {
50
+ input: {
51
+ model: string;
52
+ where?: ConvexCleanedWhere[];
53
+ update: Record<string, unknown>;
54
+ };
55
+ paginationOpts: {
56
+ numItems: number;
57
+ cursor: string | null;
58
+ };
59
+ }, PaginationResult<unknown> & {
60
+ count: number;
61
+ }>;
62
+ deleteOne: FunctionReference<'mutation', 'public', {
63
+ input: {
64
+ model: string;
65
+ where?: ConvexCleanedWhere[];
66
+ };
67
+ }, unknown>;
68
+ deleteMany: FunctionReference<'mutation', 'public', {
69
+ input: {
70
+ model: string;
71
+ where?: ConvexCleanedWhere[];
72
+ };
73
+ paginationOpts: {
74
+ numItems: number;
75
+ cursor: string | null;
76
+ };
77
+ }, PaginationResult<unknown> & {
78
+ count: number;
79
+ }>;
80
+ }
81
+ export interface ConvexHttpAdapterOptions {
82
+ /** Convex deployment URL (e.g., https://your-app.convex.cloud) */
83
+ url: string;
84
+ /** Convex API functions for auth operations - import from your convex/_generated/api */
85
+ api: ConvexAuthApi;
86
+ /** Enable debug logging for adapter operations */
87
+ debugLogs?: boolean;
88
+ }
89
+ /**
90
+ * Creates a Better Auth adapter that communicates with Convex via HTTP.
91
+ * Uses ConvexHttpClient for server-side auth operations.
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * import { api } from '~/convex/_generated/api'
96
+ *
97
+ * export default defineServerAuth(() => ({
98
+ * database: createConvexHttpAdapter({
99
+ * url: process.env.CONVEX_URL!,
100
+ * api: api.auth,
101
+ * }),
102
+ * }))
103
+ * ```
104
+ *
105
+ * @limitations
106
+ * - `update()` only supports AND-connected where clauses (no OR support)
107
+ * - `count()` fetches all documents client-side (Convex limitation)
108
+ * - `offset` pagination not supported in `findMany()`
109
+ */
110
+ export declare function createConvexHttpAdapter(options: ConvexHttpAdapterOptions): import("better-auth/adapters").AdapterFactory;
111
+ export {};
@@ -0,0 +1,213 @@
1
+ import { createAdapterFactory } from "better-auth/adapters";
2
+ import { ConvexHttpClient } from "convex/browser";
3
+ function parseWhere(where) {
4
+ if (!where)
5
+ return [];
6
+ const whereArray = Array.isArray(where) ? where : [where];
7
+ return whereArray.map((w) => {
8
+ if (w.value instanceof Date)
9
+ return { ...w, value: w.value.getTime() };
10
+ return w;
11
+ });
12
+ }
13
+ async function handlePagination(next, { limit } = {}) {
14
+ const state = { isDone: false, cursor: null, docs: [], count: 0 };
15
+ const onResult = (result) => {
16
+ state.cursor = result.pageStatus === "SplitRecommended" || result.pageStatus === "SplitRequired" ? result.splitCursor ?? result.continueCursor : result.continueCursor;
17
+ if (result.page) {
18
+ state.docs.push(...result.page);
19
+ state.isDone = limit && state.docs.length >= limit || result.isDone;
20
+ return;
21
+ }
22
+ if (result.count) {
23
+ state.count += result.count;
24
+ state.isDone = limit && state.count >= limit || result.isDone;
25
+ return;
26
+ }
27
+ state.isDone = result.isDone;
28
+ };
29
+ do {
30
+ const result = await next({
31
+ paginationOpts: {
32
+ numItems: Math.min(200, (limit ?? 200) - state.docs.length, 200),
33
+ cursor: state.cursor
34
+ }
35
+ });
36
+ onResult(result);
37
+ } while (!state.isDone);
38
+ return state;
39
+ }
40
+ export function createConvexHttpAdapter(options) {
41
+ if (!options.url.startsWith("https://") || !options.url.includes(".convex.")) {
42
+ throw new Error(`Invalid Convex URL: ${options.url}. Expected format: https://your-app.convex.cloud`);
43
+ }
44
+ const client = new ConvexHttpClient(options.url);
45
+ return createAdapterFactory({
46
+ config: {
47
+ adapterId: "convex-http",
48
+ adapterName: "Convex HTTP Adapter",
49
+ debugLogs: options.debugLogs ?? false,
50
+ disableIdGeneration: true,
51
+ transaction: false,
52
+ supportsNumericIds: false,
53
+ supportsJSON: false,
54
+ supportsDates: false,
55
+ supportsArrays: true,
56
+ usePlural: false,
57
+ mapKeysTransformInput: { id: "_id" },
58
+ mapKeysTransformOutput: { _id: "id" },
59
+ customTransformInput: ({ data, fieldAttributes }) => {
60
+ if (data && fieldAttributes.type === "date")
61
+ return new Date(data).getTime();
62
+ return data;
63
+ },
64
+ customTransformOutput: ({ data, fieldAttributes }) => {
65
+ if (data && fieldAttributes.type === "date")
66
+ return new Date(data).getTime();
67
+ return data;
68
+ }
69
+ },
70
+ adapter: ({ options: authOptions }) => {
71
+ authOptions.telemetry = { enabled: false };
72
+ return {
73
+ id: "convex-http",
74
+ create: async ({ model, data, select }) => {
75
+ return client.mutation(options.api.create, {
76
+ input: { model, data },
77
+ select
78
+ });
79
+ },
80
+ findOne: async (data) => {
81
+ if (data.where?.every((w) => w.connector === "OR")) {
82
+ for (const w of data.where) {
83
+ const result = await client.query(options.api.findOne, {
84
+ ...data,
85
+ model: data.model,
86
+ where: parseWhere(w)
87
+ });
88
+ if (result)
89
+ return result;
90
+ }
91
+ return null;
92
+ }
93
+ return client.query(options.api.findOne, {
94
+ ...data,
95
+ model: data.model,
96
+ where: parseWhere(data.where)
97
+ });
98
+ },
99
+ findMany: async (data) => {
100
+ if (data.offset)
101
+ throw new Error("offset not supported");
102
+ if (data.where?.some((w) => w.connector === "OR")) {
103
+ const results = await Promise.all(
104
+ data.where.map(
105
+ async (w) => handlePagination(async ({ paginationOpts }) => {
106
+ return client.query(options.api.findMany, {
107
+ ...data,
108
+ model: data.model,
109
+ where: parseWhere(w),
110
+ paginationOpts
111
+ });
112
+ }, { limit: data.limit })
113
+ )
114
+ );
115
+ const allDocs = results.flatMap((r) => r.docs);
116
+ const uniqueDocs = [...new Map(allDocs.map((d) => [d._id, d])).values()];
117
+ if (data.sortBy) {
118
+ return uniqueDocs.sort((a, b) => {
119
+ const aVal = a[data.sortBy.field];
120
+ const bVal = b[data.sortBy.field];
121
+ const cmp = aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
122
+ return data.sortBy.direction === "asc" ? cmp : -cmp;
123
+ });
124
+ }
125
+ return uniqueDocs;
126
+ }
127
+ const result = await handlePagination(
128
+ async ({ paginationOpts }) => client.query(options.api.findMany, {
129
+ ...data,
130
+ model: data.model,
131
+ where: parseWhere(data.where),
132
+ paginationOpts
133
+ }),
134
+ { limit: data.limit }
135
+ );
136
+ return result.docs;
137
+ },
138
+ // Note: Convex doesn't have a native count query, so we fetch all docs and count client-side.
139
+ // This is inefficient for large datasets but acceptable for auth tables (typically small).
140
+ count: async (data) => {
141
+ if (data.where?.some((w) => w.connector === "OR")) {
142
+ const results = await Promise.all(
143
+ data.where.map(
144
+ async (w) => handlePagination(async ({ paginationOpts }) => {
145
+ return client.query(options.api.findMany, {
146
+ ...data,
147
+ model: data.model,
148
+ where: parseWhere(w),
149
+ paginationOpts
150
+ });
151
+ })
152
+ )
153
+ );
154
+ const allDocs = results.flatMap((r) => r.docs);
155
+ const uniqueDocs = [...new Map(allDocs.map((d) => [d._id, d])).values()];
156
+ return uniqueDocs.length;
157
+ }
158
+ const result = await handlePagination(async ({ paginationOpts }) => client.query(options.api.findMany, {
159
+ ...data,
160
+ model: data.model,
161
+ where: parseWhere(data.where),
162
+ paginationOpts
163
+ }));
164
+ return result.docs.length;
165
+ },
166
+ // Supports single eq or multiple AND-connected conditions (Better Auth's common patterns)
167
+ update: async (data) => {
168
+ const hasOrConnector = data.where?.some((w) => w.connector === "OR");
169
+ if (hasOrConnector) {
170
+ throw new Error("update() does not support OR conditions - use updateMany() or split into multiple calls");
171
+ }
172
+ return client.mutation(options.api.updateOne, {
173
+ input: {
174
+ model: data.model,
175
+ where: parseWhere(data.where),
176
+ update: data.update
177
+ }
178
+ });
179
+ },
180
+ updateMany: async (data) => {
181
+ const result = await handlePagination(async ({ paginationOpts }) => client.mutation(options.api.updateMany, {
182
+ input: {
183
+ ...data,
184
+ model: data.model,
185
+ where: parseWhere(data.where)
186
+ },
187
+ paginationOpts
188
+ }));
189
+ return result.count;
190
+ },
191
+ delete: async (data) => {
192
+ await client.mutation(options.api.deleteOne, {
193
+ input: {
194
+ model: data.model,
195
+ where: parseWhere(data.where)
196
+ }
197
+ });
198
+ },
199
+ deleteMany: async (data) => {
200
+ const result = await handlePagination(async ({ paginationOpts }) => client.mutation(options.api.deleteMany, {
201
+ input: {
202
+ ...data,
203
+ model: data.model,
204
+ where: parseWhere(data.where)
205
+ },
206
+ paginationOpts
207
+ }));
208
+ return result.count;
209
+ }
210
+ };
211
+ }
212
+ });
213
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@onmax/nuxt-better-auth",
3
3
  "type": "module",
4
- "version": "0.0.2-alpha.15",
4
+ "version": "0.0.2-alpha.17",
5
5
  "packageManager": "pnpm@10.15.1",
6
6
  "description": "Nuxt module for Better Auth integration with NuxtHub, route protection, session management, and role-based access",
7
7
  "author": "onmax",
@@ -26,6 +26,10 @@
26
26
  "./config": {
27
27
  "types": "./dist/runtime/config.d.ts",
28
28
  "import": "./dist/runtime/config.js"
29
+ },
30
+ "./adapters/convex": {
31
+ "types": "./dist/runtime/adapters/convex.d.ts",
32
+ "import": "./dist/runtime/adapters/convex.js"
29
33
  }
30
34
  },
31
35
  "main": "./dist/module.mjs",
@@ -36,6 +40,9 @@
36
40
  ],
37
41
  "config": [
38
42
  "./dist/runtime/config.d.ts"
43
+ ],
44
+ "adapters/convex": [
45
+ "./dist/runtime/adapters/convex.d.ts"
39
46
  ]
40
47
  }
41
48
  },
@@ -60,11 +67,15 @@
60
67
  },
61
68
  "peerDependencies": {
62
69
  "@nuxthub/core": ">=0.10.0",
63
- "better-auth": ">=1.0.0"
70
+ "better-auth": ">=1.0.0",
71
+ "convex": ">=1.25.0"
64
72
  },
65
73
  "peerDependenciesMeta": {
66
74
  "@nuxthub/core": {
67
75
  "optional": true
76
+ },
77
+ "convex": {
78
+ "optional": true
68
79
  }
69
80
  },
70
81
  "dependencies": {
@@ -85,7 +96,7 @@
85
96
  "@nuxt/module-builder": "^1.0.2",
86
97
  "@nuxt/schema": "^4.2.2",
87
98
  "@nuxt/test-utils": "^3.21.0",
88
- "@nuxthub/core": "^0.10.3",
99
+ "@nuxthub/core": "^0.10.5",
89
100
  "@types/better-sqlite3": "^7.6.13",
90
101
  "@types/node": "latest",
91
102
  "better-auth": "^1.5.0-beta.3",