diff --git a/drizzle/20260824204138_shallow_doctor_strange/migration.sql b/drizzle/20260824204138_shallow_doctor_strange/migration.sql new file mode 100644 index 0000000..c1676b3 --- /dev/null +++ b/drizzle/20260824204138_shallow_doctor_strange/migration.sql @@ -0,0 +1,83 @@ +ALTER TABLE `two_factor` ADD `failed_verification_count` integer DEFAULT 0;--> statement-breakpoint +ALTER TABLE `two_factor` ADD `locked_until` integer;--> statement-breakpoint +PRAGMA foreign_keys=OFF;--> statement-breakpoint +CREATE TABLE `__new_account` ( + `access_token` text, + `access_token_expires_at` integer, + `account_id` text NOT NULL, + `created_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL, + `id` text PRIMARY KEY, + `id_token` text, + `issuer` text NOT NULL, + `password` text, + `provider_id` text NOT NULL, + `refresh_token` text, + `refresh_token_expires_at` integer, + `scope` text, + `updated_at` integer NOT NULL, + `user_id` text NOT NULL, + CONSTRAINT `fk_account_user_id_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE +); +--> statement-breakpoint +INSERT INTO `__new_account`(`access_token`, `access_token_expires_at`, `account_id`, `created_at`, `id`, `id_token`, `issuer`, `password`, `provider_id`, `refresh_token`, `refresh_token_expires_at`, `scope`, `updated_at`, `user_id`) SELECT `access_token`, `access_token_expires_at`, `account_id`, `created_at`, `id`, `id_token`, CASE `provider_id` WHEN 'credential' THEN 'local:credential' WHEN 'google' THEN 'https://accounts.google.com' WHEN 'facebook' THEN 'https://www.facebook.com' WHEN 'apple' THEN 'https://appleid.apple.com' ELSE 'local:oauth:' || `provider_id` END, `password`, `provider_id`, `refresh_token`, `refresh_token_expires_at`, `scope`, `updated_at`, `user_id` FROM `account`;--> statement-breakpoint +DROP TABLE `account`;--> statement-breakpoint +ALTER TABLE `__new_account` RENAME TO `account`;--> statement-breakpoint +PRAGMA foreign_keys=ON;--> statement-breakpoint +PRAGMA foreign_keys=OFF;--> statement-breakpoint +CREATE TABLE `__new_session` ( + `created_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL, + `expires_at` integer NOT NULL, + `id` text PRIMARY KEY, + `impersonated_by` text, + `ip_address` text, + `token` text NOT NULL UNIQUE, + `updated_at` integer NOT NULL, + `user_agent` text, + `user_id` text NOT NULL, + CONSTRAINT `fk_session_user_id_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE +); +--> statement-breakpoint +INSERT INTO `__new_session`(`created_at`, `expires_at`, `id`, `impersonated_by`, `ip_address`, `token`, `updated_at`, `user_agent`, `user_id`) SELECT `created_at`, `expires_at`, `id`, `impersonated_by`, `ip_address`, `token`, `updated_at`, `user_agent`, `user_id` FROM `session`;--> statement-breakpoint +DROP TABLE `session`;--> statement-breakpoint +ALTER TABLE `__new_session` RENAME TO `session`;--> statement-breakpoint +PRAGMA foreign_keys=ON;--> statement-breakpoint +PRAGMA foreign_keys=OFF;--> statement-breakpoint +CREATE TABLE `__new_user` ( + `ban_expires` integer, + `banned` integer DEFAULT false, + `ban_reason` text, + `created_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL, + `display_username` text, + `email` text NOT NULL UNIQUE, + `email_verified` integer DEFAULT false NOT NULL, + `id` text PRIMARY KEY, + `image` text, + `name` text NOT NULL, + `role` text, + `two_factor_enabled` integer DEFAULT false, + `updated_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL, + `username` text UNIQUE +); +--> statement-breakpoint +INSERT INTO `__new_user`(`ban_expires`, `banned`, `ban_reason`, `created_at`, `display_username`, `email`, `email_verified`, `id`, `image`, `name`, `role`, `two_factor_enabled`, `updated_at`, `username`) SELECT `ban_expires`, `banned`, `ban_reason`, `created_at`, `display_username`, `email`, `email_verified`, `id`, `image`, `name`, `role`, `two_factor_enabled`, `updated_at`, `username` FROM `user`;--> statement-breakpoint +DROP TABLE `user`;--> statement-breakpoint +ALTER TABLE `__new_user` RENAME TO `user`;--> statement-breakpoint +PRAGMA foreign_keys=ON;--> statement-breakpoint +PRAGMA foreign_keys=OFF;--> statement-breakpoint +CREATE TABLE `__new_verification` ( + `created_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL, + `expires_at` integer NOT NULL, + `id` text PRIMARY KEY, + `identifier` text NOT NULL, + `updated_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL, + `value` text NOT NULL +); +--> statement-breakpoint +INSERT INTO `__new_verification`(`created_at`, `expires_at`, `id`, `identifier`, `updated_at`, `value`) SELECT `created_at`, `expires_at`, `id`, `identifier`, `updated_at`, `value` FROM `verification`;--> statement-breakpoint +DROP TABLE `verification`;--> statement-breakpoint +ALTER TABLE `__new_verification` RENAME TO `verification`;--> statement-breakpoint +PRAGMA foreign_keys=ON;--> statement-breakpoint +CREATE UNIQUE INDEX `account_issuer_accountId_uidx` ON `account` (`issuer`,`account_id`);--> statement-breakpoint +CREATE INDEX `account_userId_idx` ON `account` (`user_id`);--> statement-breakpoint +CREATE INDEX `session_userId_idx` ON `session` (`user_id`);--> statement-breakpoint +CREATE INDEX `verification_identifier_idx` ON `verification` (`identifier`); \ No newline at end of file diff --git a/drizzle/20260824204138_shallow_doctor_strange/snapshot.json b/drizzle/20260824204138_shallow_doctor_strange/snapshot.json new file mode 100644 index 0000000..8a8a6c4 --- /dev/null +++ b/drizzle/20260824204138_shallow_doctor_strange/snapshot.json @@ -0,0 +1,851 @@ +{ + "version": "7", + "dialect": "sqlite", + "id": "318d902d-7167-4d9e-a3d1-6abf4ab35a0a", + "prevIds": [ + "208e7c97-0071-4c2f-bc0c-7c4cbf18af2e" + ], + "ddl": [ + { + "name": "machines", + "entityType": "tables" + }, + { + "name": "settings", + "entityType": "tables" + }, + { + "name": "account", + "entityType": "tables" + }, + { + "name": "session", + "entityType": "tables" + }, + { + "name": "two_factor", + "entityType": "tables" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "name": "verification", + "entityType": "tables" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": "'http://127.0.0.1:9999'", + "generated": null, + "name": "address", + "entityType": "columns", + "table": "machines" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "machines" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "machines" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "order", + "entityType": "columns", + "table": "machines" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "token", + "entityType": "columns", + "table": "machines" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "key", + "entityType": "columns", + "table": "settings" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "settings" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "value", + "entityType": "columns", + "table": "settings" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "access_token", + "entityType": "columns", + "table": "account" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "access_token_expires_at", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "account_id", + "entityType": "columns", + "table": "account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id_token", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "issuer", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "password", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "provider_id", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "refresh_token", + "entityType": "columns", + "table": "account" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "refresh_token_expires_at", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "scope", + "entityType": "columns", + "table": "account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "expires_at", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "impersonated_by", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "ip_address", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "token", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_agent", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "backup_codes", + "entityType": "columns", + "table": "two_factor" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "failed_verification_count", + "entityType": "columns", + "table": "two_factor" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "two_factor" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "locked_until", + "entityType": "columns", + "table": "two_factor" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "secret", + "entityType": "columns", + "table": "two_factor" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "two_factor" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": "true", + "generated": null, + "name": "verified", + "entityType": "columns", + "table": "two_factor" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "ban_expires", + "entityType": "columns", + "table": "user" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "banned", + "entityType": "columns", + "table": "user" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "ban_reason", + "entityType": "columns", + "table": "user" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "user" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "display_username", + "entityType": "columns", + "table": "user" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "email", + "entityType": "columns", + "table": "user" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "email_verified", + "entityType": "columns", + "table": "user" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "user" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "image", + "entityType": "columns", + "table": "user" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "user" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "role", + "entityType": "columns", + "table": "user" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "two_factor_enabled", + "entityType": "columns", + "table": "user" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "user" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "username", + "entityType": "columns", + "table": "user" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "verification" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "expires_at", + "entityType": "columns", + "table": "verification" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "verification" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "identifier", + "entityType": "columns", + "table": "verification" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "verification" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "value", + "entityType": "columns", + "table": "verification" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_account_user_id_user_id_fk", + "entityType": "fks", + "table": "account" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_session_user_id_user_id_fk", + "entityType": "fks", + "table": "session" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_two_factor_user_id_user_id_fk", + "entityType": "fks", + "table": "two_factor" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "machines_pk", + "table": "machines", + "entityType": "pks" + }, + { + "columns": [ + "key" + ], + "nameExplicit": false, + "name": "settings_pk", + "table": "settings", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "account_pk", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "session_pk", + "table": "session", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "two_factor_pk", + "table": "two_factor", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "user_pk", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "verification_pk", + "table": "verification", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "issuer", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "where": null, + "origin": "manual", + "name": "account_issuer_accountId_uidx", + "entityType": "indexes", + "table": "account" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "account_userId_idx", + "entityType": "indexes", + "table": "account" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_userId_idx", + "entityType": "indexes", + "table": "session" + }, + { + "columns": [ + { + "value": "secret", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "twoFactor_secret_idx", + "entityType": "indexes", + "table": "two_factor" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "twoFactor_userId_idx", + "entityType": "indexes", + "table": "two_factor" + }, + { + "columns": [ + { + "value": "identifier", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "verification_identifier_idx", + "entityType": "indexes", + "table": "verification" + }, + { + "columns": [ + "order" + ], + "nameExplicit": false, + "name": "machines_order_unique", + "entityType": "uniques", + "table": "machines" + }, + { + "columns": [ + "token" + ], + "nameExplicit": false, + "name": "session_token_unique", + "entityType": "uniques", + "table": "session" + }, + { + "columns": [ + "email" + ], + "nameExplicit": false, + "name": "user_email_unique", + "entityType": "uniques", + "table": "user" + }, + { + "columns": [ + "username" + ], + "nameExplicit": false, + "name": "user_username_unique", + "entityType": "uniques", + "table": "user" + } + ], + "renames": [] +} \ No newline at end of file diff --git a/src/lib/server/db/auth-schema.ts b/src/lib/server/db/auth-schema.ts index 52561d6..7335ed1 100644 --- a/src/lib/server/db/auth-schema.ts +++ b/src/lib/server/db/auth-schema.ts @@ -1,100 +1,130 @@ -import { index, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { sql } from "drizzle-orm/sql"; +import { + index, + integer, + sqliteTable, + text, + uniqueIndex, +} from "drizzle-orm/sqlite-core"; -export const user = sqliteTable('user', { - banExpires: integer('ban_expires', { mode: 'timestamp_ms' }), - banned: integer('banned', { mode: 'boolean' }).default(false), - banReason: text('ban_reason'), - createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(), - displayUsername: text('display_username'), - email: text('email').notNull().unique(), - emailVerified: integer('email_verified', { mode: 'boolean' }).default(false).notNull(), - id: text('id').primaryKey(), - image: text('image'), - name: text('name').notNull(), - role: text('role'), - twoFactorEnabled: integer('two_factor_enabled', { mode: 'boolean' }).default(false), - updatedAt: integer('updated_at', { mode: 'timestamp_ms' }) - .$onUpdate(() => new Date()) - .notNull(), - username: text('username').unique() +export const user = sqliteTable("user", { + banExpires: integer("ban_expires", { mode: "timestamp_ms" }), + banned: integer("banned", { mode: "boolean" }).default(false), + banReason: text("ban_reason"), + createdAt: integer("created_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) + .notNull(), + displayUsername: text("display_username"), + email: text("email").notNull().unique(), + emailVerified: integer("email_verified", { mode: "boolean" }) + .default(false) + .notNull(), + id: text("id").primaryKey(), + image: text("image"), + name: text("name").notNull(), + role: text("role"), + twoFactorEnabled: integer("two_factor_enabled", { mode: "boolean" }).default( + false, + ), + updatedAt: integer("updated_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + username: text("username").unique(), }); export const session = sqliteTable( - 'session', - { - createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(), - expiresAt: integer('expires_at', { mode: 'timestamp_ms' }).notNull(), - id: text('id').primaryKey(), - impersonatedBy: text('impersonated_by'), - ipAddress: text('ip_address'), - token: text('token').notNull().unique(), - updatedAt: integer('updated_at', { mode: 'timestamp_ms' }) - .$onUpdate(() => new Date()) - .notNull(), - userAgent: text('user_agent'), - userId: text('user_id') - .notNull() - .references(() => user.id, { onDelete: 'cascade' }) - }, - (table) => [index('session_userId_idx').on(table.userId)] + "session", + { + createdAt: integer("created_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) + .notNull(), + expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(), + id: text("id").primaryKey(), + impersonatedBy: text("impersonated_by"), + ipAddress: text("ip_address"), + token: text("token").notNull().unique(), + updatedAt: integer("updated_at", { mode: "timestamp_ms" }) + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + userAgent: text("user_agent"), + userId: text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + }, + (table) => [index("session_userId_idx").on(table.userId)], ); export const account = sqliteTable( - 'account', - { - accessToken: text('access_token'), - accessTokenExpiresAt: integer('access_token_expires_at', { - mode: 'timestamp_ms' - }), - accountId: text('account_id').notNull(), - createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(), - id: text('id').primaryKey(), - idToken: text('id_token'), - password: text('password'), - providerId: text('provider_id').notNull(), - refreshToken: text('refresh_token'), - refreshTokenExpiresAt: integer('refresh_token_expires_at', { - mode: 'timestamp_ms' - }), - scope: text('scope'), - updatedAt: integer('updated_at', { mode: 'timestamp_ms' }) - .$onUpdate(() => new Date()) - .notNull(), - userId: text('user_id') - .notNull() - .references(() => user.id, { onDelete: 'cascade' }) - }, - (table) => [index('account_userId_idx').on(table.userId)] + "account", + { + accessToken: text("access_token"), + accessTokenExpiresAt: integer("access_token_expires_at", { + mode: "timestamp_ms", + }), + accountId: text("account_id").notNull(), + createdAt: integer("created_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) + .notNull(), + id: text("id").primaryKey(), + idToken: text("id_token"), + issuer: text("issuer").notNull(), + password: text("password"), + providerId: text("provider_id").notNull(), + refreshToken: text("refresh_token"), + refreshTokenExpiresAt: integer("refresh_token_expires_at", { + mode: "timestamp_ms", + }), + scope: text("scope"), + updatedAt: integer("updated_at", { mode: "timestamp_ms" }) + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + userId: text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + }, + (table) => [ + uniqueIndex("account_issuer_accountId_uidx").on( + table.issuer, + table.accountId, + ), + index("account_userId_idx").on(table.userId), + ], ); export const verification = sqliteTable( - 'verification', - { - createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(), - expiresAt: integer('expires_at', { mode: 'timestamp_ms' }).notNull(), - id: text('id').primaryKey(), - identifier: text('identifier').notNull(), - updatedAt: integer('updated_at', { mode: 'timestamp_ms' }) - .$onUpdate(() => new Date()) - .notNull(), - value: text('value').notNull() - }, - (table) => [index('verification_identifier_idx').on(table.identifier)] + "verification", + { + createdAt: integer("created_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) + .notNull(), + expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(), + id: text("id").primaryKey(), + identifier: text("identifier").notNull(), + updatedAt: integer("updated_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + value: text("value").notNull(), + }, + (table) => [index("verification_identifier_idx").on(table.identifier)], ); export const twoFactor = sqliteTable( - 'two_factor', - { - backupCodes: text('backup_codes').notNull(), - id: text('id').primaryKey(), - secret: text('secret').notNull(), - userId: text('user_id') - .notNull() - .references(() => user.id, { onDelete: 'cascade' }), - verified: integer('verified', { mode: 'boolean' }).default(true) - }, - (table) => [ - index('twoFactor_secret_idx').on(table.secret), - index('twoFactor_userId_idx').on(table.userId) - ] -); + "two_factor", + { + backupCodes: text("backup_codes").notNull(), + failedVerificationCount: integer("failed_verification_count").default(0), + id: text("id").primaryKey(), + lockedUntil: integer("locked_until", { mode: "timestamp_ms" }), + secret: text("secret").notNull(), + userId: text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + verified: integer("verified", { mode: "boolean" }).default(true), + }, + (table) => [ + index("twoFactor_secret_idx").on(table.secret), + index("twoFactor_userId_idx").on(table.userId), + ], +); \ No newline at end of file