@better-auth/core 1.5.4 → 1.5.6

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 (139) hide show
  1. package/dist/api/index.d.mts +0 -3
  2. package/dist/context/endpoint-context.d.mts +0 -1
  3. package/dist/context/global.mjs +1 -1
  4. package/dist/db/adapter/factory.d.mts +0 -2
  5. package/dist/db/adapter/factory.mjs +53 -20
  6. package/dist/db/adapter/factory.mjs.map +1 -1
  7. package/dist/db/adapter/get-field-attributes.d.mts +0 -3
  8. package/dist/db/adapter/get-id-field.d.mts +0 -3
  9. package/dist/db/adapter/get-id-field.mjs +2 -2
  10. package/dist/db/adapter/get-id-field.mjs.map +1 -1
  11. package/dist/db/adapter/index.d.mts +0 -2
  12. package/dist/db/adapter/types.d.mts +0 -2
  13. package/dist/db/get-tables.d.mts +0 -2
  14. package/dist/db/schema/account.d.mts +0 -1
  15. package/dist/db/schema/rate-limit.d.mts +0 -1
  16. package/dist/db/schema/session.d.mts +0 -1
  17. package/dist/db/schema/user.d.mts +0 -1
  18. package/dist/db/schema/verification.d.mts +0 -1
  19. package/dist/db/type.d.mts +0 -1
  20. package/dist/instrumentation/attributes.d.mts +12 -0
  21. package/dist/instrumentation/attributes.mjs +13 -0
  22. package/dist/instrumentation/attributes.mjs.map +1 -0
  23. package/dist/instrumentation/index.d.mts +3 -0
  24. package/dist/instrumentation/index.mjs +4 -0
  25. package/dist/instrumentation/tracer.d.mts +14 -0
  26. package/dist/instrumentation/tracer.mjs +37 -0
  27. package/dist/instrumentation/tracer.mjs.map +1 -0
  28. package/dist/oauth2/client-credentials-token.d.mts +0 -1
  29. package/dist/oauth2/create-authorization-url.d.mts +0 -3
  30. package/dist/oauth2/oauth-provider.d.mts +0 -2
  31. package/dist/oauth2/refresh-access-token.d.mts +0 -1
  32. package/dist/oauth2/validate-authorization-code.d.mts +0 -2
  33. package/dist/social-providers/apple.d.mts +0 -2
  34. package/dist/social-providers/apple.mjs +1 -1
  35. package/dist/social-providers/apple.mjs.map +1 -1
  36. package/dist/social-providers/atlassian.d.mts +0 -2
  37. package/dist/social-providers/atlassian.mjs +3 -2
  38. package/dist/social-providers/atlassian.mjs.map +1 -1
  39. package/dist/social-providers/cognito.d.mts +0 -2
  40. package/dist/social-providers/discord.d.mts +0 -2
  41. package/dist/social-providers/discord.mjs +3 -2
  42. package/dist/social-providers/discord.mjs.map +1 -1
  43. package/dist/social-providers/dropbox.d.mts +0 -2
  44. package/dist/social-providers/facebook.d.mts +0 -2
  45. package/dist/social-providers/figma.d.mts +0 -2
  46. package/dist/social-providers/figma.mjs +3 -2
  47. package/dist/social-providers/figma.mjs.map +1 -1
  48. package/dist/social-providers/github.d.mts +0 -2
  49. package/dist/social-providers/github.mjs +1 -1
  50. package/dist/social-providers/github.mjs.map +1 -1
  51. package/dist/social-providers/gitlab.d.mts +0 -2
  52. package/dist/social-providers/google.d.mts +0 -2
  53. package/dist/social-providers/huggingface.d.mts +0 -2
  54. package/dist/social-providers/huggingface.mjs +3 -2
  55. package/dist/social-providers/huggingface.mjs.map +1 -1
  56. package/dist/social-providers/index.d.mts +61 -3
  57. package/dist/social-providers/index.mjs +4 -2
  58. package/dist/social-providers/index.mjs.map +1 -1
  59. package/dist/social-providers/kakao.d.mts +0 -2
  60. package/dist/social-providers/kakao.mjs +3 -2
  61. package/dist/social-providers/kakao.mjs.map +1 -1
  62. package/dist/social-providers/kick.d.mts +0 -2
  63. package/dist/social-providers/line.d.mts +0 -2
  64. package/dist/social-providers/linear.d.mts +0 -2
  65. package/dist/social-providers/linkedin.d.mts +0 -2
  66. package/dist/social-providers/microsoft-entra-id.d.mts +0 -2
  67. package/dist/social-providers/naver.d.mts +0 -2
  68. package/dist/social-providers/naver.mjs +3 -2
  69. package/dist/social-providers/naver.mjs.map +1 -1
  70. package/dist/social-providers/notion.d.mts +0 -2
  71. package/dist/social-providers/paybin.d.mts +0 -2
  72. package/dist/social-providers/paypal.d.mts +0 -2
  73. package/dist/social-providers/polar.d.mts +0 -2
  74. package/dist/social-providers/polar.mjs +3 -2
  75. package/dist/social-providers/polar.mjs.map +1 -1
  76. package/dist/social-providers/railway.d.mts +0 -2
  77. package/dist/social-providers/reddit.d.mts +0 -2
  78. package/dist/social-providers/roblox.d.mts +0 -2
  79. package/dist/social-providers/roblox.mjs +3 -2
  80. package/dist/social-providers/roblox.mjs.map +1 -1
  81. package/dist/social-providers/salesforce.d.mts +0 -2
  82. package/dist/social-providers/slack.d.mts +0 -2
  83. package/dist/social-providers/slack.mjs +3 -2
  84. package/dist/social-providers/slack.mjs.map +1 -1
  85. package/dist/social-providers/spotify.d.mts +0 -2
  86. package/dist/social-providers/spotify.mjs +3 -2
  87. package/dist/social-providers/spotify.mjs.map +1 -1
  88. package/dist/social-providers/tiktok.d.mts +0 -2
  89. package/dist/social-providers/tiktok.mjs +3 -2
  90. package/dist/social-providers/tiktok.mjs.map +1 -1
  91. package/dist/social-providers/twitch.d.mts +0 -2
  92. package/dist/social-providers/twitch.mjs +3 -2
  93. package/dist/social-providers/twitch.mjs.map +1 -1
  94. package/dist/social-providers/twitter.d.mts +0 -2
  95. package/dist/social-providers/twitter.mjs +3 -2
  96. package/dist/social-providers/twitter.mjs.map +1 -1
  97. package/dist/social-providers/vercel.d.mts +0 -2
  98. package/dist/social-providers/vk.d.mts +0 -2
  99. package/dist/social-providers/vk.mjs +3 -2
  100. package/dist/social-providers/vk.mjs.map +1 -1
  101. package/dist/social-providers/wechat.d.mts +114 -0
  102. package/dist/social-providers/wechat.mjs +84 -0
  103. package/dist/social-providers/wechat.mjs.map +1 -0
  104. package/dist/social-providers/zoom.d.mts +0 -2
  105. package/dist/types/context.d.mts +0 -2
  106. package/dist/types/init-options.d.mts +0 -1
  107. package/dist/types/plugin.d.mts +0 -1
  108. package/dist/utils/db.d.mts +0 -2
  109. package/dist/utils/fetch-metadata.d.mts +5 -0
  110. package/dist/utils/fetch-metadata.mjs +8 -0
  111. package/dist/utils/fetch-metadata.mjs.map +1 -0
  112. package/package.json +15 -2
  113. package/src/db/adapter/factory.ts +119 -47
  114. package/src/db/adapter/get-id-field.test.ts +222 -0
  115. package/src/db/adapter/get-id-field.ts +15 -4
  116. package/src/instrumentation/attributes.ts +22 -0
  117. package/src/instrumentation/index.ts +2 -0
  118. package/src/instrumentation/instrumentation.test.ts +139 -0
  119. package/src/instrumentation/tracer.ts +62 -0
  120. package/src/social-providers/apple.ts +1 -1
  121. package/src/social-providers/atlassian.ts +3 -2
  122. package/src/social-providers/discord.ts +3 -2
  123. package/src/social-providers/figma.ts +3 -2
  124. package/src/social-providers/github.ts +1 -1
  125. package/src/social-providers/huggingface.ts +3 -2
  126. package/src/social-providers/index.ts +3 -0
  127. package/src/social-providers/kakao.ts +3 -2
  128. package/src/social-providers/naver.ts +3 -2
  129. package/src/social-providers/polar.ts +3 -2
  130. package/src/social-providers/roblox.ts +3 -2
  131. package/src/social-providers/slack.ts +3 -2
  132. package/src/social-providers/spotify.ts +3 -2
  133. package/src/social-providers/tiktok.ts +3 -2
  134. package/src/social-providers/twitch.ts +3 -2
  135. package/src/social-providers/twitter.ts +3 -2
  136. package/src/social-providers/vk.ts +3 -2
  137. package/src/social-providers/wechat.ts +213 -0
  138. package/src/utils/fetch-metadata.test.ts +28 -0
  139. package/src/utils/fetch-metadata.ts +3 -0
@@ -0,0 +1,213 @@
1
+ import { betterFetch } from "@better-fetch/fetch";
2
+ import type { OAuth2Tokens, OAuthProvider, ProviderOptions } from "../oauth2";
3
+
4
+ /**
5
+ * WeChat user profile information
6
+ * @see https://developers.weixin.qq.com/doc/oplatform/en/Website_App/WeChat_Login/Wechat_Login.html
7
+ */
8
+ export interface WeChatProfile extends Record<string, any> {
9
+ /**
10
+ * User's unique OpenID
11
+ */
12
+ openid: string;
13
+ /**
14
+ * User's nickname
15
+ */
16
+ nickname: string;
17
+ /**
18
+ * User's avatar image URL
19
+ */
20
+ headimgurl: string;
21
+ /**
22
+ * User's privileges
23
+ */
24
+ privilege: string[];
25
+ /**
26
+ * User's UnionID (unique across the developer's various applications)
27
+ */
28
+ unionid?: string;
29
+ /** @note Email is currently unsupported by WeChat */
30
+ email?: string;
31
+ }
32
+
33
+ export interface WeChatOptions extends ProviderOptions<WeChatProfile> {
34
+ /**
35
+ * WeChat App ID
36
+ */
37
+ clientId: string;
38
+ /**
39
+ * WeChat App Secret
40
+ */
41
+ clientSecret: string;
42
+ /**
43
+ * Platform type for WeChat login
44
+ * - Currently only supports "WebsiteApp" for WeChat Website Application (网站应用)
45
+ * @default "WebsiteApp"
46
+ */
47
+ platformType?: "WebsiteApp";
48
+
49
+ /**
50
+ * UI language for the WeChat login page
51
+ * cn for Simplified Chinese, en for English
52
+ * @default "cn" if left undefined
53
+ */
54
+ lang?: "cn" | "en";
55
+ }
56
+
57
+ export const wechat = (options: WeChatOptions) => {
58
+ return {
59
+ id: "wechat",
60
+ name: "WeChat",
61
+ createAuthorizationURL({ state, scopes, redirectURI }) {
62
+ const _scopes = options.disableDefaultScope ? [] : ["snsapi_login"];
63
+ options.scope && _scopes.push(...options.scope);
64
+ scopes && _scopes.push(...scopes);
65
+
66
+ // WeChat uses non-standard OAuth2 parameters (appid instead of client_id)
67
+ // and requires a fragment (#wechat_redirect), so we construct the URL manually.
68
+ const url = new URL("https://open.weixin.qq.com/connect/qrconnect");
69
+ url.searchParams.set("scope", _scopes.join(","));
70
+ url.searchParams.set("response_type", "code");
71
+ url.searchParams.set("appid", options.clientId);
72
+ url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
73
+ url.searchParams.set("state", state);
74
+ url.searchParams.set("lang", options.lang || "cn");
75
+ url.hash = "wechat_redirect";
76
+
77
+ return url;
78
+ },
79
+
80
+ // WeChat uses non-standard token exchange (appid/secret instead of
81
+ // client_id/client_secret, GET instead of POST), so shared helpers
82
+ // like validateAuthorizationCode/getOAuth2Tokens cannot be used directly.
83
+ validateAuthorizationCode: async ({ code }) => {
84
+ const params = new URLSearchParams({
85
+ appid: options.clientId,
86
+ secret: options.clientSecret,
87
+ code: code,
88
+ grant_type: "authorization_code",
89
+ });
90
+
91
+ const { data: tokenData, error } = await betterFetch<{
92
+ access_token: string;
93
+ expires_in: number;
94
+ refresh_token: string;
95
+ openid: string;
96
+ scope: string;
97
+ unionid?: string;
98
+ errcode?: number;
99
+ errmsg?: string;
100
+ }>(
101
+ "https://api.weixin.qq.com/sns/oauth2/access_token?" +
102
+ params.toString(),
103
+ {
104
+ method: "GET",
105
+ },
106
+ );
107
+
108
+ if (error || !tokenData || tokenData.errcode) {
109
+ throw new Error(
110
+ `Failed to validate authorization code: ${tokenData?.errmsg || error?.message || "Unknown error"}`,
111
+ );
112
+ }
113
+
114
+ return {
115
+ tokenType: "Bearer" as const,
116
+ accessToken: tokenData.access_token,
117
+ refreshToken: tokenData.refresh_token,
118
+ accessTokenExpiresAt: new Date(
119
+ Date.now() + tokenData.expires_in * 1000,
120
+ ),
121
+ scopes: tokenData.scope.split(","),
122
+ // WeChat requires openid for the userinfo endpoint, which is
123
+ // returned alongside the access token.
124
+ openid: tokenData.openid,
125
+ unionid: tokenData.unionid,
126
+ };
127
+ },
128
+
129
+ refreshAccessToken: options.refreshAccessToken
130
+ ? options.refreshAccessToken
131
+ : async (refreshToken) => {
132
+ const params = new URLSearchParams({
133
+ appid: options.clientId,
134
+ grant_type: "refresh_token",
135
+ refresh_token: refreshToken,
136
+ });
137
+
138
+ const { data: tokenData, error } = await betterFetch<{
139
+ access_token: string;
140
+ expires_in: number;
141
+ refresh_token: string;
142
+ openid: string;
143
+ scope: string;
144
+ errcode?: number;
145
+ errmsg?: string;
146
+ }>(
147
+ "https://api.weixin.qq.com/sns/oauth2/refresh_token?" +
148
+ params.toString(),
149
+ {
150
+ method: "GET",
151
+ },
152
+ );
153
+
154
+ if (error || !tokenData || tokenData.errcode) {
155
+ throw new Error(
156
+ `Failed to refresh access token: ${tokenData?.errmsg || error?.message || "Unknown error"}`,
157
+ );
158
+ }
159
+
160
+ return {
161
+ tokenType: "Bearer" as const,
162
+ accessToken: tokenData.access_token,
163
+ refreshToken: tokenData.refresh_token,
164
+ accessTokenExpiresAt: new Date(
165
+ Date.now() + tokenData.expires_in * 1000,
166
+ ),
167
+ scopes: tokenData.scope.split(","),
168
+ };
169
+ },
170
+
171
+ async getUserInfo(token) {
172
+ if (options.getUserInfo) {
173
+ return options.getUserInfo(token);
174
+ }
175
+
176
+ const openid = (token as OAuth2Tokens & { openid?: string }).openid;
177
+
178
+ if (!openid) {
179
+ return null;
180
+ }
181
+
182
+ const params = new URLSearchParams({
183
+ access_token: token.accessToken || "",
184
+ openid: openid,
185
+ lang: "zh_CN",
186
+ });
187
+
188
+ const { data: profile, error } = await betterFetch<
189
+ WeChatProfile & { errcode?: number; errmsg?: string }
190
+ >("https://api.weixin.qq.com/sns/userinfo?" + params.toString(), {
191
+ method: "GET",
192
+ });
193
+
194
+ if (error || !profile || profile.errcode) {
195
+ return null;
196
+ }
197
+
198
+ const userMap = await options.mapProfileToUser?.(profile);
199
+ return {
200
+ user: {
201
+ id: profile.unionid || profile.openid || openid,
202
+ name: profile.nickname,
203
+ email: profile.email || null,
204
+ image: profile.headimgurl,
205
+ emailVerified: false,
206
+ ...userMap,
207
+ },
208
+ data: profile,
209
+ };
210
+ },
211
+ options,
212
+ } satisfies OAuthProvider<WeChatProfile, WeChatOptions>;
213
+ };
@@ -0,0 +1,28 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { isBrowserFetchRequest } from "./fetch-metadata";
3
+
4
+ describe("isBrowserFetchRequest", () => {
5
+ it("returns true for browser fetch requests", () => {
6
+ expect(
7
+ isBrowserFetchRequest(
8
+ new Headers({
9
+ "Sec-Fetch-Mode": "cors",
10
+ }),
11
+ ),
12
+ ).toBe(true);
13
+ });
14
+
15
+ it("returns false for navigation requests", () => {
16
+ expect(
17
+ isBrowserFetchRequest(
18
+ new Headers({
19
+ "Sec-Fetch-Mode": "navigate",
20
+ }),
21
+ ),
22
+ ).toBe(false);
23
+ });
24
+
25
+ it("returns false without fetch metadata", () => {
26
+ expect(isBrowserFetchRequest()).toBe(false);
27
+ });
28
+ });
@@ -0,0 +1,3 @@
1
+ export function isBrowserFetchRequest(headers?: Headers | null): boolean {
2
+ return headers?.get("sec-fetch-mode") === "cors";
3
+ }