fix: refersh cookie cache properly when it's expired (#909)

This commit is contained in:
Bereket Engida
2024-12-16 16:53:01 +03:00
committed by GitHub
parent 69b804cfbc
commit caf0cf9cf7
4 changed files with 87 additions and 29 deletions

View File

@@ -42,6 +42,22 @@ export const auth = betterAuth({
dialect, dialect,
type: process.env.USE_MYSQL ? "mysql" : "sqlite", type: process.env.USE_MYSQL ? "mysql" : "sqlite",
}, },
databaseHooks: {
user: {
update: {
async before(user) {
if (user.emailVerified) {
return {
data: {
...user,
emailVerifiedAt: new Date().toISOString(),
},
};
}
},
},
},
},
emailVerification: { emailVerification: {
async sendVerificationEmail({ user, url }) { async sendVerificationEmail({ user, url }) {
const res = await resend.emails.send({ const res = await resend.emails.send({

View File

@@ -435,7 +435,7 @@ describe("cookie cache", async () => {
}; };
const adapter = memoryAdapter(database); const adapter = memoryAdapter(database);
const { client, testUser, auth } = await getTestInstance({ const { client, testUser, auth, cookieSetter } = await getTestInstance({
database: adapter, database: adapter,
session: { session: {
cookieCache: { cookieCache: {
@@ -498,4 +498,33 @@ describe("cookie cache", async () => {
expect(session.data).not.toBeNull(); expect(session.data).not.toBeNull();
expect(fn).toHaveBeenCalledTimes(3); expect(fn).toHaveBeenCalledTimes(3);
}); });
it("should reset cache when expires", async () => {
expect(fn).toHaveBeenCalledTimes(3);
await client.getSession({
fetchOptions: {
headers,
},
});
vi.useFakeTimers();
await vi.advanceTimersByTimeAsync(1000 * 60 * 10); // 10 minutes
await client.getSession({
fetchOptions: {
headers,
onSuccess(context) {
cookieSetter(headers)(context);
},
},
});
expect(fn).toHaveBeenCalledTimes(5);
await client.getSession({
fetchOptions: {
headers,
onSuccess(context) {
cookieSetter(headers)(context);
},
},
});
expect(fn).toHaveBeenCalledTimes(5);
});
}); });

View File

@@ -1,7 +1,11 @@
import { APIError } from "better-call"; import { APIError } from "better-call";
import { createAuthEndpoint, createAuthMiddleware } from "../call"; import { createAuthEndpoint, createAuthMiddleware } from "../call";
import { getDate } from "../../utils/date"; import { getDate } from "../../utils/date";
import { deleteSessionCookie, setSessionCookie } from "../../cookies"; import {
deleteSessionCookie,
setCookieCache,
setSessionCookie,
} from "../../cookies";
import { z } from "zod"; import { z } from "zod";
import type { import type {
BetterAuthOptions, BetterAuthOptions,
@@ -229,7 +233,7 @@ export const getSession = <Option extends BetterAuthOptions>() =>
user: InferUser<Option>; user: InferUser<Option>;
}); });
} }
await setCookieCache(ctx, session);
return ctx.json( return ctx.json(
session as unknown as { session as unknown as {
session: InferSession<Option>; session: InferSession<Option>;

View File

@@ -92,38 +92,13 @@ export function getCookies(options: BetterAuthOptions) {
export type BetterAuthCookies = ReturnType<typeof getCookies>; export type BetterAuthCookies = ReturnType<typeof getCookies>;
export async function setSessionCookie( export async function setCookieCache(
ctx: GenericEndpointContext, ctx: GenericEndpointContext,
session: { session: {
session: Session & Record<string, any>; session: Session & Record<string, any>;
user: User; user: User;
}, },
dontRememberMe?: boolean,
overrides?: Partial<CookieOptions>,
) { ) {
const options = ctx.context.authCookies.sessionToken.options;
const maxAge = dontRememberMe
? undefined
: ctx.context.sessionConfig.expiresIn;
await ctx.setSignedCookie(
ctx.context.authCookies.sessionToken.name,
session.session.token,
ctx.context.secret,
{
...options,
maxAge,
...overrides,
},
);
if (dontRememberMe) {
await ctx.setSignedCookie(
ctx.context.authCookies.dontRememberToken.name,
"true",
ctx.context.secret,
ctx.context.authCookies.dontRememberToken.options,
);
}
const shouldStoreSessionDataInCookie = const shouldStoreSessionDataInCookie =
ctx.context.options.session?.cookieCache?.enabled; ctx.context.options.session?.cookieCache?.enabled;
@@ -157,7 +132,41 @@ export async function setSessionCookie(
ctx.context.authCookies.sessionData.options, ctx.context.authCookies.sessionData.options,
); );
} }
}
export async function setSessionCookie(
ctx: GenericEndpointContext,
session: {
session: Session & Record<string, any>;
user: User;
},
dontRememberMe?: boolean,
overrides?: Partial<CookieOptions>,
) {
const options = ctx.context.authCookies.sessionToken.options;
const maxAge = dontRememberMe
? undefined
: ctx.context.sessionConfig.expiresIn;
await ctx.setSignedCookie(
ctx.context.authCookies.sessionToken.name,
session.session.token,
ctx.context.secret,
{
...options,
maxAge,
...overrides,
},
);
if (dontRememberMe) {
await ctx.setSignedCookie(
ctx.context.authCookies.dontRememberToken.name,
"true",
ctx.context.secret,
ctx.context.authCookies.dontRememberToken.options,
);
}
await setCookieCache(ctx, session);
ctx.context.setNewSession(session); ctx.context.setNewSession(session);
/** /**
* If secondary storage is enabled, store the session data in the secondary storage * If secondary storage is enabled, store the session data in the secondary storage