diff --git a/src/auth.ts b/src/auth.ts index 3bd935d..39b486c 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -1,4 +1,5 @@ import { betterAuth } from "better-auth"; +import { syncAutumnCustomerOnRegistration } from "./autumn"; import { buildAuthEmail, sendEmail } from "./email"; import { trustedOrigins, type Env } from "./env"; import { createSocialProviders } from "./oauth"; @@ -19,6 +20,21 @@ export function createAuth(env: Env, runtime: AuthRuntime = {}) { secret: env.BETTER_AUTH_SECRET ?? "development-secret-change-before-production", baseURL: env.BETTER_AUTH_URL, trustedOrigins: trustedOrigins(env, runtime.requestOrigin), + databaseHooks: { + user: { + create: { + after: async (user) => { + const sync = syncAutumnCustomerOnRegistration(env, user); + if (runtime.waitUntil) { + runtime.waitUntil(sync); + return; + } + + await sync; + }, + }, + }, + }, session: { cookieCache: { enabled: true, diff --git a/tests/auth-config.test.ts b/tests/auth-config.test.ts index efcd8d2..14a3291 100644 --- a/tests/auth-config.test.ts +++ b/tests/auth-config.test.ts @@ -1,5 +1,5 @@ import { readFileSync } from "node:fs"; -import { describe, expect, it } from "vitest"; +import { describe, expect, it, vi } from "vitest"; import { createAuth } from "../src/auth"; import { booleanEnv, @@ -89,6 +89,52 @@ describe("auth env helpers", () => { }); }); +describe("Autumn registration hook", () => { + it("schedules Autumn sync after Better Auth creates a user", async () => { + const waitUntil = vi.fn(); + const auth = createAuth( + { + ...env, + AUTUMN_SECRET_KEY: "autumn-secret", + AUTUMN_FREE_PLAN_ID: "free", + }, + { + waitUntil, + }, + ); + + const hook = ( + auth as unknown as { + options: { + databaseHooks?: { + user?: { + create?: { + after?: ( + user: { id: string; email?: string | null; name?: string | null }, + context?: unknown, + ) => Promise; + }; + }; + }; + }; + } + ).options.databaseHooks?.user?.create?.after; + expect(hook).toEqual(expect.any(Function)); + + await hook?.( + { + id: "user_123", + email: "user@example.com", + name: "Example User", + }, + undefined, + ); + + expect(waitUntil).toHaveBeenCalledTimes(1); + expect(waitUntil.mock.calls[0]?.[0]).toBeInstanceOf(Promise); + }); +}); + describe("production auth config", () => { it("allows the Web Shell origin in Wrangler trusted origins", () => { const config = JSON.parse(readFileSync("wrangler.jsonc", "utf8")) as {