@convex-dev/better-auth 0.10.13 → 0.11.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 (185) hide show
  1. package/dist/auth-options.d.ts.map +1 -1
  2. package/dist/auth-options.js +0 -2
  3. package/dist/auth-options.js.map +1 -1
  4. package/dist/client/adapter-utils.d.ts +10 -10
  5. package/dist/client/adapter-utils.d.ts.map +1 -1
  6. package/dist/client/adapter-utils.js +41 -32
  7. package/dist/client/adapter-utils.js.map +1 -1
  8. package/dist/client/adapter.d.ts +1 -1
  9. package/dist/client/adapter.d.ts.map +1 -1
  10. package/dist/client/adapter.js +113 -7
  11. package/dist/client/adapter.js.map +1 -1
  12. package/dist/client/create-api.d.ts +8 -7
  13. package/dist/client/create-api.d.ts.map +1 -1
  14. package/dist/client/create-api.js +1 -0
  15. package/dist/client/create-api.js.map +1 -1
  16. package/dist/client/create-client.d.ts +1 -1
  17. package/dist/client/create-client.d.ts.map +1 -1
  18. package/dist/client/create-client.js +8 -7
  19. package/dist/client/create-client.js.map +1 -1
  20. package/dist/client/create-schema.d.ts +0 -1
  21. package/dist/client/create-schema.d.ts.map +1 -1
  22. package/dist/client/create-schema.js +0 -1
  23. package/dist/client/create-schema.js.map +1 -1
  24. package/dist/component/_generated/api.d.ts +12 -0
  25. package/dist/component/_generated/api.d.ts.map +1 -1
  26. package/dist/component/_generated/api.js.map +1 -1
  27. package/dist/component/_generated/component.d.ts +7407 -92
  28. package/dist/component/_generated/component.d.ts.map +1 -1
  29. package/dist/component/adapter.d.ts +8 -7
  30. package/dist/component/adapter.d.ts.map +1 -1
  31. package/dist/component/adapterTest.d.ts +1 -7
  32. package/dist/component/adapterTest.d.ts.map +1 -1
  33. package/dist/component/adapterTest.js +193 -390
  34. package/dist/component/adapterTest.js.map +1 -1
  35. package/dist/component/schema.d.ts +35 -74
  36. package/dist/component/schema.d.ts.map +1 -1
  37. package/dist/component/schema.js +16 -21
  38. package/dist/component/schema.js.map +1 -1
  39. package/dist/component/testProfiles/adapterAdditionalFields.d.ts +131 -0
  40. package/dist/component/testProfiles/adapterAdditionalFields.d.ts.map +1 -0
  41. package/dist/component/testProfiles/adapterAdditionalFields.js +5 -0
  42. package/dist/component/testProfiles/adapterAdditionalFields.js.map +1 -0
  43. package/dist/component/testProfiles/adapterOrganizationJoins.d.ts +131 -0
  44. package/dist/component/testProfiles/adapterOrganizationJoins.d.ts.map +1 -0
  45. package/dist/component/testProfiles/adapterOrganizationJoins.js +5 -0
  46. package/dist/component/testProfiles/adapterOrganizationJoins.js.map +1 -0
  47. package/dist/component/testProfiles/adapterPluginTable.d.ts +131 -0
  48. package/dist/component/testProfiles/adapterPluginTable.d.ts.map +1 -0
  49. package/dist/component/testProfiles/adapterPluginTable.js +5 -0
  50. package/dist/component/testProfiles/adapterPluginTable.js.map +1 -0
  51. package/dist/component/testProfiles/adapterRenameField.d.ts +131 -0
  52. package/dist/component/testProfiles/adapterRenameField.d.ts.map +1 -0
  53. package/dist/component/testProfiles/adapterRenameField.js +5 -0
  54. package/dist/component/testProfiles/adapterRenameField.js.map +1 -0
  55. package/dist/component/testProfiles/adapterRenameUserCustom.d.ts +131 -0
  56. package/dist/component/testProfiles/adapterRenameUserCustom.d.ts.map +1 -0
  57. package/dist/component/testProfiles/adapterRenameUserCustom.js +5 -0
  58. package/dist/component/testProfiles/adapterRenameUserCustom.js.map +1 -0
  59. package/dist/component/testProfiles/adapterRenameUserTable.d.ts +131 -0
  60. package/dist/component/testProfiles/adapterRenameUserTable.d.ts.map +1 -0
  61. package/dist/component/testProfiles/adapterRenameUserTable.js +5 -0
  62. package/dist/component/testProfiles/adapterRenameUserTable.js.map +1 -0
  63. package/dist/component/testProfiles/auth-options.profile-additional-fields.d.ts +3 -0
  64. package/dist/component/testProfiles/auth-options.profile-additional-fields.d.ts.map +1 -0
  65. package/dist/component/testProfiles/auth-options.profile-additional-fields.js +38 -0
  66. package/dist/component/testProfiles/auth-options.profile-additional-fields.js.map +1 -0
  67. package/dist/component/testProfiles/auth-options.profile-plugin-table.d.ts +3 -0
  68. package/dist/component/testProfiles/auth-options.profile-plugin-table.d.ts.map +1 -0
  69. package/dist/component/testProfiles/auth-options.profile-plugin-table.js +92 -0
  70. package/dist/component/testProfiles/auth-options.profile-plugin-table.js.map +1 -0
  71. package/dist/component/testProfiles/auth-options.profile-rename-joins.d.ts +6 -0
  72. package/dist/component/testProfiles/auth-options.profile-rename-joins.d.ts.map +1 -0
  73. package/dist/component/testProfiles/auth-options.profile-rename-joins.js +49 -0
  74. package/dist/component/testProfiles/auth-options.profile-rename-joins.js.map +1 -0
  75. package/dist/component/testProfiles/schema.profile-additional-fields.d.ts +227 -0
  76. package/dist/component/testProfiles/schema.profile-additional-fields.d.ts.map +1 -0
  77. package/dist/component/testProfiles/schema.profile-additional-fields.js +37 -0
  78. package/dist/component/testProfiles/schema.profile-additional-fields.js.map +1 -0
  79. package/dist/component/testProfiles/schema.profile-plugin-table.d.ts +450 -0
  80. package/dist/component/testProfiles/schema.profile-plugin-table.d.ts.map +1 -0
  81. package/dist/component/testProfiles/schema.profile-plugin-table.js +116 -0
  82. package/dist/component/testProfiles/schema.profile-plugin-table.js.map +1 -0
  83. package/dist/nextjs/index.d.ts.map +1 -1
  84. package/dist/nextjs/index.js +1 -0
  85. package/dist/nextjs/index.js.map +1 -1
  86. package/dist/plugins/convex/index.d.ts +131 -12
  87. package/dist/plugins/convex/index.d.ts.map +1 -1
  88. package/dist/plugins/convex/index.js +12 -5
  89. package/dist/plugins/convex/index.js.map +1 -1
  90. package/dist/plugins/cross-domain/client.d.ts +1 -1
  91. package/dist/plugins/cross-domain/index.d.ts +126 -1
  92. package/dist/plugins/cross-domain/index.d.ts.map +1 -1
  93. package/dist/plugins/cross-domain/index.js +10 -15
  94. package/dist/plugins/cross-domain/index.js.map +1 -1
  95. package/dist/react-start/index.d.ts.map +1 -1
  96. package/dist/react-start/index.js +1 -0
  97. package/dist/react-start/index.js.map +1 -1
  98. package/dist/test/adapter-factory/auth-flow.d.ts +42 -0
  99. package/dist/test/adapter-factory/auth-flow.d.ts.map +1 -0
  100. package/dist/test/adapter-factory/auth-flow.js +145 -0
  101. package/dist/test/adapter-factory/auth-flow.js.map +1 -0
  102. package/dist/test/adapter-factory/basic.d.ts +190 -0
  103. package/dist/test/adapter-factory/basic.d.ts.map +1 -0
  104. package/dist/test/adapter-factory/basic.js +2713 -0
  105. package/dist/test/adapter-factory/basic.js.map +1 -0
  106. package/dist/test/adapter-factory/convex-custom.d.ts +18 -0
  107. package/dist/test/adapter-factory/convex-custom.d.ts.map +1 -0
  108. package/dist/test/adapter-factory/convex-custom.js +610 -0
  109. package/dist/test/adapter-factory/convex-custom.js.map +1 -0
  110. package/dist/test/adapter-factory/index.d.ts +11 -0
  111. package/dist/test/adapter-factory/index.d.ts.map +1 -0
  112. package/dist/test/adapter-factory/index.js +11 -0
  113. package/dist/test/adapter-factory/index.js.map +1 -0
  114. package/dist/test/adapter-factory/joins.d.ts +18 -0
  115. package/dist/test/adapter-factory/joins.d.ts.map +1 -0
  116. package/dist/test/adapter-factory/joins.js +22 -0
  117. package/dist/test/adapter-factory/joins.js.map +1 -0
  118. package/dist/test/adapter-factory/number-id.d.ts +18 -0
  119. package/dist/test/adapter-factory/number-id.d.ts.map +1 -0
  120. package/dist/test/adapter-factory/number-id.js +36 -0
  121. package/dist/test/adapter-factory/number-id.js.map +1 -0
  122. package/dist/test/adapter-factory/profile-additional-fields.d.ts +71 -0
  123. package/dist/test/adapter-factory/profile-additional-fields.d.ts.map +1 -0
  124. package/dist/test/adapter-factory/profile-additional-fields.js +44 -0
  125. package/dist/test/adapter-factory/profile-additional-fields.js.map +1 -0
  126. package/dist/test/adapter-factory/profile-plugin-table.d.ts +19 -0
  127. package/dist/test/adapter-factory/profile-plugin-table.d.ts.map +1 -0
  128. package/dist/test/adapter-factory/profile-plugin-table.js +25 -0
  129. package/dist/test/adapter-factory/profile-plugin-table.js.map +1 -0
  130. package/dist/test/adapter-factory/profile-rename-joins.d.ts +73 -0
  131. package/dist/test/adapter-factory/profile-rename-joins.d.ts.map +1 -0
  132. package/dist/test/adapter-factory/profile-rename-joins.js +34 -0
  133. package/dist/test/adapter-factory/profile-rename-joins.js.map +1 -0
  134. package/dist/test/adapter-factory/transactions.d.ts +21 -0
  135. package/dist/test/adapter-factory/transactions.d.ts.map +1 -0
  136. package/dist/test/adapter-factory/transactions.js +28 -0
  137. package/dist/test/adapter-factory/transactions.js.map +1 -0
  138. package/dist/test/adapter-factory/uuid.d.ts +18 -0
  139. package/dist/test/adapter-factory/uuid.d.ts.map +1 -0
  140. package/dist/test/adapter-factory/uuid.js +58 -0
  141. package/dist/test/adapter-factory/uuid.js.map +1 -0
  142. package/dist/utils/index.d.ts +18 -3
  143. package/dist/utils/index.d.ts.map +1 -1
  144. package/dist/utils/index.js.map +1 -1
  145. package/package.json +8 -4
  146. package/src/auth-options.ts +0 -2
  147. package/src/client/adapter-utils.ts +80 -73
  148. package/src/client/adapter.test.ts +2 -74
  149. package/src/client/adapter.ts +142 -7
  150. package/src/client/create-api.ts +1 -0
  151. package/src/client/create-client.ts +14 -6
  152. package/src/client/create-schema.ts +0 -1
  153. package/src/component/_generated/api.ts +12 -0
  154. package/src/component/_generated/component.ts +19454 -215
  155. package/src/component/adapterTest.ts +250 -466
  156. package/src/component/schema.ts +21 -26
  157. package/src/component/testProfiles/adapterAdditionalFields.ts +13 -0
  158. package/src/component/testProfiles/adapterOrganizationJoins.ts +13 -0
  159. package/src/component/testProfiles/adapterPluginTable.ts +13 -0
  160. package/src/component/testProfiles/adapterRenameField.ts +13 -0
  161. package/src/component/testProfiles/adapterRenameUserCustom.ts +13 -0
  162. package/src/component/testProfiles/adapterRenameUserTable.ts +13 -0
  163. package/src/component/testProfiles/auth-options.profile-additional-fields.ts +39 -0
  164. package/src/component/testProfiles/auth-options.profile-plugin-table.ts +93 -0
  165. package/src/component/testProfiles/auth-options.profile-rename-joins.ts +54 -0
  166. package/src/component/testProfiles/schema.profile-additional-fields.ts +39 -0
  167. package/src/component/testProfiles/schema.profile-plugin-table.ts +130 -0
  168. package/src/nextjs/index.ts +1 -0
  169. package/src/plugins/convex/index.test.ts +55 -0
  170. package/src/plugins/convex/index.ts +26 -11
  171. package/src/plugins/cross-domain/index.test.ts +67 -0
  172. package/src/plugins/cross-domain/index.ts +10 -21
  173. package/src/react-start/index.ts +1 -0
  174. package/src/test/adapter-factory/auth-flow.ts +170 -0
  175. package/src/test/adapter-factory/basic.ts +3190 -0
  176. package/src/test/adapter-factory/convex-custom.ts +706 -0
  177. package/src/test/adapter-factory/index.ts +10 -0
  178. package/src/test/adapter-factory/joins.ts +28 -0
  179. package/src/test/adapter-factory/number-id.ts +45 -0
  180. package/src/test/adapter-factory/profile-additional-fields.ts +84 -0
  181. package/src/test/adapter-factory/profile-plugin-table.ts +37 -0
  182. package/src/test/adapter-factory/profile-rename-joins.ts +67 -0
  183. package/src/test/adapter-factory/transactions.ts +38 -0
  184. package/src/test/adapter-factory/uuid.ts +67 -0
  185. package/src/utils/index.ts +25 -3
@@ -1,12 +1,11 @@
1
- import type {
2
- BetterAuthPlugin,
3
- Session,
4
- User,
5
- } from "better-auth";
1
+ import type { BetterAuthPlugin, Session, User } from "better-auth";
6
2
  import type { BetterAuthOptions } from "better-auth/minimal";
7
- import { createAuthMiddleware, sessionMiddleware } from "better-auth/api";
8
3
  import {
9
4
  createAuthEndpoint,
5
+ createAuthMiddleware,
6
+ sessionMiddleware,
7
+ } from "better-auth/api";
8
+ import {
10
9
  jwt as jwtPlugin,
11
10
  bearer as bearerPlugin,
12
11
  oidcProvider as oidcProviderPlugin,
@@ -17,6 +16,21 @@ import type { AuthConfig, AuthProvider } from "convex/server";
17
16
 
18
17
  export const JWT_COOKIE_NAME = "convex_jwt";
19
18
 
19
+ type BetterAuthAfterHooks = NonNullable<
20
+ NonNullable<BetterAuthPlugin["hooks"]>["after"]
21
+ >;
22
+ type BetterAuthAfterHook = BetterAuthAfterHooks[number];
23
+ type BetterAuthHookContext = Parameters<BetterAuthAfterHook["matcher"]>[0];
24
+
25
+ const normalizeAfterHooks = <THook extends BetterAuthAfterHook>(
26
+ hooks: THook[]
27
+ ): BetterAuthAfterHooks => {
28
+ return hooks.map((hook) => ({
29
+ ...hook,
30
+ matcher: (ctx: BetterAuthHookContext) => Boolean(hook.matcher(ctx)),
31
+ }));
32
+ };
33
+
20
34
  const getJwksAlg = (authProvider: AuthProvider) => {
21
35
  const isCustomJwt =
22
36
  "type" in authProvider && authProvider.type === "customJwt";
@@ -280,7 +294,7 @@ export const convex = (opts: {
280
294
  const knownSafePaths = ["/api-key/list", "/api-key/get"];
281
295
  const noopWrite = (method: string) => {
282
296
  return async (..._args: any[]) => {
283
- if (!knownSafePaths.includes(ctx.path)) {
297
+ if (ctx.path && !knownSafePaths.includes(ctx.path)) {
284
298
  // eslint-disable-next-line no-console
285
299
  console.warn(
286
300
  `[convex-better-auth] Write operation "${method}" skipped in query context for ${ctx.path}`
@@ -299,7 +313,7 @@ export const convex = (opts: {
299
313
  },
300
314
  ],
301
315
  after: [
302
- ...oidcProvider.hooks.after,
316
+ ...normalizeAfterHooks(oidcProvider.hooks.after),
303
317
  {
304
318
  matcher: (ctx) => {
305
319
  return Boolean(
@@ -311,6 +325,7 @@ export const convex = (opts: {
311
325
  ctx.path?.startsWith("/email-otp/verify-email") ||
312
326
  ctx.path?.startsWith("/phone-number/verify") ||
313
327
  ctx.path?.startsWith("/siwe/verify") ||
328
+ ctx.path?.startsWith("/update-session") ||
314
329
  (ctx.path?.startsWith("/get-session") && ctx.context.session)
315
330
  );
316
331
  },
@@ -341,10 +356,10 @@ export const convex = (opts: {
341
356
  },
342
357
  {
343
358
  matcher: (ctx) => {
344
- return (
359
+ return Boolean(
345
360
  ctx.path?.startsWith("/sign-out") ||
346
- ctx.path?.startsWith("/delete-user") ||
347
- (ctx.path?.startsWith("/get-session") && !ctx.context.session)
361
+ ctx.path?.startsWith("/delete-user") ||
362
+ (ctx.path?.startsWith("/get-session") && !ctx.context.session)
348
363
  );
349
364
  },
350
365
  handler: createAuthMiddleware(async (ctx) => {
@@ -0,0 +1,67 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { crossDomain } from "./index.js";
3
+
4
+ const getPostRewriteMatcher = () => {
5
+ const plugin = crossDomain({ siteUrl: "https://example.com" });
6
+ const matcher = plugin.hooks?.before?.[2]?.matcher;
7
+ if (!matcher) {
8
+ throw new Error("expected cross-domain POST rewrite matcher");
9
+ }
10
+ return matcher;
11
+ };
12
+
13
+ describe("crossDomain POST rewrite matcher", () => {
14
+ it("matches POST requests regardless of route", () => {
15
+ const matcher = getPostRewriteMatcher();
16
+ type MatcherContext = Parameters<typeof matcher>[0];
17
+
18
+ const knownPathCtx = {
19
+ method: "POST",
20
+ path: "/sign-in/email",
21
+ headers: new Headers(),
22
+ } satisfies Partial<MatcherContext>;
23
+ const unknownPathCtx = {
24
+ method: "POST",
25
+ path: "/custom-endpoint",
26
+ headers: new Headers(),
27
+ } satisfies Partial<MatcherContext>;
28
+
29
+ expect(matcher(knownPathCtx as MatcherContext)).toBe(true);
30
+ expect(matcher(unknownPathCtx as MatcherContext)).toBe(true);
31
+ });
32
+
33
+ it("rejects non-POST methods", () => {
34
+ const matcher = getPostRewriteMatcher();
35
+ type MatcherContext = Parameters<typeof matcher>[0];
36
+
37
+ const getSignInCtx = {
38
+ method: "GET",
39
+ path: "/sign-in/email",
40
+ headers: new Headers(),
41
+ } satisfies Partial<MatcherContext>;
42
+ const optionsLinkSocialCtx = {
43
+ method: "OPTIONS",
44
+ path: "/link-social",
45
+ headers: new Headers(),
46
+ } satisfies Partial<MatcherContext>;
47
+
48
+ expect(matcher(getSignInCtx as MatcherContext)).toBe(false);
49
+ expect(matcher(optionsLinkSocialCtx as MatcherContext)).toBe(false);
50
+ });
51
+
52
+ it("rejects expo-native requests", () => {
53
+ const matcher = getPostRewriteMatcher();
54
+ type MatcherContext = Parameters<typeof matcher>[0];
55
+
56
+ const headers = new Headers();
57
+ headers.set("expo-origin", "expo");
58
+
59
+ const expoCtx = {
60
+ method: "POST",
61
+ path: "/sign-in/social",
62
+ headers,
63
+ } satisfies Partial<MatcherContext>;
64
+
65
+ expect(matcher(expoCtx as MatcherContext)).toBe(false);
66
+ });
67
+ });
@@ -1,11 +1,8 @@
1
1
  import type { BetterAuthPlugin } from "better-auth";
2
2
  import { setSessionCookie } from "better-auth/cookies";
3
3
  import { generateRandomString } from "better-auth/crypto";
4
- import {
5
- createAuthEndpoint,
6
- createAuthMiddleware,
7
- oneTimeToken as oneTimeTokenPlugin,
8
- } from "better-auth/plugins";
4
+ import { createAuthEndpoint, createAuthMiddleware } from "better-auth/api";
5
+ import { oneTimeToken as oneTimeTokenPlugin } from "better-auth/plugins";
9
6
  import { z } from "zod";
10
7
 
11
8
  export const crossDomain = ({ siteUrl }: { siteUrl: string }) => {
@@ -86,7 +83,7 @@ export const crossDomain = ({ siteUrl }: { siteUrl: string }) => {
86
83
  },
87
84
  {
88
85
  matcher: (ctx) => {
89
- return (
86
+ return Boolean(
90
87
  ctx.method === "GET" &&
91
88
  ctx.path?.startsWith("/verify-email") &&
92
89
  !isExpoNative(ctx)
@@ -101,26 +98,18 @@ export const crossDomain = ({ siteUrl }: { siteUrl: string }) => {
101
98
  },
102
99
  {
103
100
  matcher: (ctx) => {
104
- return (
105
- ((ctx.method === "POST" && ctx.path?.startsWith("/link-social")) ||
106
- ctx.path?.startsWith("/send-verification-email") ||
107
- ctx.path?.startsWith("/sign-in/email") ||
108
- ctx.path?.startsWith("/sign-in/social") ||
109
- ctx.path?.startsWith("/sign-in/magic-link") ||
110
- ctx.path?.startsWith("/delete-user") ||
111
- ctx.path?.startsWith("/change-email")) &&
112
- !isExpoNative(ctx)
113
- );
101
+ return Boolean(ctx.method === "POST" && !isExpoNative(ctx));
114
102
  },
115
103
  handler: createAuthMiddleware(async (ctx) => {
116
- const isSignIn = ctx.path.startsWith("/sign-in");
117
- ctx.body.callbackURL = rewriteCallbackURL(ctx.body.callbackURL);
118
- if (isSignIn && ctx.body.newUserCallbackURL) {
104
+ if (ctx.body?.callbackURL) {
105
+ ctx.body.callbackURL = rewriteCallbackURL(ctx.body.callbackURL);
106
+ }
107
+ if (ctx.body?.newUserCallbackURL) {
119
108
  ctx.body.newUserCallbackURL = rewriteCallbackURL(
120
109
  ctx.body.newUserCallbackURL
121
110
  );
122
111
  }
123
- if (isSignIn && ctx.body.errorCallbackURL) {
112
+ if (ctx.body?.errorCallbackURL) {
124
113
  ctx.body.errorCallbackURL = rewriteCallbackURL(
125
114
  ctx.body.errorCallbackURL
126
115
  );
@@ -151,7 +140,7 @@ export const crossDomain = ({ siteUrl }: { siteUrl: string }) => {
151
140
  },
152
141
  {
153
142
  matcher: (ctx) => {
154
- return (
143
+ return Boolean(
155
144
  (ctx.path?.startsWith("/callback") ||
156
145
  ctx.path?.startsWith("/oauth2/callback") ||
157
146
  ctx.path?.startsWith("/magic-link/verify")) &&
@@ -89,6 +89,7 @@ export const convexBetterAuthReactStart = (
89
89
  const mutableHeaders = new Headers(headers);
90
90
  mutableHeaders.delete("content-length");
91
91
  mutableHeaders.delete("transfer-encoding");
92
+ mutableHeaders.set("accept-encoding", "identity");
92
93
  return getToken(siteUrl, mutableHeaders, opts);
93
94
  });
94
95
 
@@ -0,0 +1,170 @@
1
+ import type { Session, User } from "@better-auth/core/db";
2
+ import { createTestSuite } from "@better-auth/test-utils/adapter";
3
+ import { setCookieToHeader } from "better-auth/cookies";
4
+ import { expect } from "vitest";
5
+
6
+ export const AUTH_FLOW_DEFAULT_BETTER_AUTH_OPTIONS = {
7
+ emailAndPassword: {
8
+ enabled: true,
9
+ password: {
10
+ hash: async (password: string) => password,
11
+ async verify(data: { hash: string; password: string }) {
12
+ return data.hash === data.password;
13
+ },
14
+ },
15
+ },
16
+ };
17
+
18
+ export const getAuthFlowSuiteTests = (
19
+ {
20
+ generate,
21
+ getAuth,
22
+ modifyBetterAuthOptions,
23
+ tryCatch,
24
+ }: Parameters<Parameters<typeof createTestSuite>[2]>[0],
25
+ ) => ({
26
+ "should successfully sign up": async () => {
27
+ const auth = await getAuth();
28
+ const user = await generate("user");
29
+ const result = await auth.api.signUpEmail({
30
+ body: {
31
+ email: user.email,
32
+ password: crypto.randomUUID(),
33
+ name: user.name,
34
+ image: user.image || "",
35
+ },
36
+ });
37
+ expect(result.user).toBeDefined();
38
+ expect(result.user.email).toBe(user.email);
39
+ expect(result.user.name).toBe(user.name);
40
+ expect(result.user.image).toBe(user.image || "");
41
+ expect(result.user.emailVerified).toBe(false);
42
+ expect(result.user.createdAt).toBeDefined();
43
+ expect(result.user.updatedAt).toBeDefined();
44
+ },
45
+ "should successfully sign in": async () => {
46
+ const auth = await getAuth();
47
+ const user = await generate("user");
48
+ const password = crypto.randomUUID();
49
+ const signUpResult = await auth.api.signUpEmail({
50
+ body: {
51
+ email: user.email,
52
+ password: password,
53
+ name: user.name,
54
+ image: user.image || "",
55
+ },
56
+ });
57
+ const result = await auth.api.signInEmail({
58
+ body: { email: user.email, password: password },
59
+ });
60
+ expect(result.user).toBeDefined();
61
+ expect(result.user.id).toBe(signUpResult.user.id);
62
+ },
63
+ "should successfully get session": async () => {
64
+ const auth = await getAuth();
65
+ const user = await generate("user");
66
+ const password = crypto.randomUUID();
67
+ const response = await auth.api.signUpEmail({
68
+ body: {
69
+ email: user.email,
70
+ password: password,
71
+ name: user.name,
72
+ image: user.image || "",
73
+ },
74
+ asResponse: true,
75
+ });
76
+ const headers = new Headers();
77
+ setCookieToHeader(headers)({ response });
78
+ const result = await auth.api.getSession({
79
+ headers,
80
+ });
81
+ const signUpResult = (await response.json()) as {
82
+ user: User;
83
+ session: Session;
84
+ };
85
+ signUpResult.user.createdAt = new Date(signUpResult.user.createdAt);
86
+ signUpResult.user.updatedAt = new Date(signUpResult.user.updatedAt);
87
+ expect(result?.user).toBeDefined();
88
+ expect(result?.user).toStrictEqual(signUpResult.user);
89
+ expect(result?.session).toBeDefined();
90
+ },
91
+ "should not sign in with invalid email": async () => {
92
+ const auth = await getAuth();
93
+ const user = await generate("user");
94
+ const { data, error } = await tryCatch(
95
+ auth.api.signInEmail({
96
+ body: { email: user.email, password: crypto.randomUUID() },
97
+ }),
98
+ );
99
+ expect(data).toBeNull();
100
+ expect(error).toBeDefined();
101
+ },
102
+ "should store and retrieve timestamps correctly across timezones": async () => {
103
+ using _ = recoverProcessTZ();
104
+ const auth = await getAuth();
105
+ const user = await generate("user");
106
+ const password = crypto.randomUUID();
107
+ const userSignUp = await auth.api.signUpEmail({
108
+ body: {
109
+ email: user.email,
110
+ password: password,
111
+ name: user.name,
112
+ image: user.image || "",
113
+ },
114
+ });
115
+ process.env.TZ = "Europe/London";
116
+ const userSignIn = await auth.api.signInEmail({
117
+ body: { email: user.email, password: password },
118
+ });
119
+ process.env.TZ = "America/Los_Angeles";
120
+ expect(userSignUp.user.createdAt.toISOString()).toStrictEqual(
121
+ userSignIn.user.createdAt.toISOString(),
122
+ );
123
+ },
124
+ "should sign up with additional fields": async () => {
125
+ await modifyBetterAuthOptions(
126
+ { user: { additionalFields: { dateField: { type: "date" } } } },
127
+ true,
128
+ );
129
+ const auth = await getAuth();
130
+ const user = await generate("user");
131
+ const dateField = new Date();
132
+ const response = await auth.api.signUpEmail({
133
+ body: {
134
+ email: user.email,
135
+ name: user.name,
136
+ password: crypto.randomUUID(),
137
+ //@ts-expect-error - we are testing with additional fields
138
+ dateField: dateField.toISOString(), // using iso string to simulate client to server communication (this should be converted back to Date)
139
+ },
140
+ asResponse: true,
141
+ });
142
+ const headers = new Headers();
143
+ setCookieToHeader(headers)({ response });
144
+ const result = await auth.api.getSession({
145
+ headers,
146
+ });
147
+ //@ts-expect-error - we are testing with additional fields
148
+ expect(result?.user.dateField).toStrictEqual(dateField);
149
+ },
150
+ });
151
+
152
+ /**
153
+ * This test suite tests basic authentication flow using the adapter.
154
+ */
155
+ export const authFlowTestSuite = createTestSuite(
156
+ "auth-flow",
157
+ {
158
+ defaultBetterAuthOptions: AUTH_FLOW_DEFAULT_BETTER_AUTH_OPTIONS,
159
+ },
160
+ (helpers) => getAuthFlowSuiteTests(helpers),
161
+ );
162
+
163
+ function recoverProcessTZ() {
164
+ const originalTZ = process.env.TZ;
165
+ return {
166
+ [Symbol.dispose]: () => {
167
+ process.env.TZ = originalTZ;
168
+ },
169
+ };
170
+ }