@lobehub/lobehub 2.0.0-next.355 → 2.0.0-next.357
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/.env.desktop +0 -1
- package/.env.example +16 -20
- package/.env.example.development +1 -4
- package/.github/workflows/e2e.yml +10 -11
- package/CHANGELOG.md +60 -0
- package/Dockerfile +28 -4
- package/changelog/v1.json +18 -0
- package/docker-compose/local/docker-compose.yml +2 -2
- package/docker-compose/local/grafana/docker-compose.yml +2 -2
- package/docker-compose/local/logto/docker-compose.yml +2 -2
- package/docker-compose/local/zitadel/.env.example +2 -2
- package/docker-compose/local/zitadel/.env.zh-CN.example +2 -2
- package/docker-compose/production/grafana/docker-compose.yml +2 -2
- package/docker-compose/production/logto/.env.example +2 -2
- package/docker-compose/production/logto/.env.zh-CN.example +2 -2
- package/docker-compose/production/zitadel/.env.example +2 -2
- package/docker-compose/production/zitadel/.env.zh-CN.example +2 -2
- package/docs/development/basic/add-new-authentication-providers.mdx +144 -136
- package/docs/development/basic/add-new-authentication-providers.zh-CN.mdx +146 -136
- package/docs/self-hosting/advanced/auth/legacy.mdx +4 -0
- package/docs/self-hosting/advanced/auth/legacy.zh-CN.mdx +4 -0
- package/docs/self-hosting/advanced/auth/nextauth-to-betterauth.mdx +326 -0
- package/docs/self-hosting/advanced/auth/nextauth-to-betterauth.zh-CN.mdx +323 -0
- package/docs/self-hosting/advanced/auth.mdx +43 -16
- package/docs/self-hosting/advanced/auth.zh-CN.mdx +44 -16
- package/docs/self-hosting/advanced/redis/upstash.mdx +69 -0
- package/docs/self-hosting/advanced/redis/upstash.zh-CN.mdx +69 -0
- package/docs/self-hosting/advanced/redis.mdx +128 -0
- package/docs/self-hosting/advanced/redis.zh-CN.mdx +126 -0
- package/docs/self-hosting/environment-variables/auth.mdx +15 -1
- package/docs/self-hosting/environment-variables/auth.zh-CN.mdx +15 -1
- package/docs/self-hosting/environment-variables/basic.mdx +13 -0
- package/docs/self-hosting/environment-variables/basic.zh-CN.mdx +13 -0
- package/docs/self-hosting/environment-variables/redis.mdx +68 -0
- package/docs/self-hosting/environment-variables/redis.zh-CN.mdx +67 -0
- package/docs/self-hosting/migration/v2/breaking-changes.mdx +23 -23
- package/docs/self-hosting/migration/v2/breaking-changes.zh-CN.mdx +23 -23
- package/docs/self-hosting/server-database/docker-compose.mdx +4 -4
- package/docs/self-hosting/server-database/docker-compose.zh-CN.mdx +4 -4
- package/e2e/CLAUDE.md +5 -6
- package/e2e/docs/local-setup.md +9 -12
- package/e2e/scripts/setup.ts +9 -15
- package/e2e/src/support/webServer.ts +6 -5
- package/package.json +4 -6
- package/packages/database/src/schemas/nextauth.ts +7 -2
- package/packages/model-runtime/src/core/contextBuilders/anthropic.test.ts +370 -0
- package/packages/model-runtime/src/core/contextBuilders/anthropic.ts +18 -5
- package/packages/utils/src/server/__tests__/auth.test.ts +1 -63
- package/packages/utils/src/server/auth.ts +8 -24
- package/scripts/_shared/checkDeprecatedAuth.js +99 -0
- package/scripts/clerk-to-betterauth/index.ts +8 -3
- package/scripts/nextauth-to-betterauth/_internal/config.ts +41 -0
- package/scripts/nextauth-to-betterauth/_internal/db.ts +32 -0
- package/scripts/nextauth-to-betterauth/_internal/env.ts +6 -0
- package/scripts/nextauth-to-betterauth/index.ts +226 -0
- package/scripts/nextauth-to-betterauth/verify.ts +188 -0
- package/scripts/prebuild.mts +66 -13
- package/scripts/serverLauncher/startServer.js +5 -5
- package/src/app/(backend)/api/auth/[...all]/route.ts +5 -23
- package/src/app/(backend)/api/webhooks/casdoor/route.ts +5 -5
- package/src/app/(backend)/api/webhooks/logto/route.ts +8 -8
- package/src/app/(backend)/middleware/auth/index.test.ts +8 -1
- package/src/app/(backend)/middleware/auth/index.ts +6 -15
- package/src/app/(backend)/middleware/auth/utils.test.ts +0 -32
- package/src/app/(backend)/middleware/auth/utils.ts +3 -8
- package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +8 -1
- package/src/app/(backend)/webapi/create-image/comfyui/route.ts +0 -1
- package/src/app/(backend)/webapi/models/[provider]/route.test.ts +8 -1
- package/src/app/[variants]/(auth)/signin/SignInEmailStep.tsx +1 -1
- package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +4 -17
- package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobContentEditor.tsx +34 -21
- package/src/app/[variants]/(main)/settings/profile/features/SSOProvidersList/index.tsx +12 -19
- package/src/app/[variants]/(main)/settings/profile/index.tsx +8 -14
- package/src/components/{NextAuth/AuthIcons.tsx → AuthIcons.tsx} +8 -10
- package/src/envs/auth.ts +12 -51
- package/src/envs/email.ts +3 -0
- package/src/envs/redis.ts +12 -54
- package/src/features/ChatInput/ChatInputProvider.tsx +22 -2
- package/src/features/ChatInput/InputEditor/index.tsx +14 -3
- package/src/features/ChatInput/store/initialState.ts +2 -0
- package/src/features/EditorCanvas/DiffAllToolbar.tsx +4 -5
- package/src/features/EditorCanvas/DocumentIdMode.tsx +21 -1
- package/src/features/User/__tests__/PanelContent.test.tsx +0 -11
- package/src/features/User/__tests__/UserAvatar.test.tsx +1 -16
- package/src/layout/AuthProvider/index.tsx +1 -6
- package/src/layout/GlobalProvider/StoreInitialization.tsx +2 -4
- package/src/libs/better-auth/define-config.ts +2 -0
- package/src/libs/better-auth/plugins/email-whitelist.test.ts +120 -0
- package/src/libs/better-auth/plugins/email-whitelist.ts +62 -0
- package/src/libs/next/config/define-config.ts +13 -1
- package/src/libs/next/proxy/define-config.ts +2 -75
- package/src/libs/oidc-provider/provider.test.ts +0 -4
- package/src/libs/redis/index.ts +0 -1
- package/src/libs/redis/manager.test.ts +9 -45
- package/src/libs/redis/manager.ts +2 -16
- package/src/libs/redis/redis.test.ts +2 -4
- package/src/libs/redis/redis.ts +2 -4
- package/src/libs/redis/types.ts +2 -24
- package/src/libs/redis/utils.test.ts +0 -10
- package/src/libs/redis/utils.ts +0 -19
- package/src/libs/trpc/lambda/context.test.ts +0 -13
- package/src/libs/trpc/lambda/context.ts +21 -59
- package/src/libs/trpc/middleware/userAuth.ts +1 -7
- package/src/libs/trusted-client/getSessionUser.ts +15 -35
- package/src/server/globalConfig/index.ts +1 -3
- package/src/server/routers/lambda/__tests__/user.test.ts +0 -48
- package/src/server/routers/lambda/user.ts +1 -12
- package/src/server/services/email/impls/nodemailer/index.ts +2 -2
- package/src/server/services/webhookUser/index.ts +88 -0
- package/src/services/user/index.test.ts +0 -14
- package/src/services/user/index.ts +0 -4
- package/src/store/document/slices/document/action.ts +1 -0
- package/src/store/user/slices/auth/action.test.ts +22 -126
- package/src/store/user/slices/auth/action.ts +32 -65
- package/src/store/user/slices/auth/initialState.ts +0 -3
- package/src/store/user/slices/auth/selectors.ts +0 -3
- package/tests/setup.ts +10 -0
- package/scripts/_shared/checkDeprecatedClerkEnv.js +0 -42
- package/src/app/(backend)/api/auth/adapter/route.ts +0 -137
- package/src/app/[variants]/(auth)/next-auth/error/AuthErrorPage.tsx +0 -40
- package/src/app/[variants]/(auth)/next-auth/error/page.tsx +0 -11
- package/src/app/[variants]/(auth)/next-auth/signin/AuthSignInBox.tsx +0 -167
- package/src/app/[variants]/(auth)/next-auth/signin/page.tsx +0 -11
- package/src/app/[variants]/(auth)/reset-password/layout.tsx +0 -12
- package/src/app/[variants]/(auth)/signin/layout.tsx +0 -12
- package/src/app/[variants]/(auth)/verify-email/layout.tsx +0 -12
- package/src/envs/auth.test.ts +0 -47
- package/src/layout/AuthProvider/NextAuth/UserUpdater.tsx +0 -44
- package/src/layout/AuthProvider/NextAuth/index.tsx +0 -17
- package/src/libs/next-auth/adapter/index.ts +0 -177
- package/src/libs/next-auth/auth.config.ts +0 -64
- package/src/libs/next-auth/index.ts +0 -20
- package/src/libs/next-auth/sso-providers/auth0.ts +0 -24
- package/src/libs/next-auth/sso-providers/authelia.ts +0 -39
- package/src/libs/next-auth/sso-providers/authentik.ts +0 -25
- package/src/libs/next-auth/sso-providers/casdoor.ts +0 -50
- package/src/libs/next-auth/sso-providers/cloudflare-zero-trust.ts +0 -34
- package/src/libs/next-auth/sso-providers/cognito.ts +0 -8
- package/src/libs/next-auth/sso-providers/feishu.ts +0 -83
- package/src/libs/next-auth/sso-providers/generic-oidc.ts +0 -38
- package/src/libs/next-auth/sso-providers/github.ts +0 -23
- package/src/libs/next-auth/sso-providers/google.ts +0 -18
- package/src/libs/next-auth/sso-providers/index.ts +0 -35
- package/src/libs/next-auth/sso-providers/keycloak.ts +0 -22
- package/src/libs/next-auth/sso-providers/logto.ts +0 -48
- package/src/libs/next-auth/sso-providers/microsoft-entra-id-helper.ts +0 -29
- package/src/libs/next-auth/sso-providers/microsoft-entra-id.ts +0 -19
- package/src/libs/next-auth/sso-providers/okta.ts +0 -22
- package/src/libs/next-auth/sso-providers/sso.config.ts +0 -8
- package/src/libs/next-auth/sso-providers/wechat.ts +0 -36
- package/src/libs/next-auth/sso-providers/zitadel.ts +0 -21
- package/src/libs/redis/upstash.test.ts +0 -158
- package/src/libs/redis/upstash.ts +0 -136
- package/src/server/services/nextAuthUser/index.ts +0 -318
- package/src/server/services/nextAuthUser/utils.ts +0 -62
- package/src/types/next-auth.d.ts +0 -26
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
import { type LobeChatDatabase } from '@lobechat/database';
|
|
2
|
-
import { and, eq } from 'drizzle-orm';
|
|
3
|
-
import { type Adapter, type AdapterAccount } from 'next-auth/adapters';
|
|
4
|
-
import { NextResponse } from 'next/server';
|
|
5
|
-
|
|
6
|
-
import { UserModel } from '@/database/models/user';
|
|
7
|
-
import {
|
|
8
|
-
type UserItem,
|
|
9
|
-
nextauthAccounts,
|
|
10
|
-
nextauthAuthenticators,
|
|
11
|
-
nextauthSessions,
|
|
12
|
-
nextauthVerificationTokens,
|
|
13
|
-
users,
|
|
14
|
-
} from '@/database/schemas';
|
|
15
|
-
import { pino } from '@/libs/logger';
|
|
16
|
-
import { merge } from '@/utils/merge';
|
|
17
|
-
|
|
18
|
-
import {
|
|
19
|
-
mapAdapterUserToLobeUser,
|
|
20
|
-
mapAuthenticatorQueryResutlToAdapterAuthenticator,
|
|
21
|
-
mapLobeUserToAdapterUser,
|
|
22
|
-
partialMapAdapterUserToLobeUser,
|
|
23
|
-
} from './utils';
|
|
24
|
-
|
|
25
|
-
export class NextAuthUserService {
|
|
26
|
-
private db: LobeChatDatabase;
|
|
27
|
-
|
|
28
|
-
constructor(db: LobeChatDatabase) {
|
|
29
|
-
this.db = db;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
safeUpdateUser = async (
|
|
33
|
-
{ providerAccountId, provider }: { provider: string; providerAccountId: string },
|
|
34
|
-
data: Partial<UserItem>,
|
|
35
|
-
) => {
|
|
36
|
-
pino.info(`updating user "${JSON.stringify({ provider, providerAccountId })}" due to webhook`);
|
|
37
|
-
// 1. Find User by account
|
|
38
|
-
const user = await this.getUserByAccount({
|
|
39
|
-
provider,
|
|
40
|
-
providerAccountId,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// 2. If found, Update user data from provider
|
|
44
|
-
if (user?.id) {
|
|
45
|
-
const userModel = new UserModel(this.db, user.id);
|
|
46
|
-
|
|
47
|
-
// Perform update
|
|
48
|
-
await userModel.updateUser({
|
|
49
|
-
avatar: data?.avatar,
|
|
50
|
-
email: data?.email,
|
|
51
|
-
fullName: data?.fullName,
|
|
52
|
-
});
|
|
53
|
-
} else {
|
|
54
|
-
pino.warn(
|
|
55
|
-
`[${provider}]: Webhooks handler user "${JSON.stringify({ provider, providerAccountId })}" update for "${JSON.stringify(data)}", but no user was found by the providerAccountId.`,
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
return NextResponse.json({ message: 'user updated', success: true }, { status: 200 });
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
safeSignOutUser = async ({
|
|
62
|
-
providerAccountId,
|
|
63
|
-
provider,
|
|
64
|
-
}: {
|
|
65
|
-
provider: string;
|
|
66
|
-
providerAccountId: string;
|
|
67
|
-
}) => {
|
|
68
|
-
pino.info(`Signing out user "${JSON.stringify({ provider, providerAccountId })}"`);
|
|
69
|
-
const user = await this.getUserByAccount({
|
|
70
|
-
provider,
|
|
71
|
-
providerAccountId,
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// 2. If found, Update user data from provider
|
|
75
|
-
if (user?.id) {
|
|
76
|
-
// Perform update
|
|
77
|
-
await this.db.delete(nextauthSessions).where(eq(nextauthSessions.userId, user.id));
|
|
78
|
-
} else {
|
|
79
|
-
pino.warn(
|
|
80
|
-
`[${provider}]: Webhooks handler user "${JSON.stringify({ provider, providerAccountId })}" to signout", but no user was found by the providerAccountId.`,
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
return NextResponse.json({ message: 'user signed out', success: true }, { status: 200 });
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
createAuthenticator: NonNullable<Adapter['createAuthenticator']> = async (authenticator) => {
|
|
87
|
-
return await this.db
|
|
88
|
-
.insert(nextauthAuthenticators)
|
|
89
|
-
.values(authenticator)
|
|
90
|
-
.returning()
|
|
91
|
-
.then((res: any) => res[0] ?? undefined);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
createSession: NonNullable<Adapter['createSession']> = async (data) => {
|
|
95
|
-
return await this.db
|
|
96
|
-
.insert(nextauthSessions)
|
|
97
|
-
.values(data)
|
|
98
|
-
.returning()
|
|
99
|
-
.then((res: any) => res[0]);
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
createUser: NonNullable<Adapter['createUser']> = async (user) => {
|
|
103
|
-
const { id, name, email, emailVerified, image, providerAccountId } = user;
|
|
104
|
-
// return the user if it already exists
|
|
105
|
-
let existingUser =
|
|
106
|
-
email && typeof email === 'string' && email.trim()
|
|
107
|
-
? await UserModel.findByEmail(this.db, email)
|
|
108
|
-
: undefined;
|
|
109
|
-
// If the user is not found by email, try to find by providerAccountId
|
|
110
|
-
if (!existingUser && providerAccountId) {
|
|
111
|
-
existingUser = await UserModel.findById(this.db, providerAccountId);
|
|
112
|
-
}
|
|
113
|
-
if (existingUser) {
|
|
114
|
-
const adapterUser = mapLobeUserToAdapterUser(existingUser);
|
|
115
|
-
return adapterUser;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// create a new user if it does not exist
|
|
119
|
-
// Use id from provider if it exists, otherwise use id assigned by next-auth
|
|
120
|
-
// ref: https://github.com/lobehub/lobe-chat/pull/2935
|
|
121
|
-
const uid = providerAccountId ?? id;
|
|
122
|
-
await UserModel.createUser(
|
|
123
|
-
this.db,
|
|
124
|
-
mapAdapterUserToLobeUser({
|
|
125
|
-
email,
|
|
126
|
-
emailVerified,
|
|
127
|
-
// Use providerAccountId as userid to identify if the user exists in a SSO provider
|
|
128
|
-
id: uid,
|
|
129
|
-
image,
|
|
130
|
-
name,
|
|
131
|
-
}),
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
return { ...user, id: uid };
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
createVerificationToken: NonNullable<Adapter['createVerificationToken']> = async (data) => {
|
|
138
|
-
return await this.db
|
|
139
|
-
.insert(nextauthVerificationTokens)
|
|
140
|
-
.values(data)
|
|
141
|
-
.returning()
|
|
142
|
-
.then((res: any) => res[0]);
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
deleteSession: NonNullable<Adapter['deleteSession']> = async (sessionToken) => {
|
|
146
|
-
await this.db.delete(nextauthSessions).where(eq(nextauthSessions.sessionToken, sessionToken));
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
deleteUser: NonNullable<Adapter['deleteUser']> = async (id) => {
|
|
150
|
-
const user = await UserModel.findById(this.db, id);
|
|
151
|
-
if (!user) throw new Error('NextAuth: Delete User not found');
|
|
152
|
-
await UserModel.deleteUser(this.db, id);
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
getAccount: NonNullable<Adapter['getAccount']> = async (providerAccountId, provider) => {
|
|
156
|
-
return (await this.db
|
|
157
|
-
.select()
|
|
158
|
-
.from(nextauthAccounts)
|
|
159
|
-
.where(
|
|
160
|
-
and(
|
|
161
|
-
eq(nextauthAccounts.provider, provider),
|
|
162
|
-
eq(nextauthAccounts.providerAccountId, providerAccountId),
|
|
163
|
-
),
|
|
164
|
-
)
|
|
165
|
-
.then((res: any) => res[0] ?? null)) as Promise<AdapterAccount | null>;
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
getAuthenticator: NonNullable<Adapter['getAuthenticator']> = async (credentialID) => {
|
|
169
|
-
const result = await this.db
|
|
170
|
-
.select()
|
|
171
|
-
.from(nextauthAuthenticators)
|
|
172
|
-
.where(eq(nextauthAuthenticators.credentialID, credentialID))
|
|
173
|
-
.then((res) => res[0] ?? null);
|
|
174
|
-
if (!result) throw new Error('NextAuthUserService: Failed to get authenticator');
|
|
175
|
-
return mapAuthenticatorQueryResutlToAdapterAuthenticator(result);
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
getSessionAndUser: NonNullable<Adapter['getSessionAndUser']> = async (sessionToken) => {
|
|
179
|
-
const result = await this.db
|
|
180
|
-
.select({
|
|
181
|
-
session: nextauthSessions,
|
|
182
|
-
user: users,
|
|
183
|
-
})
|
|
184
|
-
.from(nextauthSessions)
|
|
185
|
-
.where(eq(nextauthSessions.sessionToken, sessionToken))
|
|
186
|
-
.innerJoin(users, eq(users.id, nextauthSessions.userId))
|
|
187
|
-
.then((res: any) => (res.length > 0 ? res[0] : null));
|
|
188
|
-
|
|
189
|
-
if (!result) return null;
|
|
190
|
-
const adapterUser = mapLobeUserToAdapterUser(result.user);
|
|
191
|
-
if (!adapterUser) return null;
|
|
192
|
-
return {
|
|
193
|
-
session: result.session,
|
|
194
|
-
user: adapterUser,
|
|
195
|
-
};
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
getUser: NonNullable<Adapter['getUser']> = async (id) => {
|
|
199
|
-
const lobeUser = await UserModel.findById(this.db, id);
|
|
200
|
-
if (!lobeUser) return null;
|
|
201
|
-
return mapLobeUserToAdapterUser(lobeUser);
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
getUserByAccount: NonNullable<Adapter['getUserByAccount']> = async (account) => {
|
|
205
|
-
const result = await this.db
|
|
206
|
-
.select({
|
|
207
|
-
account: nextauthAccounts,
|
|
208
|
-
users,
|
|
209
|
-
})
|
|
210
|
-
.from(nextauthAccounts)
|
|
211
|
-
.innerJoin(users, eq(nextauthAccounts.userId, users.id))
|
|
212
|
-
.where(
|
|
213
|
-
and(
|
|
214
|
-
eq(nextauthAccounts.provider, account.provider),
|
|
215
|
-
eq(nextauthAccounts.providerAccountId, account.providerAccountId),
|
|
216
|
-
),
|
|
217
|
-
)
|
|
218
|
-
.then((res: any) => res[0]);
|
|
219
|
-
|
|
220
|
-
return result?.users ? mapLobeUserToAdapterUser(result.users) : null;
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
getUserByEmail: NonNullable<Adapter['getUserByEmail']> = async (email) => {
|
|
224
|
-
const lobeUser =
|
|
225
|
-
email && typeof email === 'string' && email.trim()
|
|
226
|
-
? await UserModel.findByEmail(this.db, email)
|
|
227
|
-
: undefined;
|
|
228
|
-
return lobeUser ? mapLobeUserToAdapterUser(lobeUser) : null;
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
linkAccount: NonNullable<Adapter['linkAccount']> = async (data) => {
|
|
232
|
-
const [account] = await this.db
|
|
233
|
-
.insert(nextauthAccounts)
|
|
234
|
-
.values(data as any)
|
|
235
|
-
.returning();
|
|
236
|
-
if (!account) throw new Error('NextAuthAccountModel: Failed to create account');
|
|
237
|
-
// TODO Update type annotation
|
|
238
|
-
return account as any;
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
listAuthenticatorsByUserId: NonNullable<Adapter['listAuthenticatorsByUserId']> = async (
|
|
242
|
-
userId,
|
|
243
|
-
) => {
|
|
244
|
-
const result = await this.db
|
|
245
|
-
.select()
|
|
246
|
-
.from(nextauthAuthenticators)
|
|
247
|
-
.where(eq(nextauthAuthenticators.userId, userId))
|
|
248
|
-
.then((res: any) => res);
|
|
249
|
-
if (result.length === 0)
|
|
250
|
-
throw new Error('NextAuthUserService: Failed to get authenticator list');
|
|
251
|
-
return result.map((r: any) => mapAuthenticatorQueryResutlToAdapterAuthenticator(r));
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
unlinkAccount: NonNullable<Adapter['unlinkAccount']> = async (account) => {
|
|
255
|
-
await this.db
|
|
256
|
-
.delete(nextauthAccounts)
|
|
257
|
-
.where(
|
|
258
|
-
and(
|
|
259
|
-
eq(nextauthAccounts.provider, account.provider),
|
|
260
|
-
eq(nextauthAccounts.providerAccountId, account.providerAccountId),
|
|
261
|
-
),
|
|
262
|
-
);
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
updateAuthenticatorCounter: NonNullable<Adapter['updateAuthenticatorCounter']> = async (
|
|
266
|
-
credentialID,
|
|
267
|
-
counter,
|
|
268
|
-
) => {
|
|
269
|
-
const result = await this.db
|
|
270
|
-
.update(nextauthAuthenticators)
|
|
271
|
-
.set({ counter })
|
|
272
|
-
.where(eq(nextauthAuthenticators.credentialID, credentialID))
|
|
273
|
-
.returning()
|
|
274
|
-
.then((res: any) => res[0]);
|
|
275
|
-
if (!result) throw new Error('NextAuthUserService: Failed to update authenticator counter');
|
|
276
|
-
return mapAuthenticatorQueryResutlToAdapterAuthenticator(result);
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
updateSession: NonNullable<Adapter['updateSession']> = async (data) => {
|
|
280
|
-
const res = await this.db
|
|
281
|
-
.update(nextauthSessions)
|
|
282
|
-
.set(data)
|
|
283
|
-
.where(eq(nextauthSessions.sessionToken, data.sessionToken))
|
|
284
|
-
.returning();
|
|
285
|
-
return res[0];
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
updateUser: NonNullable<Adapter['updateUser']> = async (user) => {
|
|
289
|
-
const lobeUser = await UserModel.findById(this.db, user?.id);
|
|
290
|
-
if (!lobeUser) throw new Error('NextAuth: User not found');
|
|
291
|
-
const userModel = new UserModel(this.db, user.id);
|
|
292
|
-
|
|
293
|
-
const updatedUser = await userModel.updateUser({
|
|
294
|
-
...partialMapAdapterUserToLobeUser(user),
|
|
295
|
-
});
|
|
296
|
-
if (!updatedUser) throw new Error('NextAuth: Failed to update user');
|
|
297
|
-
|
|
298
|
-
// merge new user data with old user data
|
|
299
|
-
const newAdapterUser = mapLobeUserToAdapterUser(lobeUser);
|
|
300
|
-
if (!newAdapterUser) {
|
|
301
|
-
throw new Error('NextAuth: Failed to map user data to adapter user');
|
|
302
|
-
}
|
|
303
|
-
return merge(newAdapterUser, user);
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
useVerificationToken: NonNullable<Adapter['useVerificationToken']> = async (identifier_token) => {
|
|
307
|
-
return await this.db
|
|
308
|
-
.delete(nextauthVerificationTokens)
|
|
309
|
-
.where(
|
|
310
|
-
and(
|
|
311
|
-
eq(nextauthVerificationTokens.identifier, identifier_token.identifier),
|
|
312
|
-
eq(nextauthVerificationTokens.token, identifier_token.token),
|
|
313
|
-
),
|
|
314
|
-
)
|
|
315
|
-
.returning()
|
|
316
|
-
.then((res: any) => (res.length > 0 ? res[0] : null));
|
|
317
|
-
};
|
|
318
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { type AdapterAuthenticator, type AdapterUser } from 'next-auth/adapters';
|
|
2
|
-
|
|
3
|
-
import { type NewUser } from '@/database/schemas';
|
|
4
|
-
|
|
5
|
-
export const mapAdapterUserToLobeUser = (adapterUser: AdapterUser): NewUser => {
|
|
6
|
-
const { id, email, name, image, emailVerified } = adapterUser;
|
|
7
|
-
return {
|
|
8
|
-
avatar: image,
|
|
9
|
-
email,
|
|
10
|
-
emailVerifiedAt: emailVerified ? new Date(emailVerified) : undefined,
|
|
11
|
-
fullName: name,
|
|
12
|
-
id,
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export const partialMapAdapterUserToLobeUser = ({
|
|
17
|
-
id,
|
|
18
|
-
name,
|
|
19
|
-
email,
|
|
20
|
-
image,
|
|
21
|
-
emailVerified,
|
|
22
|
-
}: Partial<AdapterUser>): Partial<NewUser> => {
|
|
23
|
-
return {
|
|
24
|
-
avatar: image,
|
|
25
|
-
email,
|
|
26
|
-
emailVerifiedAt: emailVerified ? new Date(emailVerified) : undefined,
|
|
27
|
-
fullName: name,
|
|
28
|
-
id,
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const mapLobeUserToAdapterUser = (lobeUser: NewUser): AdapterUser => {
|
|
33
|
-
const { id, fullName, email, avatar, emailVerifiedAt } = lobeUser;
|
|
34
|
-
return {
|
|
35
|
-
// In LobeUser, email is nullable
|
|
36
|
-
email: email ?? '',
|
|
37
|
-
emailVerified: emailVerifiedAt ? new Date(emailVerifiedAt) : null,
|
|
38
|
-
id,
|
|
39
|
-
image: avatar,
|
|
40
|
-
name: fullName,
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
type AuthenticatorQueryResult = {
|
|
45
|
-
counter: number;
|
|
46
|
-
credentialBackedUp: boolean;
|
|
47
|
-
credentialDeviceType: string;
|
|
48
|
-
credentialID: string;
|
|
49
|
-
credentialPublicKey: string;
|
|
50
|
-
providerAccountId: string;
|
|
51
|
-
transports: string | null;
|
|
52
|
-
userId: string;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export const mapAuthenticatorQueryResutlToAdapterAuthenticator = (
|
|
56
|
-
authenticator: AuthenticatorQueryResult,
|
|
57
|
-
): AdapterAuthenticator => {
|
|
58
|
-
return {
|
|
59
|
-
...authenticator,
|
|
60
|
-
transports: authenticator?.transports ?? undefined,
|
|
61
|
-
};
|
|
62
|
-
};
|
package/src/types/next-auth.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { type DefaultSession } from 'next-auth';
|
|
2
|
-
|
|
3
|
-
declare module 'next-auth' {
|
|
4
|
-
/**
|
|
5
|
-
* Returned by `useSession`, `auth`, contains information about the active session.
|
|
6
|
-
*/
|
|
7
|
-
interface Session {
|
|
8
|
-
user: {
|
|
9
|
-
firstName?: string;
|
|
10
|
-
} & DefaultSession['user'];
|
|
11
|
-
}
|
|
12
|
-
interface User {
|
|
13
|
-
providerAccountId?: string;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* More types can be extends here
|
|
17
|
-
* ref: https://authjs.dev/getting-started/typescript
|
|
18
|
-
*/
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
declare module '@auth/core/jwt' {
|
|
22
|
-
/** Returned by the `jwt` callback and `auth`, when using JWT sessions */
|
|
23
|
-
interface JWT {
|
|
24
|
-
userId: string;
|
|
25
|
-
}
|
|
26
|
-
}
|