mirror of
https://github.com/better-auth/better-auth.git
synced 2026-05-25 00:22:43 -05:00
fix(adapter): allow run internal adapter outside context (#6617)
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import type { GenericEndpointContext } from "@better-auth/core";
|
||||
import { runWithEndpointContext } from "@better-auth/core/context";
|
||||
import { safeJSONParse } from "@better-auth/core/utils";
|
||||
import Database from "better-sqlite3";
|
||||
import { Kysely, SqliteDialect } from "kysely";
|
||||
@@ -122,22 +121,20 @@ describe("internal adapter test", async () => {
|
||||
const internalAdapter = authContext.internalAdapter;
|
||||
|
||||
it("should create oauth user with custom generate id", async () => {
|
||||
const user = await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.createOAuthUser(
|
||||
{
|
||||
email: "email@email.com",
|
||||
name: "name",
|
||||
emailVerified: false,
|
||||
},
|
||||
{
|
||||
providerId: "provider",
|
||||
accountId: "account",
|
||||
accessTokenExpiresAt: new Date(),
|
||||
refreshTokenExpiresAt: new Date(),
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
),
|
||||
const user = await internalAdapter.createOAuthUser(
|
||||
{
|
||||
email: "email@email.com",
|
||||
name: "name",
|
||||
emailVerified: false,
|
||||
},
|
||||
{
|
||||
providerId: "provider",
|
||||
accountId: "account",
|
||||
accessTokenExpiresAt: new Date(),
|
||||
refreshTokenExpiresAt: new Date(),
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
);
|
||||
expect(user).toMatchObject({
|
||||
user: {
|
||||
@@ -184,26 +181,22 @@ describe("internal adapter test", async () => {
|
||||
});
|
||||
|
||||
it("should delete expired verification values on find", async () => {
|
||||
await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.createVerificationValue({
|
||||
identifier: `test-id-1`,
|
||||
value: "test-id-1",
|
||||
expiresAt: new Date(Date.now() - 1000),
|
||||
}),
|
||||
);
|
||||
await internalAdapter.createVerificationValue({
|
||||
identifier: `test-id-1`,
|
||||
value: "test-id-1",
|
||||
expiresAt: new Date(Date.now() - 1000),
|
||||
});
|
||||
const value = await internalAdapter.findVerificationValue("test-id-1");
|
||||
expect(value).toMatchObject({
|
||||
identifier: "test-id-1",
|
||||
});
|
||||
const value2 = await internalAdapter.findVerificationValue("test-id-1");
|
||||
expect(value2).toBe(undefined);
|
||||
await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.createVerificationValue({
|
||||
identifier: `test-id-1`,
|
||||
value: "test-id-1",
|
||||
expiresAt: new Date(Date.now() + 1000),
|
||||
}),
|
||||
);
|
||||
await internalAdapter.createVerificationValue({
|
||||
identifier: `test-id-1`,
|
||||
value: "test-id-1",
|
||||
expiresAt: new Date(Date.now() + 1000),
|
||||
});
|
||||
const value3 = await internalAdapter.findVerificationValue("test-id-1");
|
||||
expect(value3).toMatchObject({
|
||||
identifier: "test-id-1",
|
||||
@@ -336,9 +329,7 @@ describe("internal adapter test", async () => {
|
||||
};
|
||||
|
||||
// Create a user in the database first
|
||||
await runWithEndpointContext(ctx, () =>
|
||||
ctx.context.internalAdapter.createUser(testUser),
|
||||
);
|
||||
await ctx.context.internalAdapter.createUser(testUser);
|
||||
|
||||
// Test case 1: Session with fractional seconds in TTL
|
||||
const expiresAt = new Date(Date.now() + 3599500); // 59 minutes and 59.5 seconds from now
|
||||
@@ -369,11 +360,9 @@ describe("internal adapter test", async () => {
|
||||
);
|
||||
|
||||
// Trigger refreshUserSessions by updating the user
|
||||
await runWithEndpointContext(ctx, () =>
|
||||
ctx.context.internalAdapter.updateUser(testUser.id, {
|
||||
name: "Updated Name",
|
||||
}),
|
||||
);
|
||||
await ctx.context.internalAdapter.updateUser(testUser.id, {
|
||||
name: "Updated Name",
|
||||
});
|
||||
|
||||
// The TTL should be properly rounded down
|
||||
const lastTTL = capturedTTLs[capturedTTLs.length - 1];
|
||||
@@ -403,11 +392,9 @@ describe("internal adapter test", async () => {
|
||||
JSON.stringify({ session: almostExpiredSession, user: testUser }),
|
||||
);
|
||||
|
||||
await runWithEndpointContext(ctx, () =>
|
||||
ctx.context.internalAdapter.updateUser(testUser.id, {
|
||||
name: "Updated Again",
|
||||
}),
|
||||
);
|
||||
await ctx.context.internalAdapter.updateUser(testUser.id, {
|
||||
name: "Updated Again",
|
||||
});
|
||||
|
||||
// Should be rounded down to 0
|
||||
expect(capturedTTLs.at(-1)).toBe(0);
|
||||
@@ -435,11 +422,9 @@ describe("internal adapter test", async () => {
|
||||
JSON.stringify({ session: longSession, user: testUser }),
|
||||
);
|
||||
|
||||
await runWithEndpointContext(ctx, () =>
|
||||
ctx.context.internalAdapter.updateUser(testUser.id, {
|
||||
name: "Final Update",
|
||||
}),
|
||||
);
|
||||
await ctx.context.internalAdapter.updateUser(testUser.id, {
|
||||
name: "Final Update",
|
||||
});
|
||||
|
||||
// Should be rounded down to 7199
|
||||
const finalTTL = capturedTTLs.at(-1);
|
||||
@@ -451,15 +436,11 @@ describe("internal adapter test", async () => {
|
||||
// Create session
|
||||
const now = Date.now();
|
||||
const expiresAt = new Date(now + 60 * 60 * 24 * 7 * 1000);
|
||||
const user = await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.createUser({
|
||||
name: "test-user",
|
||||
email: "test@email.com",
|
||||
}),
|
||||
);
|
||||
const session = await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.createSession(user.id),
|
||||
);
|
||||
const user = await internalAdapter.createUser({
|
||||
name: "test-user",
|
||||
email: "test@email.com",
|
||||
});
|
||||
const session = await internalAdapter.createSession(user.id);
|
||||
const storedSessions: { token: string; expiresAt: number }[] = JSON.parse(
|
||||
map.get(`active-sessions-${user.id}`),
|
||||
);
|
||||
@@ -505,15 +486,13 @@ describe("internal adapter test", async () => {
|
||||
for (let i = -5; i < 5; i++) {
|
||||
const expiresIn = i * 60 * 60 * 24 * 1000;
|
||||
const expiresAt = new Date(now + expiresIn);
|
||||
await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.createSession(
|
||||
userId,
|
||||
undefined,
|
||||
{
|
||||
expiresAt,
|
||||
},
|
||||
true,
|
||||
),
|
||||
await internalAdapter.createSession(
|
||||
userId,
|
||||
undefined,
|
||||
{
|
||||
expiresAt,
|
||||
},
|
||||
true,
|
||||
);
|
||||
if (i > 0) {
|
||||
const actualExp = expirationMap.get(`active-sessions-${userId}`);
|
||||
@@ -535,9 +514,7 @@ describe("internal adapter test", async () => {
|
||||
expect(tokenStored).toBeDefined();
|
||||
|
||||
// Delete session should clean expiresAt and token
|
||||
await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.deleteSession(token!),
|
||||
);
|
||||
await internalAdapter.deleteSession(token!);
|
||||
const afterDeleted: { token: string; expiresAt: number }[] = JSON.parse(
|
||||
map.get(`active-sessions-${userId}`),
|
||||
);
|
||||
@@ -557,62 +534,48 @@ describe("internal adapter test", async () => {
|
||||
});
|
||||
|
||||
it("should delete a single account", async () => {
|
||||
const user = await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.createUser({
|
||||
name: "Account Delete User",
|
||||
email: "account.delete@example.com",
|
||||
}),
|
||||
);
|
||||
const user = await internalAdapter.createUser({
|
||||
name: "Account Delete User",
|
||||
email: "account.delete@example.com",
|
||||
});
|
||||
|
||||
const account = await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.createAccount({
|
||||
userId: user.id,
|
||||
providerId: "test-provider",
|
||||
accountId: "test-account-id-1",
|
||||
}),
|
||||
);
|
||||
const account = await internalAdapter.createAccount({
|
||||
userId: user.id,
|
||||
providerId: "test-provider",
|
||||
accountId: "test-account-id-1",
|
||||
});
|
||||
|
||||
let foundAccount = await internalAdapter.findAccount(account.accountId);
|
||||
expect(foundAccount).toBeDefined();
|
||||
|
||||
await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.deleteAccount(account.id),
|
||||
);
|
||||
await internalAdapter.deleteAccount(account.id);
|
||||
|
||||
foundAccount = await internalAdapter.findAccount(account.accountId);
|
||||
expect(foundAccount).toBeNull();
|
||||
});
|
||||
|
||||
it("should delete multiple accounts for a user", async () => {
|
||||
const user = await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.createUser({
|
||||
name: "Accounts Delete User",
|
||||
email: "accounts.delete@example.com",
|
||||
}),
|
||||
);
|
||||
const user = await internalAdapter.createUser({
|
||||
name: "Accounts Delete User",
|
||||
email: "accounts.delete@example.com",
|
||||
});
|
||||
|
||||
await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.createAccount({
|
||||
userId: user.id,
|
||||
providerId: "test-provider-1",
|
||||
accountId: "test-account-id-2",
|
||||
}),
|
||||
);
|
||||
await internalAdapter.createAccount({
|
||||
userId: user.id,
|
||||
providerId: "test-provider-1",
|
||||
accountId: "test-account-id-2",
|
||||
});
|
||||
|
||||
await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.createAccount({
|
||||
userId: user.id,
|
||||
providerId: "test-provider-2",
|
||||
accountId: "test-account-id-3",
|
||||
}),
|
||||
);
|
||||
await internalAdapter.createAccount({
|
||||
userId: user.id,
|
||||
providerId: "test-provider-2",
|
||||
accountId: "test-account-id-3",
|
||||
});
|
||||
|
||||
let accounts = await internalAdapter.findAccounts(user.id);
|
||||
expect(accounts.length).toBe(2);
|
||||
|
||||
await runWithEndpointContext(ctx, () =>
|
||||
internalAdapter.deleteAccounts(user.id),
|
||||
);
|
||||
await internalAdapter.deleteAccounts(user.id);
|
||||
|
||||
accounts = await internalAdapter.findAccounts(user.id);
|
||||
expect(accounts.length).toBe(0);
|
||||
|
||||
@@ -24,7 +24,7 @@ export function getWithHooks(
|
||||
}
|
||||
| undefined,
|
||||
) {
|
||||
const context = await getCurrentAuthContext();
|
||||
const context = await getCurrentAuthContext().catch(() => null);
|
||||
let actualData = data;
|
||||
for (const hook of hooks || []) {
|
||||
const toRun = hook[model]?.create?.before;
|
||||
@@ -78,7 +78,7 @@ export function getWithHooks(
|
||||
}
|
||||
| undefined,
|
||||
) {
|
||||
const context = await getCurrentAuthContext();
|
||||
const context = await getCurrentAuthContext().catch(() => null);
|
||||
let actualData = data;
|
||||
|
||||
for (const hook of hooks || []) {
|
||||
@@ -133,7 +133,7 @@ export function getWithHooks(
|
||||
}
|
||||
| undefined,
|
||||
) {
|
||||
const context = await getCurrentAuthContext();
|
||||
const context = await getCurrentAuthContext().catch(() => null);
|
||||
let actualData = data;
|
||||
|
||||
for (const hook of hooks || []) {
|
||||
@@ -188,7 +188,7 @@ export function getWithHooks(
|
||||
}
|
||||
| undefined,
|
||||
) {
|
||||
const context = await getCurrentAuthContext();
|
||||
const context = await getCurrentAuthContext().catch(() => null);
|
||||
let entityToDelete: T | null = null;
|
||||
|
||||
try {
|
||||
@@ -250,7 +250,7 @@ export function getWithHooks(
|
||||
}
|
||||
| undefined,
|
||||
) {
|
||||
const context = await getCurrentAuthContext();
|
||||
const context = await getCurrentAuthContext().catch(() => null);
|
||||
let entitiesToDelete: T[] = [];
|
||||
|
||||
try {
|
||||
|
||||
@@ -995,7 +995,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
before?: (
|
||||
user: User & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<
|
||||
| boolean
|
||||
| void
|
||||
@@ -1008,7 +1008,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
after?: (
|
||||
user: User & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<void>;
|
||||
};
|
||||
update?: {
|
||||
@@ -1019,7 +1019,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
before?: (
|
||||
user: Partial<User> & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<
|
||||
| boolean
|
||||
| void
|
||||
@@ -1032,7 +1032,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
after?: (
|
||||
user: User & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<void>;
|
||||
};
|
||||
delete?: {
|
||||
@@ -1042,14 +1042,14 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
before?: (
|
||||
user: User & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<boolean | void>;
|
||||
/**
|
||||
* Hook that is called after a user is deleted.
|
||||
*/
|
||||
after?: (
|
||||
user: User & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<void>;
|
||||
};
|
||||
};
|
||||
@@ -1065,7 +1065,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
before?: (
|
||||
session: Session & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<
|
||||
| boolean
|
||||
| void
|
||||
@@ -1078,7 +1078,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
after?: (
|
||||
session: Session & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<void>;
|
||||
};
|
||||
/**
|
||||
@@ -1092,7 +1092,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
before?: (
|
||||
session: Partial<Session> & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<
|
||||
| boolean
|
||||
| void
|
||||
@@ -1105,7 +1105,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
after?: (
|
||||
session: Session & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<void>;
|
||||
};
|
||||
delete?: {
|
||||
@@ -1115,14 +1115,14 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
before?: (
|
||||
session: Session & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<boolean | void>;
|
||||
/**
|
||||
* Hook that is called after a session is deleted.
|
||||
*/
|
||||
after?: (
|
||||
session: Session & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<void>;
|
||||
};
|
||||
};
|
||||
@@ -1138,7 +1138,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
before?: (
|
||||
account: Account,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<
|
||||
| boolean
|
||||
| void
|
||||
@@ -1151,7 +1151,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
after?: (
|
||||
account: Account,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<void>;
|
||||
};
|
||||
/**
|
||||
@@ -1165,7 +1165,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
before?: (
|
||||
account: Partial<Account> & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<
|
||||
| boolean
|
||||
| void
|
||||
@@ -1178,7 +1178,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
after?: (
|
||||
account: Account & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<void>;
|
||||
};
|
||||
delete?: {
|
||||
@@ -1188,14 +1188,14 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
before?: (
|
||||
account: Account & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<boolean | void>;
|
||||
/**
|
||||
* Hook that is called after an account is deleted.
|
||||
*/
|
||||
after?: (
|
||||
account: Account & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<void>;
|
||||
};
|
||||
};
|
||||
@@ -1211,7 +1211,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
before?: (
|
||||
verification: Verification & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<
|
||||
| boolean
|
||||
| void
|
||||
@@ -1224,7 +1224,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
after?: (
|
||||
verification: Verification & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<void>;
|
||||
};
|
||||
update?: {
|
||||
@@ -1235,7 +1235,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
before?: (
|
||||
verification: Partial<Verification> & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<
|
||||
| boolean
|
||||
| void
|
||||
@@ -1248,7 +1248,7 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
after?: (
|
||||
verification: Verification & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<void>;
|
||||
};
|
||||
delete?: {
|
||||
@@ -1258,14 +1258,14 @@ export type BetterAuthOptions = {
|
||||
*/
|
||||
before?: (
|
||||
verification: Verification & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<boolean | void>;
|
||||
/**
|
||||
* Hook that is called after a verification is deleted.
|
||||
*/
|
||||
after?: (
|
||||
verification: Verification & Record<string, unknown>,
|
||||
context?: GenericEndpointContext,
|
||||
context: GenericEndpointContext | null,
|
||||
) => Promise<void>;
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user