better-auth 1.6.9 → 1.6.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 (71) hide show
  1. package/dist/api/index.d.mts +0 -2
  2. package/dist/api/routes/callback.mjs +6 -5
  3. package/dist/api/routes/email-verification.mjs +2 -2
  4. package/dist/api/routes/error.mjs +1 -1
  5. package/dist/api/routes/sign-in.d.mts +0 -1
  6. package/dist/api/routes/sign-in.mjs +4 -11
  7. package/dist/api/routes/sign-up.mjs +1 -1
  8. package/dist/api/routes/update-user.mjs +1 -1
  9. package/dist/api/to-auth-endpoints.mjs +7 -1
  10. package/dist/client/index.d.mts +2 -2
  11. package/dist/client/plugins/index.d.mts +2 -1
  12. package/dist/cookies/cookie-utils.d.mts +10 -1
  13. package/dist/cookies/cookie-utils.mjs +19 -1
  14. package/dist/cookies/index.d.mts +2 -2
  15. package/dist/cookies/index.mjs +2 -2
  16. package/dist/db/internal-adapter.mjs +103 -7
  17. package/dist/db/with-hooks.d.mts +1 -0
  18. package/dist/db/with-hooks.mjs +58 -1
  19. package/dist/integrations/cookie-plugin-guard.mjs +18 -0
  20. package/dist/integrations/next-js.mjs +6 -0
  21. package/dist/integrations/svelte-kit.mjs +6 -0
  22. package/dist/integrations/tanstack-start-solid.mjs +6 -0
  23. package/dist/integrations/tanstack-start.mjs +6 -0
  24. package/dist/oauth2/link-account.mjs +3 -1
  25. package/dist/package.mjs +1 -1
  26. package/dist/plugins/access/access.d.mts +3 -15
  27. package/dist/plugins/access/index.d.mts +2 -2
  28. package/dist/plugins/access/types.d.mts +11 -4
  29. package/dist/plugins/admin/access/statement.d.mts +29 -93
  30. package/dist/plugins/admin/client.d.mts +5 -0
  31. package/dist/plugins/admin/client.mjs +5 -0
  32. package/dist/plugins/admin/routes.mjs +1 -0
  33. package/dist/plugins/anonymous/client.d.mts +1 -0
  34. package/dist/plugins/anonymous/error-codes.d.mts +1 -0
  35. package/dist/plugins/anonymous/error-codes.mjs +1 -0
  36. package/dist/plugins/anonymous/index.d.mts +1 -0
  37. package/dist/plugins/anonymous/index.mjs +16 -2
  38. package/dist/plugins/bearer/index.mjs +2 -4
  39. package/dist/plugins/captcha/index.mjs +14 -1
  40. package/dist/plugins/device-authorization/error-codes.mjs +1 -0
  41. package/dist/plugins/device-authorization/index.d.mts +1 -0
  42. package/dist/plugins/device-authorization/routes.mjs +34 -3
  43. package/dist/plugins/email-otp/routes.mjs +3 -3
  44. package/dist/plugins/generic-oauth/routes.mjs +3 -3
  45. package/dist/plugins/index.d.mts +2 -2
  46. package/dist/plugins/magic-link/index.d.mts +8 -1
  47. package/dist/plugins/magic-link/index.mjs +5 -17
  48. package/dist/plugins/mcp/authorize.mjs +8 -2
  49. package/dist/plugins/mcp/index.mjs +73 -30
  50. package/dist/plugins/oidc-provider/authorize.mjs +8 -2
  51. package/dist/plugins/oidc-provider/index.mjs +63 -33
  52. package/dist/plugins/one-tap/index.mjs +16 -10
  53. package/dist/plugins/organization/access/statement.d.mts +68 -201
  54. package/dist/plugins/organization/client.d.mts +1 -0
  55. package/dist/plugins/organization/client.mjs +1 -1
  56. package/dist/plugins/organization/error-codes.d.mts +1 -0
  57. package/dist/plugins/organization/error-codes.mjs +1 -0
  58. package/dist/plugins/organization/routes/crud-access-control.d.mts +2 -2
  59. package/dist/plugins/organization/routes/crud-invites.d.mts +8 -1
  60. package/dist/plugins/organization/routes/crud-invites.mjs +5 -3
  61. package/dist/plugins/organization/routes/crud-team.mjs +7 -2
  62. package/dist/plugins/organization/types.d.mts +12 -2
  63. package/dist/plugins/siwe/client.d.mts +4 -0
  64. package/dist/plugins/siwe/client.mjs +5 -1
  65. package/dist/plugins/siwe/index.d.mts +13 -2
  66. package/dist/plugins/siwe/index.mjs +179 -165
  67. package/dist/plugins/username/index.d.mts +11 -0
  68. package/dist/plugins/username/index.mjs +18 -2
  69. package/dist/test-utils/test-instance.d.mts +1 -6
  70. package/dist/test-utils/test-instance.mjs +11 -2
  71. package/package.json +10 -10
@@ -9,195 +9,209 @@ import { schema } from "./schema.mjs";
9
9
  import { createAuthEndpoint } from "@better-auth/core/api";
10
10
  import * as z from "zod";
11
11
  //#region src/plugins/siwe/index.ts
12
+ const walletAddressInputSchema = z.string().regex(/^0[xX][a-fA-F0-9]{40}$/i).length(42);
12
13
  const getSiweNonceBodySchema = z.object({
13
- walletAddress: z.string().regex(/^0[xX][a-fA-F0-9]{40}$/i).length(42),
14
+ walletAddress: walletAddressInputSchema.optional(),
15
+ address: walletAddressInputSchema.optional(),
14
16
  chainId: z.number().int().positive().optional().default(1)
17
+ }).refine((body) => body.walletAddress || body.address, {
18
+ message: "walletAddress or address is required",
19
+ path: ["walletAddress"]
15
20
  });
16
- const siwe = (options) => ({
17
- id: "siwe",
18
- version: PACKAGE_VERSION,
19
- schema: mergeSchema(schema, options?.schema),
20
- endpoints: {
21
- getSiweNonce: createAuthEndpoint("/siwe/nonce", {
22
- method: "POST",
23
- body: getSiweNonceBodySchema
24
- }, async (ctx) => {
25
- const { walletAddress: rawWalletAddress, chainId } = ctx.body;
26
- const walletAddress = toChecksumAddress(rawWalletAddress);
27
- const nonce = await options.getNonce();
28
- await ctx.context.internalAdapter.createVerificationValue({
29
- identifier: `siwe:${walletAddress}:${chainId}`,
30
- value: nonce,
31
- expiresAt: new Date(Date.now() + 900 * 1e3)
32
- });
33
- return ctx.json({ nonce });
34
- }),
35
- verifySiweMessage: createAuthEndpoint("/siwe/verify", {
36
- method: "POST",
37
- body: z.object({
38
- message: z.string().min(1),
39
- signature: z.string().min(1),
40
- walletAddress: z.string().regex(/^0[xX][a-fA-F0-9]{40}$/i).length(42),
41
- chainId: z.number().int().positive().optional().default(1),
42
- email: z.email().optional()
43
- }).refine((data) => options.anonymous !== false || !!data.email, {
44
- message: "Email is required when the anonymous plugin option is disabled.",
45
- path: ["email"]
46
- }),
47
- requireRequest: true
48
- }, async (ctx) => {
49
- const { message, signature, walletAddress: rawWalletAddress, chainId, email } = ctx.body;
50
- const walletAddress = toChecksumAddress(rawWalletAddress);
51
- const isAnon = options.anonymous ?? true;
52
- if (!isAnon && !email) throw APIError.fromStatus("BAD_REQUEST", {
53
- message: "Email is required when anonymous is disabled.",
54
- status: 400
55
- });
56
- try {
57
- const verification = await ctx.context.internalAdapter.findVerificationValue(`siwe:${walletAddress}:${chainId}`);
58
- if (!verification || /* @__PURE__ */ new Date() > verification.expiresAt) throw APIError.fromStatus("UNAUTHORIZED", {
59
- message: "Unauthorized: Invalid or expired nonce",
60
- status: 401,
61
- code: "UNAUTHORIZED_INVALID_OR_EXPIRED_NONCE"
21
+ const siwe = (options) => {
22
+ const createSiweNonceEndpoint = (path) => createAuthEndpoint(path, {
23
+ method: "POST",
24
+ body: getSiweNonceBodySchema
25
+ }, async (ctx) => {
26
+ const rawWalletAddress = ctx.body.walletAddress ?? ctx.body.address;
27
+ if (!rawWalletAddress) throw APIError.fromStatus("BAD_REQUEST", {
28
+ message: "walletAddress or address is required",
29
+ status: 400
30
+ });
31
+ const { chainId } = ctx.body;
32
+ const walletAddress = toChecksumAddress(rawWalletAddress);
33
+ const nonce = await options.getNonce();
34
+ await ctx.context.internalAdapter.createVerificationValue({
35
+ identifier: `siwe:${walletAddress}:${chainId}`,
36
+ value: nonce,
37
+ expiresAt: new Date(Date.now() + 900 * 1e3)
38
+ });
39
+ return ctx.json({ nonce });
40
+ });
41
+ return {
42
+ id: "siwe",
43
+ version: PACKAGE_VERSION,
44
+ schema: mergeSchema(schema, options?.schema),
45
+ endpoints: {
46
+ getSiweNonce: createSiweNonceEndpoint("/siwe/nonce"),
47
+ getNonce: createSiweNonceEndpoint("/siwe/get-nonce"),
48
+ verifySiweMessage: createAuthEndpoint("/siwe/verify", {
49
+ method: "POST",
50
+ body: z.object({
51
+ message: z.string().min(1),
52
+ signature: z.string().min(1),
53
+ walletAddress: z.string().regex(/^0[xX][a-fA-F0-9]{40}$/i).length(42),
54
+ chainId: z.number().int().positive().optional().default(1),
55
+ email: z.email().optional()
56
+ }).refine((data) => options.anonymous !== false || !!data.email, {
57
+ message: "Email is required when the anonymous plugin option is disabled.",
58
+ path: ["email"]
59
+ }),
60
+ requireRequest: true
61
+ }, async (ctx) => {
62
+ const { message, signature, walletAddress: rawWalletAddress, chainId, email } = ctx.body;
63
+ const walletAddress = toChecksumAddress(rawWalletAddress);
64
+ const isAnon = options.anonymous ?? true;
65
+ if (!isAnon && !email) throw APIError.fromStatus("BAD_REQUEST", {
66
+ message: "Email is required when anonymous is disabled.",
67
+ status: 400
62
68
  });
63
- const { value: nonce } = verification;
64
- if (!await options.verifyMessage({
65
- message,
66
- signature,
67
- address: walletAddress,
68
- chainId,
69
- cacao: {
70
- h: { t: "caip122" },
71
- p: {
72
- domain: options.domain,
73
- aud: options.domain,
74
- nonce,
75
- iss: options.domain,
76
- version: "1"
77
- },
78
- s: {
79
- t: "eip191",
80
- s: signature
69
+ try {
70
+ const verification = await ctx.context.internalAdapter.findVerificationValue(`siwe:${walletAddress}:${chainId}`);
71
+ if (!verification || /* @__PURE__ */ new Date() > verification.expiresAt) throw APIError.fromStatus("UNAUTHORIZED", {
72
+ message: "Unauthorized: Invalid or expired nonce",
73
+ status: 401,
74
+ code: "UNAUTHORIZED_INVALID_OR_EXPIRED_NONCE"
75
+ });
76
+ const { value: nonce } = verification;
77
+ if (!await options.verifyMessage({
78
+ message,
79
+ signature,
80
+ address: walletAddress,
81
+ chainId,
82
+ cacao: {
83
+ h: { t: "caip122" },
84
+ p: {
85
+ domain: options.domain,
86
+ aud: options.domain,
87
+ nonce,
88
+ iss: options.domain,
89
+ version: "1"
90
+ },
91
+ s: {
92
+ t: "eip191",
93
+ s: signature
94
+ }
81
95
  }
82
- }
83
- })) throw APIError.fromStatus("UNAUTHORIZED", {
84
- message: "Unauthorized: Invalid SIWE signature",
85
- status: 401
86
- });
87
- await ctx.context.internalAdapter.deleteVerificationByIdentifier(`siwe:${walletAddress}:${chainId}`);
88
- let user = null;
89
- const existingWalletAddress = await ctx.context.adapter.findOne({
90
- model: "walletAddress",
91
- where: [{
92
- field: "address",
93
- operator: "eq",
94
- value: walletAddress
95
- }, {
96
- field: "chainId",
97
- operator: "eq",
98
- value: chainId
99
- }]
100
- });
101
- if (existingWalletAddress) user = await ctx.context.adapter.findOne({
102
- model: "user",
103
- where: [{
104
- field: "id",
105
- operator: "eq",
106
- value: existingWalletAddress.userId
107
- }]
108
- });
109
- else {
110
- const anyWalletAddress = await ctx.context.adapter.findOne({
96
+ })) throw APIError.fromStatus("UNAUTHORIZED", {
97
+ message: "Unauthorized: Invalid SIWE signature",
98
+ status: 401
99
+ });
100
+ await ctx.context.internalAdapter.deleteVerificationByIdentifier(`siwe:${walletAddress}:${chainId}`);
101
+ let user = null;
102
+ const existingWalletAddress = await ctx.context.adapter.findOne({
111
103
  model: "walletAddress",
112
104
  where: [{
113
105
  field: "address",
114
106
  operator: "eq",
115
107
  value: walletAddress
108
+ }, {
109
+ field: "chainId",
110
+ operator: "eq",
111
+ value: chainId
116
112
  }]
117
113
  });
118
- if (anyWalletAddress) user = await ctx.context.adapter.findOne({
114
+ if (existingWalletAddress) user = await ctx.context.adapter.findOne({
119
115
  model: "user",
120
116
  where: [{
121
117
  field: "id",
122
118
  operator: "eq",
123
- value: anyWalletAddress.userId
119
+ value: existingWalletAddress.userId
124
120
  }]
125
121
  });
126
- }
127
- if (!user) {
128
- const domain = options.emailDomainName ?? getOrigin(ctx.context.baseURL);
129
- const userEmail = !isAnon && email ? email : `${walletAddress}@${domain}`;
130
- const { name, avatar } = await options.ensLookup?.({ walletAddress }) ?? {};
131
- user = await ctx.context.internalAdapter.createUser({
132
- name: name ?? walletAddress,
133
- email: userEmail,
134
- image: avatar ?? ""
135
- });
136
- await ctx.context.adapter.create({
137
- model: "walletAddress",
138
- data: {
122
+ else {
123
+ const anyWalletAddress = await ctx.context.adapter.findOne({
124
+ model: "walletAddress",
125
+ where: [{
126
+ field: "address",
127
+ operator: "eq",
128
+ value: walletAddress
129
+ }]
130
+ });
131
+ if (anyWalletAddress) user = await ctx.context.adapter.findOne({
132
+ model: "user",
133
+ where: [{
134
+ field: "id",
135
+ operator: "eq",
136
+ value: anyWalletAddress.userId
137
+ }]
138
+ });
139
+ }
140
+ if (!user) {
141
+ const domain = options.emailDomainName ?? getOrigin(ctx.context.baseURL);
142
+ const userEmail = !isAnon && email ? email : `${walletAddress}@${domain}`;
143
+ const { name, avatar } = await options.ensLookup?.({ walletAddress }) ?? {};
144
+ user = await ctx.context.internalAdapter.createUser({
145
+ name: name ?? walletAddress,
146
+ email: userEmail,
147
+ image: avatar ?? ""
148
+ });
149
+ await ctx.context.adapter.create({
150
+ model: "walletAddress",
151
+ data: {
152
+ userId: user.id,
153
+ address: walletAddress,
154
+ chainId,
155
+ isPrimary: true,
156
+ createdAt: /* @__PURE__ */ new Date()
157
+ }
158
+ });
159
+ await ctx.context.internalAdapter.createAccount({
139
160
  userId: user.id,
140
- address: walletAddress,
141
- chainId,
142
- isPrimary: true,
143
- createdAt: /* @__PURE__ */ new Date()
144
- }
161
+ providerId: "siwe",
162
+ accountId: `${walletAddress}:${chainId}`,
163
+ createdAt: /* @__PURE__ */ new Date(),
164
+ updatedAt: /* @__PURE__ */ new Date()
165
+ });
166
+ } else if (!existingWalletAddress) {
167
+ await ctx.context.adapter.create({
168
+ model: "walletAddress",
169
+ data: {
170
+ userId: user.id,
171
+ address: walletAddress,
172
+ chainId,
173
+ isPrimary: false,
174
+ createdAt: /* @__PURE__ */ new Date()
175
+ }
176
+ });
177
+ await ctx.context.internalAdapter.createAccount({
178
+ userId: user.id,
179
+ providerId: "siwe",
180
+ accountId: `${walletAddress}:${chainId}`,
181
+ createdAt: /* @__PURE__ */ new Date(),
182
+ updatedAt: /* @__PURE__ */ new Date()
183
+ });
184
+ }
185
+ const session = await ctx.context.internalAdapter.createSession(user.id);
186
+ if (!session) throw APIError.fromStatus("INTERNAL_SERVER_ERROR", {
187
+ message: "Internal Server Error",
188
+ status: 500
145
189
  });
146
- await ctx.context.internalAdapter.createAccount({
147
- userId: user.id,
148
- providerId: "siwe",
149
- accountId: `${walletAddress}:${chainId}`,
150
- createdAt: /* @__PURE__ */ new Date(),
151
- updatedAt: /* @__PURE__ */ new Date()
190
+ await setSessionCookie(ctx, {
191
+ session,
192
+ user
152
193
  });
153
- } else if (!existingWalletAddress) {
154
- await ctx.context.adapter.create({
155
- model: "walletAddress",
156
- data: {
157
- userId: user.id,
158
- address: walletAddress,
159
- chainId,
160
- isPrimary: false,
161
- createdAt: /* @__PURE__ */ new Date()
194
+ return ctx.json({
195
+ token: session.token,
196
+ success: true,
197
+ user: {
198
+ id: user.id,
199
+ walletAddress,
200
+ chainId
162
201
  }
163
202
  });
164
- await ctx.context.internalAdapter.createAccount({
165
- userId: user.id,
166
- providerId: "siwe",
167
- accountId: `${walletAddress}:${chainId}`,
168
- createdAt: /* @__PURE__ */ new Date(),
169
- updatedAt: /* @__PURE__ */ new Date()
203
+ } catch (error) {
204
+ if (isAPIError(error)) throw error;
205
+ throw APIError.fromStatus("UNAUTHORIZED", {
206
+ message: "Something went wrong. Please try again later.",
207
+ error: error instanceof Error ? error.message : "Unknown error",
208
+ status: 401
170
209
  });
171
210
  }
172
- const session = await ctx.context.internalAdapter.createSession(user.id);
173
- if (!session) throw APIError.fromStatus("INTERNAL_SERVER_ERROR", {
174
- message: "Internal Server Error",
175
- status: 500
176
- });
177
- await setSessionCookie(ctx, {
178
- session,
179
- user
180
- });
181
- return ctx.json({
182
- token: session.token,
183
- success: true,
184
- user: {
185
- id: user.id,
186
- walletAddress,
187
- chainId
188
- }
189
- });
190
- } catch (error) {
191
- if (isAPIError(error)) throw error;
192
- throw APIError.fromStatus("UNAUTHORIZED", {
193
- message: "Something went wrong. Please try again later.",
194
- error: error instanceof Error ? error.message : "Unknown error",
195
- status: 401
196
- });
197
- }
198
- })
199
- },
200
- options
201
- });
211
+ })
212
+ },
213
+ options
214
+ };
215
+ };
202
216
  //#endregion
203
217
  export { siwe };
@@ -151,10 +151,19 @@ declare const username: (options?: UsernameOptions | undefined) => {
151
151
  schema: {
152
152
  type: "object";
153
153
  properties: {
154
+ redirect: {
155
+ type: string;
156
+ description: string;
157
+ };
154
158
  token: {
155
159
  type: string;
156
160
  description: string;
157
161
  };
162
+ url: {
163
+ type: string;
164
+ nullable: boolean;
165
+ description: string;
166
+ };
158
167
  user: {
159
168
  $ref: string;
160
169
  };
@@ -183,7 +192,9 @@ declare const username: (options?: UsernameOptions | undefined) => {
183
192
  };
184
193
  };
185
194
  }, {
195
+ redirect: boolean;
186
196
  token: string;
197
+ url: string | undefined;
187
198
  user: {
188
199
  id: string;
189
200
  createdAt: Date;
@@ -16,7 +16,7 @@ const signInUsernameBodySchema = z.object({
16
16
  username: z.string().meta({ description: "The username of the user" }),
17
17
  password: z.string().meta({ description: "The password of the user" }),
18
18
  rememberMe: z.boolean().meta({ description: "Remember the user session" }).optional(),
19
- callbackURL: z.string().meta({ description: "The URL to redirect to after email verification" }).optional()
19
+ callbackURL: z.string().meta({ description: "URL to redirect to after sign in (also used as the redirect target for email verification when required)" }).optional()
20
20
  });
21
21
  const isUsernameAvailableBodySchema = z.object({ username: z.string().meta({ description: "The username to check" }) });
22
22
  const username = (options) => {
@@ -66,13 +66,26 @@ const username = (options) => {
66
66
  content: { "application/json": { schema: {
67
67
  type: "object",
68
68
  properties: {
69
+ redirect: {
70
+ type: "boolean",
71
+ description: "Whether the client should follow the Location header. True when callbackURL was provided."
72
+ },
69
73
  token: {
70
74
  type: "string",
71
75
  description: "Session token for the authenticated session"
72
76
  },
77
+ url: {
78
+ type: "string",
79
+ nullable: true,
80
+ description: "The callbackURL echoed back so the client can redirect."
81
+ },
73
82
  user: { $ref: "#/components/schemas/User" }
74
83
  },
75
- required: ["token", "user"]
84
+ required: [
85
+ "redirect",
86
+ "token",
87
+ "user"
88
+ ]
76
89
  } } }
77
90
  },
78
91
  422: {
@@ -155,8 +168,11 @@ const username = (options) => {
155
168
  session,
156
169
  user
157
170
  }, ctx.body.rememberMe === false);
171
+ if (ctx.body.callbackURL) ctx.setHeader("Location", ctx.body.callbackURL);
158
172
  return ctx.json({
173
+ redirect: !!ctx.body.callbackURL,
159
174
  token: session.token,
175
+ url: ctx.body.callbackURL,
160
176
  user: parseUserOutput(ctx.context.options, user)
161
177
  });
162
178
  }),
@@ -190,7 +190,6 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
190
190
  };
191
191
  redirect: {
192
192
  type: string;
193
- enum: boolean[];
194
193
  };
195
194
  };
196
195
  required: string[];
@@ -2193,7 +2192,6 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
2193
2192
  };
2194
2193
  redirect: {
2195
2194
  type: string;
2196
- enum: boolean[];
2197
2195
  };
2198
2196
  };
2199
2197
  required: string[];
@@ -4199,7 +4197,6 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
4199
4197
  };
4200
4198
  redirect: {
4201
4199
  type: string;
4202
- enum: boolean[];
4203
4200
  };
4204
4201
  };
4205
4202
  required: string[];
@@ -6202,7 +6199,6 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
6202
6199
  };
6203
6200
  redirect: {
6204
6201
  type: string;
6205
- enum: boolean[];
6206
6202
  };
6207
6203
  };
6208
6204
  required: string[];
@@ -8279,7 +8275,6 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
8279
8275
  };
8280
8276
  redirect: {
8281
8277
  type: string;
8282
- enum: boolean[];
8283
8278
  };
8284
8279
  };
8285
8280
  required: string[];
@@ -10282,7 +10277,6 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
10282
10277
  };
10283
10278
  redirect: {
10284
10279
  type: string;
10285
- enum: boolean[];
10286
10280
  };
10287
10281
  };
10288
10282
  required: string[];
@@ -12157,6 +12151,7 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
12157
12151
  USER_ALREADY_EXISTS: _better_auth_core_utils_error_codes0.RawError<"USER_ALREADY_EXISTS">;
12158
12152
  USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL: _better_auth_core_utils_error_codes0.RawError<"USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL">;
12159
12153
  EMAIL_CAN_NOT_BE_UPDATED: _better_auth_core_utils_error_codes0.RawError<"EMAIL_CAN_NOT_BE_UPDATED">;
12154
+ CHANGE_EMAIL_DISABLED: _better_auth_core_utils_error_codes0.RawError<"CHANGE_EMAIL_DISABLED">;
12160
12155
  CREDENTIAL_ACCOUNT_NOT_FOUND: _better_auth_core_utils_error_codes0.RawError<"CREDENTIAL_ACCOUNT_NOT_FOUND">;
12161
12156
  ACCOUNT_NOT_FOUND: _better_auth_core_utils_error_codes0.RawError<"ACCOUNT_NOT_FOUND">;
12162
12157
  SESSION_EXPIRED: _better_auth_core_utils_error_codes0.RawError<"SESSION_EXPIRED">;
@@ -7,6 +7,7 @@ import { createAuthClient } from "../client/vanilla.mjs";
7
7
  import { bearer } from "../plugins/bearer/index.mjs";
8
8
  import { sql } from "kysely";
9
9
  import { AsyncLocalStorage } from "node:async_hooks";
10
+ import { randomUUID } from "node:crypto";
10
11
  import { afterAll } from "vitest";
11
12
  //#region src/test-utils/test-instance.ts
12
13
  const cleanupSet = /* @__PURE__ */ new Set();
@@ -19,10 +20,17 @@ afterAll(async () => {
19
20
  });
20
21
  async function getTestInstance(options, config) {
21
22
  const testWith = config?.testWith || "sqlite";
23
+ const postgresSchema = testWith === "postgres" ? `ba_test_${randomUUID().replaceAll("-", "_")}` : void 0;
24
+ const quotePostgresIdentifier = (identifier) => `"${identifier.replaceAll("\"", "\"\"")}"`;
22
25
  async function getPostgres() {
23
26
  const { Kysely, PostgresDialect } = await import("kysely");
24
27
  const { Pool } = await import("pg");
25
- return new Kysely({ dialect: new PostgresDialect({ pool: new Pool({ connectionString: "postgres://user:password@localhost:5432/better_auth" }) }) });
28
+ const pool = new Pool({
29
+ connectionString: "postgres://user:password@localhost:5432/better_auth",
30
+ options: postgresSchema ? `-c search_path=${postgresSchema},public` : void 0
31
+ });
32
+ if (postgresSchema) await pool.query(`CREATE SCHEMA IF NOT EXISTS ${quotePostgresIdentifier(postgresSchema)}`);
33
+ return new Kysely({ dialect: new PostgresDialect({ pool }) });
26
34
  }
27
35
  async function getSqlite() {
28
36
  const { DatabaseSync } = await import("node:sqlite");
@@ -103,7 +111,8 @@ async function getTestInstance(options, config) {
103
111
  }
104
112
  if (testWith === "postgres") {
105
113
  const postgres = await getPostgres();
106
- await sql`DROP SCHEMA public CASCADE; CREATE SCHEMA public;`.execute(postgres);
114
+ if (postgresSchema) await sql.raw(`DROP SCHEMA IF EXISTS ${quotePostgresIdentifier(postgresSchema)} CASCADE`).execute(postgres);
115
+ else await sql`DROP SCHEMA public CASCADE; CREATE SCHEMA public;`.execute(postgres);
107
116
  await postgres.destroy();
108
117
  return;
109
118
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-auth",
3
- "version": "1.6.9",
3
+ "version": "1.6.11",
4
4
  "description": "The most comprehensive authentication framework for TypeScript.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -486,16 +486,16 @@
486
486
  "better-call": "1.3.5",
487
487
  "defu": "^6.1.4",
488
488
  "jose": "^6.1.3",
489
- "kysely": "^0.28.14",
489
+ "kysely": "^0.28.17",
490
490
  "nanostores": "^1.1.1",
491
491
  "zod": "^4.3.6",
492
- "@better-auth/core": "1.6.9",
493
- "@better-auth/drizzle-adapter": "1.6.9",
494
- "@better-auth/kysely-adapter": "1.6.9",
495
- "@better-auth/memory-adapter": "1.6.9",
496
- "@better-auth/mongo-adapter": "1.6.9",
497
- "@better-auth/prisma-adapter": "1.6.9",
498
- "@better-auth/telemetry": "1.6.9"
492
+ "@better-auth/core": "1.6.11",
493
+ "@better-auth/drizzle-adapter": "1.6.11",
494
+ "@better-auth/kysely-adapter": "1.6.11",
495
+ "@better-auth/memory-adapter": "1.6.11",
496
+ "@better-auth/mongo-adapter": "1.6.11",
497
+ "@better-auth/prisma-adapter": "1.6.11",
498
+ "@better-auth/telemetry": "1.6.11"
499
499
  },
500
500
  "devDependencies": {
501
501
  "@lynx-js/react": "^0.116.3",
@@ -520,7 +520,7 @@
520
520
  "tsdown": "0.21.1",
521
521
  "type-fest": "^5.4.4",
522
522
  "typescript": "^5.9.3",
523
- "vitest": "^4.0.18",
523
+ "vitest": "^4.1.5",
524
524
  "vue": "^3.5.29"
525
525
  },
526
526
  "peerDependencies": {