codalware-auth
Version:
Complete authentication system with enterprise security, attack protection, team workspaces, waitlist, billing, UI components, 2FA, and account recovery - production-ready in 5 minutes. Enhanced CLI with verification, rollback, and App Router scaffolding.
61 lines (58 loc) • 3.83 kB
text/typescript
import type { Adapter, User, Session, MagicToken } from './types';
import type { DrizzleClient } from 'drizzle-orm';
import { users, sessions, magic_tokens } from './drizzle-schema';
import { eq } from 'drizzle-orm';
export function createDrizzleNativeAdapter(db: DrizzleClient): Adapter {
if (!db) throw new Error('drizzle client required');
return {
async createUser({ email, name, metadata }) {
const [r] = await db.insert(users).values({ email, name: name ?? null, metadata: metadata ?? null }).returning();
return { id: r.id, email: r.email, name: r.name, metadata: r.metadata, createdAt: r.created_at, updatedAt: r.updated_at } as User;
},
async getUserById(id) {
const r = await db.select().from(users).where(eq(users.id, id)).limit(1).then(res => res[0]);
if (!r) return null;
return { id: r.id, email: r.email, name: r.name, metadata: r.metadata, createdAt: r.created_at, updatedAt: r.updated_at } as User;
},
async getUserByEmail(email) {
const r = await db.select().from(users).where(eq(users.email, email)).limit(1).then(res => res[0]);
if (!r) return null;
return { id: r.id, email: r.email, name: r.name, metadata: r.metadata, createdAt: r.created_at, updatedAt: r.updated_at } as User;
},
async updateUser(id, patch) {
const upd = {} as any;
if (patch.email !== undefined) upd.email = patch.email;
if (patch.name !== undefined) upd.name = patch.name;
if (patch.metadata !== undefined) upd.metadata = patch.metadata;
const [r] = await db.update(users).set({ ...upd, updated_at: new Date() }).where(eq(users.id, id)).returning();
return { id: r.id, email: r.email, name: r.name, metadata: r.metadata, createdAt: r.created_at, updatedAt: r.updated_at } as User;
},
async createSession(session) {
const [r] = await db.insert(sessions).values({ user_id: session.userId, handle: session.handle ?? null, expires_at: session.expiresAt, metadata: session.metadata ?? null }).returning();
return { id: r.id, userId: r.user_id, handle: r.handle, createdAt: r.created_at, expiresAt: r.expires_at, metadata: r.metadata } as Session;
},
async getSessionById(id) {
const r = await db.select().from(sessions).where(eq(sessions.id, id)).limit(1).then(res => res[0]);
if (!r) return null;
return { id: r.id, userId: r.user_id, handle: r.handle, createdAt: r.created_at, expiresAt: r.expires_at, metadata: r.metadata } as Session;
},
async deleteSession(id) {
await db.delete(sessions).where(eq(sessions.id, id));
},
async deleteSessionsByUserId(userId) {
await db.delete(sessions).where(eq(sessions.user_id, userId));
},
async storeMagicToken({ tokenHash, userId = null, expiresAt, ip = null, userAgent = null }) {
const [r] = await db.insert(magic_tokens).values({ token_hash: tokenHash, user_id: userId, expires_at: expiresAt, ip, user_agent: userAgent }).returning();
return { id: r.id, tokenHash: r.token_hash, userId: r.user_id, createdAt: r.created_at, expiresAt: r.expires_at, consumedAt: r.consumed_at, ip: r.ip, userAgent: r.user_agent } as MagicToken;
},
async findValidMagicToken(tokenHash) {
const r = await db.select().from(magic_tokens).where(eq(magic_tokens.token_hash, tokenHash), eq(magic_tokens.consumed_at, null)).limit(1).then(res => res[0]);
if (!r) return null;
return { id: r.id, tokenHash: r.token_hash, userId: r.user_id, createdAt: r.created_at, expiresAt: r.expires_at, consumedAt: r.consumed_at, ip: r.ip, userAgent: r.user_agent } as MagicToken;
},
async consumeMagicToken(id) {
await db.update(magic_tokens).set({ consumed_at: new Date() }).where(eq(magic_tokens.id, id));
},
};
}