@better-auth/core 1.4.6-beta.2 → 1.4.6-beta.4

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 (59) hide show
  1. package/.turbo/turbo-build.log +31 -30
  2. package/dist/api/index.d.mts +1 -2
  3. package/dist/api/index.mjs +3 -2
  4. package/dist/async_hooks/index.d.mts +1 -1
  5. package/dist/async_hooks/index.mjs +2 -1
  6. package/dist/async_hooks-CrTStdt6.mjs +45 -0
  7. package/dist/context/index.d.mts +2 -3
  8. package/dist/context/index.mjs +3 -2
  9. package/dist/{context-DgQ9XGBl.mjs → context-su4uu82y.mjs} +1 -1
  10. package/dist/db/adapter/index.d.mts +2 -3
  11. package/dist/db/adapter/index.mjs +955 -1
  12. package/dist/db/index.d.mts +2 -3
  13. package/dist/db/index.mjs +2 -1
  14. package/dist/env/index.d.mts +1 -1
  15. package/dist/env/index.mjs +1 -1
  16. package/dist/error/index.mjs +3 -2
  17. package/dist/{error-BhAKg8LX.mjs → error-CMXuwPsa.mjs} +1 -1
  18. package/dist/get-tables-BGfrxIVZ.mjs +252 -0
  19. package/dist/{index-D_XSRX55.d.mts → index-Bp1Bfmzt.d.mts} +307 -32
  20. package/dist/{index-DgwIISs7.d.mts → index-Da4Ujjef.d.mts} +0 -1
  21. package/dist/index.d.mts +2 -3
  22. package/dist/oauth2/index.d.mts +1 -2
  23. package/dist/oauth2/index.mjs +1 -1
  24. package/dist/social-providers/index.d.mts +2 -3
  25. package/dist/social-providers/index.mjs +22 -8
  26. package/dist/utils/index.d.mts +10 -1
  27. package/dist/utils/index.mjs +3 -2
  28. package/dist/utils-BqQC77zO.mjs +43 -0
  29. package/package.json +8 -6
  30. package/src/async_hooks/convex.spec.ts +12 -0
  31. package/src/async_hooks/index.ts +60 -25
  32. package/src/db/adapter/factory.ts +1368 -0
  33. package/src/db/adapter/get-default-field-name.ts +59 -0
  34. package/src/db/adapter/get-default-model-name.ts +51 -0
  35. package/src/db/adapter/get-field-attributes.ts +62 -0
  36. package/src/db/adapter/get-field-name.ts +43 -0
  37. package/src/db/adapter/get-id-field.ts +141 -0
  38. package/src/db/adapter/get-model-name.ts +36 -0
  39. package/src/db/adapter/index.ts +12 -0
  40. package/src/db/adapter/types.ts +161 -0
  41. package/src/db/adapter/utils.ts +61 -0
  42. package/src/db/get-tables.ts +276 -0
  43. package/src/db/index.ts +2 -0
  44. package/src/db/test/get-tables.test.ts +62 -0
  45. package/src/env/logger.ts +4 -6
  46. package/src/oauth2/oauth-provider.ts +1 -1
  47. package/src/social-providers/google.ts +46 -17
  48. package/src/types/context.ts +10 -0
  49. package/src/types/helper.ts +4 -0
  50. package/src/types/init-options.ts +24 -24
  51. package/src/utils/id.ts +5 -0
  52. package/src/utils/index.ts +3 -0
  53. package/src/utils/json.ts +25 -0
  54. package/src/utils/string.ts +3 -0
  55. package/dist/async_hooks-BfRfbd1J.mjs +0 -18
  56. package/dist/utils-C5EN75oV.mjs +0 -7
  57. /package/dist/{env-8yWFh7b8.mjs → env-D6s-lvJz.mjs} +0 -0
  58. /package/dist/{index-X1Fs3IbM.d.mts → index-D4vfN5ui.d.mts} +0 -0
  59. /package/dist/{oauth2-B2XPHgx5.mjs → oauth2-7k48hhcV.mjs} +0 -0
@@ -1,7 +1,7 @@
1
- import { i as logger } from "../env-8yWFh7b8.mjs";
2
- import { a as refreshAccessToken, c as getOAuth2Tokens, n as validateAuthorizationCode, o as createAuthorizationURL, s as generateCodeChallenge } from "../oauth2-B2XPHgx5.mjs";
3
- import "../utils-C5EN75oV.mjs";
4
- import { t as BetterAuthError } from "../error-BhAKg8LX.mjs";
1
+ import { i as logger } from "../env-D6s-lvJz.mjs";
2
+ import "../utils-BqQC77zO.mjs";
3
+ import { t as BetterAuthError } from "../error-CMXuwPsa.mjs";
4
+ import { a as refreshAccessToken, c as getOAuth2Tokens, n as validateAuthorizationCode, o as createAuthorizationURL, s as generateCodeChallenge } from "../oauth2-7k48hhcV.mjs";
5
5
  import * as z from "zod";
6
6
  import { base64 } from "@better-auth/utils/base64";
7
7
  import { betterFetch } from "@better-fetch/fetch";
@@ -836,9 +836,16 @@ const google = (options) => {
836
836
  async verifyIdToken(token, nonce) {
837
837
  if (options.disableIdTokenSignIn) return false;
838
838
  if (options.verifyIdToken) return options.verifyIdToken(token, nonce);
839
- const { data: tokenInfo } = await betterFetch(`https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=${token}`);
840
- if (!tokenInfo) return false;
841
- return tokenInfo.aud === options.clientId && (tokenInfo.iss === "https://accounts.google.com" || tokenInfo.iss === "accounts.google.com");
839
+ const { kid, alg: jwtAlg } = decodeProtectedHeader(token);
840
+ if (!kid || !jwtAlg) return false;
841
+ const { payload: jwtClaims } = await jwtVerify(token, await getGooglePublicKey(kid), {
842
+ algorithms: [jwtAlg],
843
+ issuer: ["https://accounts.google.com", "accounts.google.com"],
844
+ audience: options.clientId,
845
+ maxTokenAge: "1h"
846
+ });
847
+ if (nonce && jwtClaims.nonce !== nonce) return false;
848
+ return true;
842
849
  },
843
850
  async getUserInfo(token) {
844
851
  if (options.getUserInfo) return options.getUserInfo(token);
@@ -860,6 +867,13 @@ const google = (options) => {
860
867
  options
861
868
  };
862
869
  };
870
+ const getGooglePublicKey = async (kid) => {
871
+ const { data } = await betterFetch("https://www.googleapis.com/oauth2/v3/certs");
872
+ if (!data?.keys) throw new APIError("BAD_REQUEST", { message: "Keys not found" });
873
+ const jwk = data.keys.find((key) => key.kid === kid);
874
+ if (!jwk) throw new Error(`JWK with kid ${kid} not found`);
875
+ return await importJWK(jwk, jwk.alg);
876
+ };
863
877
 
864
878
  //#endregion
865
879
  //#region src/social-providers/huggingface.ts
@@ -2577,4 +2591,4 @@ const socialProviderList = Object.keys(socialProviders);
2577
2591
  const SocialProviderListEnum = z.enum(socialProviderList).or(z.string());
2578
2592
 
2579
2593
  //#endregion
2580
- export { SocialProviderListEnum, apple, atlassian, cognito, discord, dropbox, facebook, figma, getApplePublicKey, getCognitoPublicKey, github, gitlab, google, huggingface, kakao, kick, line, linear, linkedin, microsoft, naver, notion, paybin, paypal, polar, reddit, roblox, salesforce, slack, socialProviderList, socialProviders, spotify, tiktok, twitch, twitter, vercel, vk, zoom };
2594
+ export { SocialProviderListEnum, apple, atlassian, cognito, discord, dropbox, facebook, figma, getApplePublicKey, getCognitoPublicKey, getGooglePublicKey, github, gitlab, google, huggingface, kakao, kick, line, linear, linkedin, microsoft, naver, notion, paybin, paypal, polar, reddit, roblox, salesforce, slack, socialProviderList, socialProviders, spotify, tiktok, twitch, twitter, vercel, vk, zoom };
@@ -6,4 +6,13 @@ type InvalidKeyError<K$1 extends string> = `Invalid error code key: "${K$1}" - m
6
6
  type ValidateErrorCodes<T> = { [K in keyof T]: K extends string ? IsValidUpperSnakeCase<K> extends false ? InvalidKeyError<K> : T[K] : T[K] };
7
7
  declare function defineErrorCodes<const T extends Record<string, string>>(codes: ValidateErrorCodes<T>): T;
8
8
  //#endregion
9
- export { defineErrorCodes };
9
+ //#region src/utils/id.d.ts
10
+ declare const generateId: (size?: number) => string;
11
+ //#endregion
12
+ //#region src/utils/json.d.ts
13
+ declare function safeJSONParse<T>(data: unknown): T | null;
14
+ //#endregion
15
+ //#region src/utils/string.d.ts
16
+ declare function capitalizeFirstLetter(str: string): string;
17
+ //#endregion
18
+ export { capitalizeFirstLetter, defineErrorCodes, generateId, safeJSONParse };
@@ -1,3 +1,4 @@
1
- import { t as defineErrorCodes } from "../utils-C5EN75oV.mjs";
1
+ import "../env-D6s-lvJz.mjs";
2
+ import { i as defineErrorCodes, n as safeJSONParse, r as generateId, t as capitalizeFirstLetter } from "../utils-BqQC77zO.mjs";
2
3
 
3
- export { defineErrorCodes };
4
+ export { capitalizeFirstLetter, defineErrorCodes, generateId, safeJSONParse };
@@ -0,0 +1,43 @@
1
+ import { i as logger } from "./env-D6s-lvJz.mjs";
2
+ import { createRandomStringGenerator } from "@better-auth/utils/random";
3
+
4
+ //#region src/utils/error-codes.ts
5
+ function defineErrorCodes(codes) {
6
+ return codes;
7
+ }
8
+
9
+ //#endregion
10
+ //#region src/utils/id.ts
11
+ const generateId = (size) => {
12
+ return createRandomStringGenerator("a-z", "A-Z", "0-9")(size || 32);
13
+ };
14
+
15
+ //#endregion
16
+ //#region src/utils/json.ts
17
+ function safeJSONParse(data) {
18
+ function reviver(_, value) {
19
+ if (typeof value === "string") {
20
+ if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/.test(value)) {
21
+ const date = new Date(value);
22
+ if (!isNaN(date.getTime())) return date;
23
+ }
24
+ }
25
+ return value;
26
+ }
27
+ try {
28
+ if (typeof data !== "string") return data;
29
+ return JSON.parse(data, reviver);
30
+ } catch (e) {
31
+ logger.error("Error parsing JSON", { error: e });
32
+ return null;
33
+ }
34
+ }
35
+
36
+ //#endregion
37
+ //#region src/utils/string.ts
38
+ function capitalizeFirstLetter(str) {
39
+ return str.charAt(0).toUpperCase() + str.slice(1);
40
+ }
41
+
42
+ //#endregion
43
+ export { defineErrorCodes as i, safeJSONParse as n, generateId as r, capitalizeFirstLetter as t };
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@better-auth/core",
3
- "version": "1.4.6-beta.2",
3
+ "version": "1.4.6-beta.4",
4
4
  "description": "The most comprehensive authentication framework for TypeScript.",
5
5
  "type": "module",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/better-auth/better-auth",
8
+ "url": "git+https://github.com/better-auth/better-auth.git",
9
9
  "directory": "packages/core"
10
10
  },
11
11
  "main": "./dist/index.mjs",
12
12
  "module": "./dist/index.mjs",
13
+ "types": "./dist/index.d.mts",
13
14
  "exports": {
14
15
  ".": {
15
16
  "dev-source": "./src/index.ts",
@@ -107,11 +108,11 @@
107
108
  "devDependencies": {
108
109
  "@better-auth/utils": "0.3.0",
109
110
  "@better-fetch/fetch": "1.1.18",
110
- "better-call": "1.1.4",
111
+ "better-call": "1.1.5",
111
112
  "jose": "^6.1.0",
112
113
  "kysely": "^0.28.5",
113
114
  "nanostores": "^1.0.1",
114
- "tsdown": "^0.16.0"
115
+ "tsdown": "^0.17.0"
115
116
  },
116
117
  "dependencies": {
117
118
  "@standard-schema/spec": "^1.0.0",
@@ -120,7 +121,7 @@
120
121
  "peerDependencies": {
121
122
  "@better-auth/utils": "0.3.0",
122
123
  "@better-fetch/fetch": "1.1.18",
123
- "better-call": "1.1.4",
124
+ "better-call": "1.1.5",
124
125
  "jose": "^6.1.0",
125
126
  "kysely": "^0.28.5",
126
127
  "nanostores": "^1.0.1"
@@ -130,6 +131,7 @@
130
131
  "dev": "tsdown --watch",
131
132
  "lint:package": "publint run --strict",
132
133
  "typecheck": "tsc --project tsconfig.json",
133
- "test": "vitest"
134
+ "test": "vitest",
135
+ "coverage": "vitest run --coverage"
134
136
  }
135
137
  }
@@ -0,0 +1,12 @@
1
+ import { expect, test, vi } from "vitest";
2
+
3
+ vi.mock(import("node:async_hooks"), () => {
4
+ throw new Error("Doesn't work with convex");
5
+ });
6
+
7
+ test("should work with convex", async () => {
8
+ vi.stubEnv("CONVEX_CLOUD_URL", "https://convex.com");
9
+ vi.stubEnv("CONVEX_SITE_URL", "http://test.com");
10
+ const { getAsyncLocalStorage } = await import(".");
11
+ await expect(getAsyncLocalStorage()).to.resolves.toBeDefined();
12
+ });
@@ -1,35 +1,70 @@
1
- /**
2
- * AsyncLocalStorage will be import directly in 1.5.x
3
- */
4
1
  import type { AsyncLocalStorage } from "node:async_hooks";
2
+ import { env } from "../env";
5
3
 
6
- // We only export the type here to avoid issues in environments where AsyncLocalStorage is not available.
7
4
  export type { AsyncLocalStorage };
8
5
 
9
- const AsyncLocalStoragePromise: Promise<typeof AsyncLocalStorage> = import(
10
- /* @vite-ignore */
11
- /* webpackIgnore: true */
12
- "node:async_hooks"
13
- )
14
- .then((mod) => mod.AsyncLocalStorage)
15
- .catch((err) => {
16
- if ("AsyncLocalStorage" in globalThis) {
17
- return (globalThis as any).AsyncLocalStorage;
6
+ /**
7
+ * Due to the lack of AsyncLocalStorage in some environments (like Convex),
8
+ *
9
+ * We assume serverless functions are short-lived and single-threaded, so we can use a simple polyfill.
10
+ */
11
+ class AsyncLocalStoragePolyfill<T> {
12
+ #current: T | undefined = undefined;
13
+
14
+ run(store: T, fn: () => unknown): unknown {
15
+ const prev = this.#current;
16
+ this.#current = store;
17
+ const result = fn();
18
+ if (result instanceof Promise) {
19
+ return result.finally(() => {
20
+ this.#current = prev;
21
+ });
18
22
  }
19
- console.warn(
20
- "[better-auth] Warning: AsyncLocalStorage is not available in this environment. Some features may not work as expected.",
21
- );
22
- console.warn(
23
- "[better-auth] Please read more about this warning at https://better-auth.com/docs/installation#mount-handler",
24
- );
25
- console.warn(
26
- "[better-auth] If you are using Cloudflare Workers, please see: https://developers.cloudflare.com/workers/configuration/compatibility-flags/#nodejs-compatibility-flag",
27
- );
28
- throw err;
29
- });
23
+ this.#current = prev;
24
+ return result;
25
+ }
26
+
27
+ getStore(): T | undefined {
28
+ return this.#current;
29
+ }
30
+ }
31
+
32
+ const AsyncLocalStoragePromise: Promise<typeof AsyncLocalStorage | null> =
33
+ import(
34
+ /* @vite-ignore */
35
+ /* webpackIgnore: true */
36
+ "node:async_hooks"
37
+ )
38
+ .then((mod) => mod.AsyncLocalStorage)
39
+ .catch((err) => {
40
+ if ("AsyncLocalStorage" in globalThis) {
41
+ return (globalThis as any).AsyncLocalStorage;
42
+ }
43
+ if (typeof window !== "undefined") {
44
+ return null;
45
+ }
46
+ if (env["CONVEX_CLOUD_URL"] || env["CONVEX_SITE_URL"]) {
47
+ return AsyncLocalStoragePolyfill;
48
+ }
49
+ console.warn(
50
+ "[better-auth] Warning: AsyncLocalStorage is not available in this environment. Some features may not work as expected.",
51
+ );
52
+ console.warn(
53
+ "[better-auth] Please read more about this warning at https://better-auth.com/docs/installation#mount-handler",
54
+ );
55
+ console.warn(
56
+ "[better-auth] If you are using Cloudflare Workers, please see: https://developers.cloudflare.com/workers/configuration/compatibility-flags/#nodejs-compatibility-flag",
57
+ );
58
+ throw err;
59
+ });
30
60
 
31
61
  export async function getAsyncLocalStorage(): Promise<
32
62
  typeof AsyncLocalStorage
33
63
  > {
34
- return AsyncLocalStoragePromise;
64
+ const mod = await AsyncLocalStoragePromise;
65
+ if (mod === null) {
66
+ throw new Error("getAsyncLocalStorage is only available in server code");
67
+ } else {
68
+ return mod;
69
+ }
35
70
  }