@convex-dev/better-auth 0.8.9 → 0.9.1

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 (103) hide show
  1. package/dist/commonjs/client/adapter.d.ts +8 -4
  2. package/dist/commonjs/client/adapter.d.ts.map +1 -1
  3. package/dist/commonjs/client/adapter.js +45 -8
  4. package/dist/commonjs/client/adapter.js.map +1 -1
  5. package/dist/commonjs/client/adapterUtils.d.ts +6 -6
  6. package/dist/commonjs/client/adapterUtils.d.ts.map +1 -1
  7. package/dist/commonjs/client/adapterUtils.js +17 -9
  8. package/dist/commonjs/client/adapterUtils.js.map +1 -1
  9. package/dist/commonjs/client/createSchema.d.ts +0 -5
  10. package/dist/commonjs/client/createSchema.d.ts.map +1 -1
  11. package/dist/commonjs/client/createSchema.js +0 -8
  12. package/dist/commonjs/client/createSchema.js.map +1 -1
  13. package/dist/commonjs/client/index.d.ts +64 -3355
  14. package/dist/commonjs/client/index.d.ts.map +1 -1
  15. package/dist/commonjs/client/index.js +100 -33
  16. package/dist/commonjs/client/index.js.map +1 -1
  17. package/dist/commonjs/component/adapter.d.ts +11 -9
  18. package/dist/commonjs/component/adapter.d.ts.map +1 -1
  19. package/dist/commonjs/component/adapter.js +1 -1
  20. package/dist/commonjs/component/adapter.js.map +1 -1
  21. package/dist/commonjs/component/adapterTest.d.ts +1 -1
  22. package/dist/commonjs/component/adapterTest.d.ts.map +1 -1
  23. package/dist/commonjs/component/schema.d.ts +16 -419
  24. package/dist/commonjs/component/schema.d.ts.map +1 -1
  25. package/dist/commonjs/component/schema.js +6 -196
  26. package/dist/commonjs/component/schema.js.map +1 -1
  27. package/dist/commonjs/plugins/convex/index.d.ts +10 -2
  28. package/dist/commonjs/plugins/convex/index.d.ts.map +1 -1
  29. package/dist/commonjs/plugins/convex/index.js +32 -5
  30. package/dist/commonjs/plugins/convex/index.js.map +1 -1
  31. package/dist/commonjs/plugins/convex/test.d.ts +4 -0
  32. package/dist/commonjs/plugins/convex/test.d.ts.map +1 -0
  33. package/dist/commonjs/plugins/convex/test.js +47 -0
  34. package/dist/commonjs/plugins/convex/test.js.map +1 -0
  35. package/dist/commonjs/plugins/cross-domain/index.d.ts +5 -0
  36. package/dist/commonjs/plugins/cross-domain/index.d.ts.map +1 -1
  37. package/dist/commonjs/plugins/cross-domain/index.js +8 -0
  38. package/dist/commonjs/plugins/cross-domain/index.js.map +1 -1
  39. package/dist/commonjs/react-start/index.d.ts.map +1 -1
  40. package/dist/commonjs/react-start/index.js +10 -2
  41. package/dist/commonjs/react-start/index.js.map +1 -1
  42. package/dist/commonjs/utils/index.d.ts +5 -5
  43. package/dist/commonjs/utils/index.d.ts.map +1 -1
  44. package/dist/commonjs/utils/index.js +9 -11
  45. package/dist/commonjs/utils/index.js.map +1 -1
  46. package/dist/esm/client/adapter.d.ts +8 -4
  47. package/dist/esm/client/adapter.d.ts.map +1 -1
  48. package/dist/esm/client/adapter.js +45 -8
  49. package/dist/esm/client/adapter.js.map +1 -1
  50. package/dist/esm/client/adapterUtils.d.ts +6 -6
  51. package/dist/esm/client/adapterUtils.d.ts.map +1 -1
  52. package/dist/esm/client/adapterUtils.js +17 -9
  53. package/dist/esm/client/adapterUtils.js.map +1 -1
  54. package/dist/esm/client/createSchema.d.ts +0 -5
  55. package/dist/esm/client/createSchema.d.ts.map +1 -1
  56. package/dist/esm/client/createSchema.js +0 -8
  57. package/dist/esm/client/createSchema.js.map +1 -1
  58. package/dist/esm/client/index.d.ts +64 -3355
  59. package/dist/esm/client/index.d.ts.map +1 -1
  60. package/dist/esm/client/index.js +100 -33
  61. package/dist/esm/client/index.js.map +1 -1
  62. package/dist/esm/component/adapter.d.ts +11 -9
  63. package/dist/esm/component/adapter.d.ts.map +1 -1
  64. package/dist/esm/component/adapter.js +1 -1
  65. package/dist/esm/component/adapter.js.map +1 -1
  66. package/dist/esm/component/adapterTest.d.ts +1 -1
  67. package/dist/esm/component/adapterTest.d.ts.map +1 -1
  68. package/dist/esm/component/schema.d.ts +16 -419
  69. package/dist/esm/component/schema.d.ts.map +1 -1
  70. package/dist/esm/component/schema.js +6 -196
  71. package/dist/esm/component/schema.js.map +1 -1
  72. package/dist/esm/plugins/convex/index.d.ts +10 -2
  73. package/dist/esm/plugins/convex/index.d.ts.map +1 -1
  74. package/dist/esm/plugins/convex/index.js +32 -5
  75. package/dist/esm/plugins/convex/index.js.map +1 -1
  76. package/dist/esm/plugins/convex/test.d.ts +4 -0
  77. package/dist/esm/plugins/convex/test.d.ts.map +1 -0
  78. package/dist/esm/plugins/convex/test.js +47 -0
  79. package/dist/esm/plugins/convex/test.js.map +1 -0
  80. package/dist/esm/plugins/cross-domain/index.d.ts +5 -0
  81. package/dist/esm/plugins/cross-domain/index.d.ts.map +1 -1
  82. package/dist/esm/plugins/cross-domain/index.js +8 -0
  83. package/dist/esm/plugins/cross-domain/index.js.map +1 -1
  84. package/dist/esm/react-start/index.d.ts.map +1 -1
  85. package/dist/esm/react-start/index.js +10 -2
  86. package/dist/esm/react-start/index.js.map +1 -1
  87. package/dist/esm/utils/index.d.ts +5 -5
  88. package/dist/esm/utils/index.d.ts.map +1 -1
  89. package/dist/esm/utils/index.js +9 -11
  90. package/dist/esm/utils/index.js.map +1 -1
  91. package/package.json +13 -8
  92. package/src/client/adapter.test.ts +94 -34
  93. package/src/client/adapter.ts +66 -14
  94. package/src/client/adapterUtils.ts +23 -8
  95. package/src/client/createSchema.ts +0 -8
  96. package/src/client/index.ts +124 -63
  97. package/src/component/_generated/api.d.ts +133 -1303
  98. package/src/component/adapter.ts +1 -0
  99. package/src/component/schema.ts +11 -214
  100. package/src/plugins/convex/index.ts +38 -5
  101. package/src/plugins/cross-domain/index.ts +8 -0
  102. package/src/react-start/index.ts +10 -2
  103. package/src/utils/index.ts +20 -10
@@ -1,14 +1,3 @@
1
- /**
2
- * @deprecated Just reference variables direct, the component will
3
- * use other ways to make sure the appropriate variables are available
4
- */
5
- export const requireEnv = (name) => {
6
- const value = process.env[name];
7
- if (value === undefined) {
8
- throw new Error(`Missing environment variable \`${name}\``);
9
- }
10
- return value;
11
- };
12
1
  export const isQueryCtx = (ctx) => {
13
2
  return "db" in ctx;
14
3
  };
@@ -18,6 +7,9 @@ export const isMutationCtx = (ctx) => {
18
7
  export const isActionCtx = (ctx) => {
19
8
  return "runAction" in ctx;
20
9
  };
10
+ export const isRunMutationCtx = (ctx) => {
11
+ return "runMutation" in ctx;
12
+ };
21
13
  export const requireQueryCtx = (ctx) => {
22
14
  if (!isQueryCtx(ctx)) {
23
15
  throw new Error("Query context required");
@@ -36,4 +28,10 @@ export const requireActionCtx = (ctx) => {
36
28
  }
37
29
  return ctx;
38
30
  };
31
+ export const requireRunMutationCtx = (ctx) => {
32
+ if (!isRunMutationCtx(ctx)) {
33
+ throw new Error("Mutation or action context required");
34
+ }
35
+ return ctx;
36
+ };
39
37
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE;IACzC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,IAAI,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,GAA0B,EACS,EAAE;IACrC,OAAO,IAAI,IAAI,GAAG,CAAC;AACrB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,GAA0B,EACY,EAAE;IACxC,OAAO,IAAI,IAAI,GAAG,IAAI,WAAW,IAAI,GAAG,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,GAA0B,EACU,EAAE;IACtC,OAAO,WAAW,IAAI,GAAG,CAAC;AAC5B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,GAA0B,EACE,EAAE;IAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,GAA0B,EACK,EAAE;IACjC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,GAA0B,EACG,EAAE;IAC/B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,GAA0B,EACS,EAAE;IACrC,OAAO,IAAI,IAAI,GAAG,CAAC;AACrB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,GAA0B,EACY,EAAE;IACxC,OAAO,IAAI,IAAI,GAAG,IAAI,WAAW,IAAI,GAAG,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,GAA0B,EACU,EAAE;IACtC,OAAO,WAAW,IAAI,GAAG,CAAC;AAC5B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,GAA0B,EACQ,EAAE;IACpC,OAAO,aAAa,IAAI,GAAG,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,GAA0B,EACE,EAAE;IAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,GAA0B,EACK,EAAE;IACjC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,GAA0B,EACG,EAAE;IAC/B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,GAA0B,EACC,EAAE;IAC7B,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC"}
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "bugs": {
7
7
  "url": "https://github.com/get-convex/better-auth/issues"
8
8
  },
9
- "version": "0.8.9",
9
+ "version": "0.9.1",
10
10
  "license": "Apache-2.0",
11
11
  "keywords": [
12
12
  "convex",
@@ -23,7 +23,7 @@
23
23
  "build:cjs": "tsc --project ./commonjs.json && npm run build:cjs:generatePackageJson",
24
24
  "build:esm:generatePackageJson": "echo '{\\n \"type\": \"module\"\\n}' > dist/esm/package.json",
25
25
  "build:cjs:generatePackageJson": "echo '{\\n \"type\": \"commonjs\"\\n}' > dist/commonjs/package.json",
26
- "build:watch": "chokidar 'tsconfig*.json' 'src/**/*.ts' -c 'npm run build' --initial",
26
+ "build:watch": "chokidar 'tsconfig*.json' 'src/**/*.{ts,tsx}' -c 'npm run build' --initial",
27
27
  "typecheck": "tsc --noEmit",
28
28
  "prepack": "node node10stubs.mjs",
29
29
  "prepublishOnly": "npm run build",
@@ -79,10 +79,12 @@
79
79
  },
80
80
  "./nextjs": {
81
81
  "import": {
82
+ "@convex-dev/component-source": "./src/nextjs/index.ts",
82
83
  "types": "./dist/esm/nextjs/index.d.ts",
83
84
  "default": "./dist/esm/nextjs/index.js"
84
85
  },
85
86
  "require": {
87
+ "@convex-dev/component-source": "./src/nextjs/index.ts",
86
88
  "types": "./dist/commonjs/nextjs/index.d.ts",
87
89
  "default": "./dist/commonjs/nextjs/index.js"
88
90
  }
@@ -113,10 +115,12 @@
113
115
  },
114
116
  "./react-start": {
115
117
  "import": {
118
+ "@convex-dev/component-source": "./src/react-start/index.ts",
116
119
  "types": "./dist/esm/react-start/index.d.ts",
117
120
  "default": "./dist/esm/react-start/index.js"
118
121
  },
119
122
  "require": {
123
+ "@convex-dev/component-source": "./src/react-start/index.ts",
120
124
  "types": "./dist/commonjs/react-start/index.d.ts",
121
125
  "default": "./dist/commonjs/react-start/index.js"
122
126
  }
@@ -149,18 +153,16 @@
149
153
  }
150
154
  },
151
155
  "peerDependencies": {
152
- "better-auth": "1.3.8",
156
+ "better-auth": "1.3.27",
153
157
  "convex": "^1.26.2",
154
158
  "react": "^18.3.1 || ^19.0.0",
155
159
  "react-dom": "^18.3.1 || ^19.0.0"
156
160
  },
157
161
  "devDependencies": {
158
- "@better-auth/stripe": "1.3.8",
162
+ "@better-fetch/fetch": "^1.1.18",
159
163
  "@edge-runtime/vm": "^5.0.0",
160
164
  "@eslint/js": "^9.9.1",
161
- "@polar-sh/better-auth": "^1.0.4",
162
- "@polar-sh/sdk": "^0.34.5",
163
- "@tanstack/react-start": "^1.120.19",
165
+ "@tanstack/react-start": "^1.132.37",
164
166
  "@types/common-tags": "^1.8.4",
165
167
  "@types/node": "^20",
166
168
  "@types/react": "19.1.6",
@@ -183,11 +185,14 @@
183
185
  "types": "./dist/commonjs/client/index.d.ts",
184
186
  "module": "./dist/esm/client/index.js",
185
187
  "dependencies": {
186
- "@better-fetch/fetch": "^1.1.18",
188
+ "@vitejs/plugin-react": "^5.0.4",
187
189
  "common-tags": "^1.8.2",
188
190
  "convex-helpers": "^0.1.95",
189
191
  "is-network-error": "^1.1.0",
192
+ "remeda": "^2.32.0",
190
193
  "type-fest": "^4.39.1",
194
+ "vite": "^7.1.9",
195
+ "vite-tsconfig-paths": "^5.1.4",
191
196
  "zod": "^3.24.4"
192
197
  }
193
198
  }
@@ -42,47 +42,62 @@ export const getAdapter = (t: ReturnType<typeof convexTest>) => async () => {
42
42
  deleteMany: async (data) => {
43
43
  return t.mutation(api.adapterTest.deleteMany, data);
44
44
  },
45
+ transaction: false as any,
45
46
  } satisfies Adapter;
46
47
  };
47
48
 
48
49
  describe("Better Auth Adapter Tests", async () => {
49
50
  const _t = convexTest(schema, import.meta.glob("../component/**/*.*s"));
50
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
51
- const activeTests = [
52
- "CREATE_MODEL",
53
- "CREATE_MODEL_SHOULD_ALWAYS_RETURN_AN_ID",
54
- "FIND_MODEL",
55
- "FIND_MODEL_WITHOUT_ID",
56
- "FIND_MODEL_WITH_SELECT",
57
- "FIND_MODEL_WITH_MODIFIED_FIELD_NAME",
58
- "UPDATE_MODEL",
59
- "SHOULD_FIND_MANY",
60
- "SHOULD_FIND_MANY_WITH_WHERE",
61
- "SHOULD_FIND_MANY_WITH_OPERATORS",
62
- "SHOULD_WORK_WITH_REFERENCE_FIELDS",
63
- "SHOULD_FIND_MANY_WITH_SORT_BY",
64
- "SHOULD_FIND_MANY_WITH_LIMIT",
65
- "SHOULD_UPDATE_WITH_MULTIPLE_WHERE",
66
- "DELETE_MODEL",
67
- "SHOULD_DELETE_MANY",
68
- "SHOULD_NOT_THROW_ON_DELETE_RECORD_NOT_FOUND",
69
- "SHOULD_NOT_THROW_ON_RECORD_NOT_FOUND",
70
- "SHOULD_FIND_MANY_WITH_CONTAINS_OPERATOR",
71
- "SHOULD_SEARCH_USERS_WITH_STARTS_WITH",
72
- "SHOULD_SEARCH_USERS_WITH_ENDS_WITH",
73
- ];
74
- const inactiveTests = [
75
- // not supported
76
- "SHOULD_FIND_MANY_WITH_OFFSET",
77
- "SHOULD_PREFER_GENERATE_ID_IF_PROVIDED",
78
- ];
51
+ const status = {
52
+ active: "active",
53
+ only: "only",
54
+ notSupported: "not supported",
55
+ } as const;
56
+ const tests: Record<string, (typeof status)[keyof typeof status]> = {
57
+ CREATE_MODEL: status.active,
58
+ CREATE_MODEL_SHOULD_ALWAYS_RETURN_AN_ID: status.active,
59
+ FIND_MODEL: status.active,
60
+ FIND_MODEL_WITHOUT_ID: status.active,
61
+ FIND_MODEL_WITH_SELECT: status.active,
62
+ FIND_MODEL_WITH_MODIFIED_FIELD_NAME: status.active,
63
+ UPDATE_MODEL: status.active,
64
+ SHOULD_FIND_MANY: status.active,
65
+ SHOULD_FIND_MANY_WITH_WHERE: status.active,
66
+ SHOULD_FIND_MANY_WITH_OPERATORS: status.active,
67
+ SHOULD_WORK_WITH_REFERENCE_FIELDS: status.active,
68
+ SHOULD_FIND_MANY_WITH_NOT_IN_OPERATOR: status.active,
69
+ SHOULD_FIND_MANY_WITH_SORT_BY: status.active,
70
+ SHOULD_FIND_MANY_WITH_LIMIT: status.active,
71
+ SHOULD_UPDATE_WITH_MULTIPLE_WHERE: status.active,
72
+ DELETE_MODEL: status.active,
73
+ SHOULD_DELETE_MANY: status.active,
74
+ SHOULD_NOT_THROW_ON_DELETE_RECORD_NOT_FOUND: status.active,
75
+ SHOULD_NOT_THROW_ON_RECORD_NOT_FOUND: status.active,
76
+ SHOULD_FIND_MANY_WITH_CONTAINS_OPERATOR: status.active,
77
+ SHOULD_SEARCH_USERS_WITH_STARTS_WITH: status.active,
78
+ SHOULD_SEARCH_USERS_WITH_ENDS_WITH: status.active,
79
+ // Use local install and Convex paginated queries
80
+ SHOULD_FIND_MANY_WITH_OFFSET: status.notSupported,
81
+ // Convex generates ids on insert
82
+ SHOULD_PREFER_GENERATE_ID_IF_PROVIDED: status.notSupported,
83
+ // Transactions are inherent for auth.api and not possible for authClient
84
+ SHOULD_ROLLBACK_FAILING_TRANSACTION: status.notSupported,
85
+ SHOULD_RETURN_TRANSACTION_RESULT: status.notSupported,
86
+ SHOULD_FIND_MANY_WITH_CONNECTORS: status.active,
87
+ };
88
+
89
+ const disableTests = Object.fromEntries(
90
+ Object.entries(tests).map((entry, idx, arr) => {
91
+ if (arr.some((e) => e[1] === status.only)) {
92
+ return [entry[0], !(entry[1] === status.only)];
93
+ }
94
+ return [entry[0], !(entry[1] === status.active)];
95
+ })
96
+ );
79
97
 
80
98
  await runAdapterTest({
81
99
  getAdapter: getAdapter(_t),
82
- disableTests: Object.fromEntries([
83
- ...activeTests.map((test) => [test, false]),
84
- ...inactiveTests.map((test) => [test, true]),
85
- ]),
100
+ disableTests,
86
101
  });
87
102
  });
88
103
 
@@ -338,6 +353,51 @@ describe("Convex Adapter Tests", async () => {
338
353
  })
339
354
  ).toEqual(user);
340
355
  });
356
+ test("should handle OR where clauses with sortBy", async () => {
357
+ const t = convexTest(schema, import.meta.glob("../component/**/*.*s"));
358
+ const adapter = await getAdapter(t)();
359
+ const fooUser = await adapter.create({
360
+ model: "user",
361
+ data: {
362
+ name: "foo",
363
+ email: "foo@bar.com",
364
+ },
365
+ });
366
+ const barUser = await adapter.create({
367
+ model: "user",
368
+ data: {
369
+ name: "bar",
370
+ email: "bar@bar.com",
371
+ },
372
+ });
373
+ await adapter.create({
374
+ model: "user",
375
+ data: {
376
+ name: "baz",
377
+ email: "baz@bar.com",
378
+ },
379
+ });
380
+ expect(
381
+ await adapter.findMany({
382
+ model: "user",
383
+ where: [
384
+ { field: "name", value: "bar", connector: "OR" },
385
+ { field: "name", value: "foo", connector: "OR" },
386
+ ],
387
+ sortBy: { field: "name", direction: "asc" },
388
+ })
389
+ ).toEqual([barUser, fooUser]);
390
+ expect(
391
+ await adapter.findMany({
392
+ model: "user",
393
+ where: [
394
+ { field: "name", value: "bar", connector: "OR" },
395
+ { field: "name", value: "foo", connector: "OR" },
396
+ ],
397
+ sortBy: { field: "name", direction: "desc" },
398
+ })
399
+ ).toEqual([fooUser, barUser]);
400
+ });
341
401
  test("should handle count", async () => {
342
402
  const t = convexTest(schema, import.meta.glob("../component/**/*.*s"));
343
403
  const adapter = await getAdapter(t)();
@@ -387,7 +447,7 @@ describe("Convex Adapter Tests", async () => {
387
447
  ).toEqual(null);
388
448
  });
389
449
 
390
- test("should handle compound operator on non-unique fieldwithout an index", async () => {
450
+ test("should handle compound operator on non-unique field without an index", async () => {
391
451
  const t = convexTest(schema, import.meta.glob("../component/**/*.*s"));
392
452
  const adapter = await getAdapter(t)();
393
453
  await adapter.create({
@@ -1,7 +1,6 @@
1
1
  import {
2
- AdapterDebugLogs,
3
- CleanedWhere,
4
- createAdapter,
2
+ createAdapterFactory,
3
+ DBAdapterDebugLogOption,
5
4
  } from "better-auth/adapters";
6
5
  import {
7
6
  createFunctionHandle,
@@ -13,10 +12,13 @@ import {
13
12
  SchemaDefinition,
14
13
  } from "convex/server";
15
14
  import { SetOptional } from "type-fest";
16
- import { createSchema } from "./createSchema";
17
15
  import { AuthFunctions, GenericCtx, Triggers, UseApi } from ".";
18
16
  import defaultSchema from "../component/schema";
19
17
  import { api as componentApi } from "../component/_generated/api";
18
+ import { Where } from "better-auth/types";
19
+ import { asyncMap } from "convex-helpers";
20
+ import { prop, sortBy, unique } from "remeda";
21
+ import { isRunMutationCtx } from "../utils";
20
22
 
21
23
  const handlePagination = async (
22
24
  next: ({
@@ -77,11 +79,11 @@ const handlePagination = async (
77
79
  return state;
78
80
  };
79
81
 
80
- type ConvexCleanedWhere = CleanedWhere & {
82
+ type ConvexCleanedWhere = Where & {
81
83
  value: string | number | boolean | string[] | number[] | null;
82
84
  };
83
85
 
84
- const parseWhere = (where?: CleanedWhere[]): ConvexCleanedWhere[] => {
86
+ const parseWhere = (where?: Where[]): ConvexCleanedWhere[] => {
85
87
  return where?.map((where) => {
86
88
  if (where.value instanceof Date) {
87
89
  return {
@@ -99,21 +101,31 @@ export const convexAdapter = <
99
101
  Schema extends SchemaDefinition<any, any> = typeof defaultSchema,
100
102
  >(
101
103
  ctx: Ctx,
102
- api: UseApi<typeof componentApi>,
104
+ api: {
105
+ adapter: SetOptional<
106
+ UseApi<typeof componentApi>["adapter"],
107
+ "migrationRemoveUserId"
108
+ >;
109
+ adapterTest?: UseApi<typeof componentApi>["adapterTest"];
110
+ },
103
111
  config: {
104
- debugLogs?: AdapterDebugLogs;
112
+ debugLogs?: DBAdapterDebugLogOption;
105
113
  authFunctions?: AuthFunctions;
106
114
  triggers?: Triggers<DataModel, Schema>;
107
115
  } = {}
108
116
  ) => {
109
- return createAdapter({
117
+ return createAdapterFactory({
110
118
  config: {
111
119
  adapterId: "convex",
112
120
  adapterName: "Convex Adapter",
113
121
  debugLogs: config.debugLogs || false,
114
122
  disableIdGeneration: true,
123
+ transaction: false,
115
124
  supportsNumericIds: false,
116
125
  usePlural: false,
126
+ mapKeysTransformInput: {
127
+ id: "_id",
128
+ },
117
129
  mapKeysTransformOutput: {
118
130
  _id: "id",
119
131
  },
@@ -135,10 +147,17 @@ export const convexAdapter = <
135
147
  },
136
148
  },
137
149
  adapter: ({ options }) => {
150
+ // Disable telemetry in all cases because it requires Node
138
151
  options.telemetry = { enabled: false };
139
152
  return {
140
153
  id: "convex",
141
- createSchema,
154
+ options: {
155
+ isRunMutationCtx: isRunMutationCtx(ctx),
156
+ },
157
+ createSchema: async ({ file, tables }) => {
158
+ const { createSchema } = await import("./createSchema");
159
+ return createSchema({ file, tables });
160
+ },
142
161
  create: async ({ model, data, select }): Promise<any> => {
143
162
  if (!("runMutation" in ctx)) {
144
163
  throw new Error("ctx is not a mutation ctx");
@@ -177,8 +196,30 @@ export const convexAdapter = <
177
196
  throw new Error("offset not supported");
178
197
  }
179
198
  if (data.where?.some((w) => w.connector === "OR")) {
180
- throw new Error("OR connector not supported in findMany");
199
+ const results = await asyncMap(data.where, async (w) =>
200
+ handlePagination(
201
+ async ({ paginationOpts }) => {
202
+ return await ctx.runQuery(api.adapter.findMany, {
203
+ ...data,
204
+ where: parseWhere([w]),
205
+ paginationOpts,
206
+ });
207
+ },
208
+ { limit: data.limit }
209
+ )
210
+ );
211
+ const docs = unique(results.flatMap((r) => r.docs));
212
+ if (data.sortBy) {
213
+ const result = sortBy(docs, [
214
+ prop(data.sortBy.field),
215
+ data.sortBy.direction,
216
+ ]);
217
+ console.log(result);
218
+ return result;
219
+ }
220
+ return docs;
181
221
  }
222
+
182
223
  const result = await handlePagination(
183
224
  async ({ paginationOpts }) => {
184
225
  return await ctx.runQuery(api.adapter.findMany, {
@@ -194,8 +235,19 @@ export const convexAdapter = <
194
235
  count: async (data) => {
195
236
  // Yes, count is just findMany returning a number.
196
237
  if (data.where?.some((w) => w.connector === "OR")) {
197
- throw new Error("OR connector not supported in findMany");
238
+ const results = await asyncMap(data.where, async (w) =>
239
+ handlePagination(async ({ paginationOpts }) => {
240
+ return await ctx.runQuery(api.adapter.findMany, {
241
+ ...data,
242
+ where: parseWhere([w]),
243
+ paginationOpts,
244
+ });
245
+ })
246
+ );
247
+ const docs = unique(results.flatMap((r) => r.docs));
248
+ return docs.length;
198
249
  }
250
+
199
251
  const result = await handlePagination(async ({ paginationOpts }) => {
200
252
  return await ctx.runQuery(api.adapter.findMany, {
201
253
  ...data,
@@ -203,7 +255,7 @@ export const convexAdapter = <
203
255
  paginationOpts,
204
256
  });
205
257
  });
206
- return result.docs?.length ?? 0;
258
+ return result.docs.length;
207
259
  },
208
260
  update: async (data): Promise<any> => {
209
261
  if (!("runMutation" in ctx)) {
@@ -272,7 +324,7 @@ export const convexAdapter = <
272
324
  },
273
325
  updateMany: async (data) => {
274
326
  if (!("runMutation" in ctx)) {
275
- throw new Error("ctx is not an action ctx");
327
+ throw new Error("ctx is not a mutation ctx");
276
328
  }
277
329
  const onUpdateHandle =
278
330
  config.authFunctions?.onUpdate &&
@@ -24,6 +24,7 @@ export const adapterWhereValidator = v.object({
24
24
  v.literal("gte"),
25
25
  v.literal("eq"),
26
26
  v.literal("in"),
27
+ v.literal("not_in"),
27
28
  v.literal("ne"),
28
29
  v.literal("contains"),
29
30
  v.literal("starts_with"),
@@ -96,6 +97,7 @@ const findIndex = (
96
97
  | "gte"
97
98
  | "eq"
98
99
  | "in"
100
+ | "not_in"
99
101
  | "ne"
100
102
  | "contains"
101
103
  | "starts_with"
@@ -120,8 +122,10 @@ const findIndex = (
120
122
  const where = args.where?.filter((w) => {
121
123
  return (
122
124
  (!w.operator ||
123
- ["lt", "lte", "gt", "gte", "eq", "in"].includes(w.operator)) &&
124
- w.field !== "id"
125
+ ["lt", "lte", "gt", "gte", "eq", "in", "not_in"].includes(
126
+ w.operator
127
+ )) &&
128
+ w.field !== "_id"
125
129
  );
126
130
  });
127
131
  if (!where?.length && !args.sortBy) {
@@ -341,6 +345,12 @@ const filterByWhere = <
341
345
  case "in": {
342
346
  return Array.isArray(w.value) && (w.value as any[]).includes(value);
343
347
  }
348
+ case "not_in": {
349
+ const result =
350
+ Array.isArray(w.value) && !(w.value as any[]).includes(value);
351
+ console.log(doc, "not_in", w, value, result);
352
+ return result;
353
+ }
344
354
  case "lt": {
345
355
  return isLessThan(value, w.value);
346
356
  }
@@ -439,7 +449,9 @@ const generateQuery = (
439
449
  // incompatible with Convex statically.
440
450
  (w) =>
441
451
  w.operator &&
442
- ["contains", "starts_with", "ends_with", "ne"].includes(w.operator)
452
+ ["contains", "starts_with", "ends_with", "ne", "not_in"].includes(
453
+ w.operator
454
+ )
443
455
  );
444
456
  });
445
457
  return filteredQuery;
@@ -470,11 +482,13 @@ export const paginate = async <
470
482
  if (
471
483
  args.where?.some(
472
484
  (w) =>
473
- w.field === "id" && w.operator && !["eq", "in"].includes(w.operator)
485
+ w.field === "_id" &&
486
+ w.operator &&
487
+ !["eq", "in", "not_in"].includes(w.operator)
474
488
  )
475
489
  ) {
476
490
  throw new Error(
477
- `id can only be used with eq or in operator: ${JSON.stringify(args.where)}`
491
+ `_id can only be used with eq, in, or not_in operator: ${JSON.stringify(args.where)}`
478
492
  );
479
493
  }
480
494
  // If any where clause is "eq" (or missing operator) on a unique field,
@@ -483,7 +497,8 @@ export const paginate = async <
483
497
  const uniqueWhere = args.where?.find(
484
498
  (w) =>
485
499
  (!w.operator || w.operator === "eq") &&
486
- (isUniqueField(betterAuthSchema, args.model, w.field) || w.field === "id")
500
+ (isUniqueField(betterAuthSchema, args.model, w.field) ||
501
+ w.field === "_id")
487
502
  );
488
503
  if (uniqueWhere) {
489
504
  const { index } =
@@ -492,7 +507,7 @@ export const paginate = async <
492
507
  where: [uniqueWhere],
493
508
  }) || {};
494
509
  const doc =
495
- uniqueWhere.field === "id"
510
+ uniqueWhere.field === "_id"
496
511
  ? await ctx.db.get(uniqueWhere.value as GenericId<T>)
497
512
  : await ctx.db
498
513
  .query(args.model as any)
@@ -533,7 +548,7 @@ export const paginate = async <
533
548
  throw new Error("in clause value must be an array");
534
549
  }
535
550
  // For ids, just use asyncMap + .get()
536
- if (inWhere.field === "id") {
551
+ if (inWhere.field === "_id") {
537
552
  const docs = await asyncMap(inWhere.value as any[], async (value) => {
538
553
  return ctx.db.get(value as GenericId<T>);
539
554
  });
@@ -9,15 +9,7 @@ export const indexFields = {
9
9
  verification: ["expiresAt", "identifier"],
10
10
  user: [["email", "name"], "name", "userId"],
11
11
  passkey: ["credentialID"],
12
- apikey: ["key"],
13
- member: [["organizationId", "userId"]],
14
- invitation: [
15
- ["email", "organizationId", "status"],
16
- ["organizationId", "status"],
17
- ],
18
12
  oauthConsent: [["clientId", "userId"]],
19
- ssoProvider: ["organizationId", "domain"],
20
- subscription: ["stripeSubscriptionId", "stripeCustomerId", "referenceId"],
21
13
  };
22
14
 
23
15
  // Return map of unique, sortable, and reference fields