@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.
- package/dist/api/index.d.mts +0 -3
- package/dist/context/endpoint-context.d.mts +0 -1
- package/dist/context/global.mjs +1 -1
- package/dist/db/adapter/factory.d.mts +0 -2
- package/dist/db/adapter/factory.mjs +53 -20
- package/dist/db/adapter/factory.mjs.map +1 -1
- package/dist/db/adapter/get-field-attributes.d.mts +0 -3
- package/dist/db/adapter/get-id-field.d.mts +0 -3
- package/dist/db/adapter/get-id-field.mjs +2 -2
- package/dist/db/adapter/get-id-field.mjs.map +1 -1
- package/dist/db/adapter/index.d.mts +0 -2
- package/dist/db/adapter/types.d.mts +0 -2
- package/dist/db/get-tables.d.mts +0 -2
- package/dist/db/schema/account.d.mts +0 -1
- package/dist/db/schema/rate-limit.d.mts +0 -1
- package/dist/db/schema/session.d.mts +0 -1
- package/dist/db/schema/user.d.mts +0 -1
- package/dist/db/schema/verification.d.mts +0 -1
- package/dist/db/type.d.mts +0 -1
- package/dist/instrumentation/attributes.d.mts +12 -0
- package/dist/instrumentation/attributes.mjs +13 -0
- package/dist/instrumentation/attributes.mjs.map +1 -0
- package/dist/instrumentation/index.d.mts +3 -0
- package/dist/instrumentation/index.mjs +4 -0
- package/dist/instrumentation/tracer.d.mts +14 -0
- package/dist/instrumentation/tracer.mjs +37 -0
- package/dist/instrumentation/tracer.mjs.map +1 -0
- package/dist/oauth2/client-credentials-token.d.mts +0 -1
- package/dist/oauth2/create-authorization-url.d.mts +0 -3
- package/dist/oauth2/oauth-provider.d.mts +0 -2
- package/dist/oauth2/refresh-access-token.d.mts +0 -1
- package/dist/oauth2/validate-authorization-code.d.mts +0 -2
- package/dist/social-providers/apple.d.mts +0 -2
- package/dist/social-providers/apple.mjs +1 -1
- package/dist/social-providers/apple.mjs.map +1 -1
- package/dist/social-providers/atlassian.d.mts +0 -2
- package/dist/social-providers/atlassian.mjs +3 -2
- package/dist/social-providers/atlassian.mjs.map +1 -1
- package/dist/social-providers/cognito.d.mts +0 -2
- package/dist/social-providers/discord.d.mts +0 -2
- package/dist/social-providers/discord.mjs +3 -2
- package/dist/social-providers/discord.mjs.map +1 -1
- package/dist/social-providers/dropbox.d.mts +0 -2
- package/dist/social-providers/facebook.d.mts +0 -2
- package/dist/social-providers/figma.d.mts +0 -2
- package/dist/social-providers/figma.mjs +3 -2
- package/dist/social-providers/figma.mjs.map +1 -1
- package/dist/social-providers/github.d.mts +0 -2
- package/dist/social-providers/github.mjs +1 -1
- package/dist/social-providers/github.mjs.map +1 -1
- package/dist/social-providers/gitlab.d.mts +0 -2
- package/dist/social-providers/google.d.mts +0 -2
- package/dist/social-providers/huggingface.d.mts +0 -2
- package/dist/social-providers/huggingface.mjs +3 -2
- package/dist/social-providers/huggingface.mjs.map +1 -1
- package/dist/social-providers/index.d.mts +61 -3
- package/dist/social-providers/index.mjs +4 -2
- package/dist/social-providers/index.mjs.map +1 -1
- package/dist/social-providers/kakao.d.mts +0 -2
- package/dist/social-providers/kakao.mjs +3 -2
- package/dist/social-providers/kakao.mjs.map +1 -1
- package/dist/social-providers/kick.d.mts +0 -2
- package/dist/social-providers/line.d.mts +0 -2
- package/dist/social-providers/linear.d.mts +0 -2
- package/dist/social-providers/linkedin.d.mts +0 -2
- package/dist/social-providers/microsoft-entra-id.d.mts +0 -2
- package/dist/social-providers/naver.d.mts +0 -2
- package/dist/social-providers/naver.mjs +3 -2
- package/dist/social-providers/naver.mjs.map +1 -1
- package/dist/social-providers/notion.d.mts +0 -2
- package/dist/social-providers/paybin.d.mts +0 -2
- package/dist/social-providers/paypal.d.mts +0 -2
- package/dist/social-providers/polar.d.mts +0 -2
- package/dist/social-providers/polar.mjs +3 -2
- package/dist/social-providers/polar.mjs.map +1 -1
- package/dist/social-providers/railway.d.mts +0 -2
- package/dist/social-providers/reddit.d.mts +0 -2
- package/dist/social-providers/roblox.d.mts +0 -2
- package/dist/social-providers/roblox.mjs +3 -2
- package/dist/social-providers/roblox.mjs.map +1 -1
- package/dist/social-providers/salesforce.d.mts +0 -2
- package/dist/social-providers/slack.d.mts +0 -2
- package/dist/social-providers/slack.mjs +3 -2
- package/dist/social-providers/slack.mjs.map +1 -1
- package/dist/social-providers/spotify.d.mts +0 -2
- package/dist/social-providers/spotify.mjs +3 -2
- package/dist/social-providers/spotify.mjs.map +1 -1
- package/dist/social-providers/tiktok.d.mts +0 -2
- package/dist/social-providers/tiktok.mjs +3 -2
- package/dist/social-providers/tiktok.mjs.map +1 -1
- package/dist/social-providers/twitch.d.mts +0 -2
- package/dist/social-providers/twitch.mjs +3 -2
- package/dist/social-providers/twitch.mjs.map +1 -1
- package/dist/social-providers/twitter.d.mts +0 -2
- package/dist/social-providers/twitter.mjs +3 -2
- package/dist/social-providers/twitter.mjs.map +1 -1
- package/dist/social-providers/vercel.d.mts +0 -2
- package/dist/social-providers/vk.d.mts +0 -2
- package/dist/social-providers/vk.mjs +3 -2
- package/dist/social-providers/vk.mjs.map +1 -1
- package/dist/social-providers/wechat.d.mts +114 -0
- package/dist/social-providers/wechat.mjs +84 -0
- package/dist/social-providers/wechat.mjs.map +1 -0
- package/dist/social-providers/zoom.d.mts +0 -2
- package/dist/types/context.d.mts +0 -2
- package/dist/types/init-options.d.mts +0 -1
- package/dist/types/plugin.d.mts +0 -1
- package/dist/utils/db.d.mts +0 -2
- package/dist/utils/fetch-metadata.d.mts +5 -0
- package/dist/utils/fetch-metadata.mjs +8 -0
- package/dist/utils/fetch-metadata.mjs.map +1 -0
- package/package.json +15 -2
- package/src/db/adapter/factory.ts +119 -47
- package/src/db/adapter/get-id-field.test.ts +222 -0
- package/src/db/adapter/get-id-field.ts +15 -4
- package/src/instrumentation/attributes.ts +22 -0
- package/src/instrumentation/index.ts +2 -0
- package/src/instrumentation/instrumentation.test.ts +139 -0
- package/src/instrumentation/tracer.ts +62 -0
- package/src/social-providers/apple.ts +1 -1
- package/src/social-providers/atlassian.ts +3 -2
- package/src/social-providers/discord.ts +3 -2
- package/src/social-providers/figma.ts +3 -2
- package/src/social-providers/github.ts +1 -1
- package/src/social-providers/huggingface.ts +3 -2
- package/src/social-providers/index.ts +3 -0
- package/src/social-providers/kakao.ts +3 -2
- package/src/social-providers/naver.ts +3 -2
- package/src/social-providers/polar.ts +3 -2
- package/src/social-providers/roblox.ts +3 -2
- package/src/social-providers/slack.ts +3 -2
- package/src/social-providers/spotify.ts +3 -2
- package/src/social-providers/tiktok.ts +3 -2
- package/src/social-providers/twitch.ts +3 -2
- package/src/social-providers/twitter.ts +3 -2
- package/src/social-providers/vk.ts +3 -2
- package/src/social-providers/wechat.ts +213 -0
- package/src/utils/fetch-metadata.test.ts +28 -0
- 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
|
+
});
|