mirror of
https://github.com/pupperpowell/bibdle.git
synced 2026-04-05 17:33:31 -04:00
Adds Google OAuth alongside existing Apple and email/password auth. Follows the same patterns as Apple Sign-In: state cookie for CSRF, anonymousId migration, and user linking by email. Key differences: Google callback is a GET redirect (sameSite: lax) and uses a static client secret instead of a signed JWT. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
51 lines
1.9 KiB
TypeScript
51 lines
1.9 KiB
TypeScript
import { integer, sqliteTable, text, index, unique } from 'drizzle-orm/sqlite-core';
|
|
|
|
export const user = sqliteTable('user', {
|
|
id: text('id').primaryKey(),
|
|
firstName: text('first_name'),
|
|
lastName: text('last_name'),
|
|
email: text('email').unique(),
|
|
passwordHash: text('password_hash'),
|
|
appleId: text('apple_id').unique(),
|
|
googleId: text('google_id').unique(),
|
|
isPrivate: integer('is_private', { mode: 'boolean' }).default(false)
|
|
});
|
|
|
|
export const session = sqliteTable('session', {
|
|
id: text('id').primaryKey(),
|
|
userId: text('user_id').notNull().references(() => user.id),
|
|
expiresAt: integer('expires_at', { mode: 'timestamp' }).notNull()
|
|
});
|
|
|
|
export type Session = typeof session.$inferSelect;
|
|
|
|
export type User = typeof user.$inferSelect;
|
|
|
|
export const dailyVerses = sqliteTable('daily_verses', {
|
|
id: text('id').primaryKey(),
|
|
date: text('date').unique().notNull(),
|
|
bookId: text('book_id').notNull(),
|
|
verseText: text('verse_text').notNull(),
|
|
reference: text('reference').notNull(),
|
|
createdAt: integer('created_at', { mode: 'timestamp' }),
|
|
});
|
|
|
|
export type DailyVerse = typeof dailyVerses.$inferSelect;
|
|
|
|
export const dailyCompletions = sqliteTable('daily_completions', {
|
|
id: text('id').primaryKey(),
|
|
anonymousId: text('anonymous_id').notNull(),
|
|
date: text('date').notNull(),
|
|
guessCount: integer('guess_count').notNull(),
|
|
guesses: text('guesses'), // nullable; only stored for logged-in users
|
|
completedAt: integer('completed_at', { mode: 'timestamp' }).notNull(),
|
|
}, (table) => [
|
|
index('anonymous_id_date_idx').on(table.anonymousId, table.date),
|
|
index('date_idx').on(table.date),
|
|
index('date_guess_idx').on(table.date, table.guessCount),
|
|
// Ensures schema matches the database migration and prevents duplicate submissions
|
|
unique('daily_completions_anonymous_id_date_unique').on(table.anonymousId, table.date),
|
|
]);
|
|
|
|
export type DailyCompletion = typeof dailyCompletions.$inferSelect;
|