diff --git a/cloudflare/migrations/0006_better_auth.sql b/cloudflare/migrations/0006_better_auth.sql new file mode 100644 index 0000000..f818de4 --- /dev/null +++ b/cloudflare/migrations/0006_better_auth.sql @@ -0,0 +1,54 @@ +CREATE TABLE IF NOT EXISTS better_auth_user ( + id TEXT NOT NULL PRIMARY KEY, + name TEXT NOT NULL, + email TEXT NOT NULL UNIQUE, + emailVerified INTEGER NOT NULL, + image TEXT, + createdAt DATE NOT NULL, + updatedAt DATE NOT NULL +); + +CREATE TABLE IF NOT EXISTS better_auth_session ( + id TEXT NOT NULL PRIMARY KEY, + expiresAt DATE NOT NULL, + token TEXT NOT NULL UNIQUE, + createdAt DATE NOT NULL, + updatedAt DATE NOT NULL, + ipAddress TEXT, + userAgent TEXT, + userId TEXT NOT NULL REFERENCES better_auth_user (id) ON DELETE CASCADE +); + +CREATE INDEX IF NOT EXISTS better_auth_session_userId_idx + ON better_auth_session (userId); + +CREATE TABLE IF NOT EXISTS better_auth_account ( + id TEXT NOT NULL PRIMARY KEY, + accountId TEXT NOT NULL, + providerId TEXT NOT NULL, + userId TEXT NOT NULL REFERENCES better_auth_user (id) ON DELETE CASCADE, + accessToken TEXT, + refreshToken TEXT, + idToken TEXT, + accessTokenExpiresAt DATE, + refreshTokenExpiresAt DATE, + scope TEXT, + password TEXT, + createdAt DATE NOT NULL, + updatedAt DATE NOT NULL +); + +CREATE INDEX IF NOT EXISTS better_auth_account_userId_idx + ON better_auth_account (userId); + +CREATE TABLE IF NOT EXISTS better_auth_verification ( + id TEXT NOT NULL PRIMARY KEY, + identifier TEXT NOT NULL, + value TEXT NOT NULL, + expiresAt DATE NOT NULL, + createdAt DATE NOT NULL, + updatedAt DATE NOT NULL +); + +CREATE INDEX IF NOT EXISTS better_auth_verification_identifier_idx + ON better_auth_verification (identifier); diff --git a/cloudflare/src/better_auth.ts b/cloudflare/src/better_auth.ts index 578b15e..4552f33 100644 --- a/cloudflare/src/better_auth.ts +++ b/cloudflare/src/better_auth.ts @@ -32,6 +32,10 @@ function createElyAuth(env: Env) { baseURL: requiredBinding(env.ELY_AUTH_BASE_URL, "ELY_AUTH_BASE_URL"), secret: requiredBinding(env.ELY_AUTH_SECRET, "ELY_AUTH_SECRET"), database: env.ELY_DB as BetterAuthDatabase, + user: { modelName: "better_auth_user" }, + session: { modelName: "better_auth_session" }, + account: { modelName: "better_auth_account" }, + verification: { modelName: "better_auth_verification" }, emailAndPassword: { enabled: true, minPasswordLength: 12, diff --git a/cloudflare/tests/migrations.test.ts b/cloudflare/tests/migrations.test.ts index 3b068d4..5d5aa32 100644 --- a/cloudflare/tests/migrations.test.ts +++ b/cloudflare/tests/migrations.test.ts @@ -12,6 +12,7 @@ const EXPECTED_MIGRATIONS = [ "0003_plugins.sql", "0004_releases.sql", "0005_audit.sql", + "0006_better_auth.sql", ]; const USER_SCOPED_TABLES = [ "user_devices", @@ -36,6 +37,10 @@ describe("D1 migrations", () => { for (const table of [ "audit_events", + "better_auth_account", + "better_auth_session", + "better_auth_user", + "better_auth_verification", "device_approvals", "plugin_packages", "plugin_registry", @@ -52,6 +57,56 @@ describe("D1 migrations", () => { }); }); + it("creates Better Auth tables compatible with the Worker auth schema", () => { + withReplayedDatabase((databasePath) => { + assert.deepEqual( + requiredColumns(databasePath, "better_auth_user", [ + "id", + "name", + "email", + "emailVerified", + "createdAt", + "updatedAt", + ]), + [], + ); + assert.deepEqual( + requiredColumns(databasePath, "better_auth_session", [ + "id", + "expiresAt", + "token", + "createdAt", + "updatedAt", + "userId", + ]), + [], + ); + assert.deepEqual( + requiredColumns(databasePath, "better_auth_account", [ + "id", + "accountId", + "providerId", + "userId", + "password", + "createdAt", + "updatedAt", + ]), + [], + ); + assert.deepEqual( + requiredColumns(databasePath, "better_auth_verification", [ + "id", + "identifier", + "value", + "expiresAt", + "createdAt", + "updatedAt", + ]), + [], + ); + }); + }); + it("keeps user-scoped D1 tables partitioned by user_id", () => { withReplayedDatabase((databasePath) => { for (const table of USER_SCOPED_TABLES) {